summaryrefslogtreecommitdiffstats
path: root/ansible_collections/cisco/aci/plugins
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-26 04:06:02 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-26 04:06:02 +0000
commite3eb94c23206603103f3c4faec6c227f59a1544c (patch)
treef2639459807ba88f55fc9c54d745bd7075d7f15c /ansible_collections/cisco/aci/plugins
parentReleasing progress-linux version 9.4.0+dfsg-1~progress7.99u1. (diff)
downloadansible-e3eb94c23206603103f3c4faec6c227f59a1544c.tar.xz
ansible-e3eb94c23206603103f3c4faec6c227f59a1544c.zip
Merging upstream version 9.5.1+dfsg.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ansible_collections/cisco/aci/plugins')
-rw-r--r--ansible_collections/cisco/aci/plugins/doc_fragments/aci.py10
-rw-r--r--ansible_collections/cisco/aci/plugins/filter/listify.py295
-rw-r--r--ansible_collections/cisco/aci/plugins/httpapi/aci.py13
-rw-r--r--ansible_collections/cisco/aci/plugins/module_utils/aci.py203
-rw-r--r--ansible_collections/cisco/aci/plugins/module_utils/annotation_unsupported.py853
-rw-r--r--ansible_collections/cisco/aci/plugins/module_utils/constants.py338
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_aaa_certificate_authority.py290
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_aaa_key_ring.py339
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_aaa_security_default_settings.py531
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_aaa_ssh_auth.py4
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_access_port_block_to_access_port.py158
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_access_port_to_interface_policy_leaf_profile.py2
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_access_spine_interface_profile.py279
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_access_spine_interface_profile_to_spine_switch_profile.py292
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_access_spine_interface_selector.py326
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_access_spine_switch_profile.py277
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_access_spine_switch_selector.py321
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_access_sub_port_block_to_access_port.py2
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_access_switch_policy_group.py600
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_action_rule_additional_communities.py304
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_action_rule_set_as_path.py304
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_action_rule_set_as_path_asn.py312
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_aep.py2
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_aep_to_epg.py2
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_bd.py238
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_bd_rogue_exception_mac.py299
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_bd_to_netflow_monitor_policy.py292
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_bfd_multihop_node_policy.py320
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_bgp_address_family_context_policy.py382
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_bgp_best_path_policy.py12
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_bgp_peer_prefix_policy.py322
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_bgp_route_summarization_policy.py310
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_bgp_rr_asn.py6
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_bgp_rr_node.py6
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_bgp_timers_policy.py12
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_cloud_subnet.py53
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_config_snapshot.py2
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_contract_subject_to_service_graph.py2
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_dhcp_option.py306
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_dhcp_option_policy.py276
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_dhcp_relay.py6
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_dhcp_relay_provider.py6
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_dns_domain.py4
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_dns_profile.py4
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_dns_provider.py2
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_domain.py2
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_encap_pool.py2
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_encap_pool_range.py2
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_epg.py71
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_epg_to_contract.py74
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_epg_to_contract_interface.py2
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_epg_to_domain.py4
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_epg_useg_attribute_block_statement.py348
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_epg_useg_attribute_simple_statement.py436
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_esg_ip_subnet_selector.py2
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_fabric_external_connection_profile.py311
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_fabric_external_routing_profile.py315
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_fabric_interface_policy_group.py2
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_fabric_leaf_profile.py2
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_fabric_management_access.py700
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_fabric_management_access_https_cipher.py282
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_fabric_pod.py292
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_fabric_pod_connectivity_profile.py336
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_fabric_pod_external_tep.py321
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_fabric_pod_profile.py267
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_fabric_pod_remote_pool.py294
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_fabric_pod_selector.py4
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_fabric_spine_profile.py2
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_fabric_spine_switch_assoc.py2
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_fabric_switch_block.py2
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_fabric_switch_policy_group.py32
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_fabric_wide_settings.py6
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_igmp_interface_policy.py4
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_interface_blacklist.py6
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_interface_description.py6
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_bfd.py318
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_bfd_multihop.py318
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_eigrp.py371
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_hsrp.py310
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_leaf_fc_policy_group.py2
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_leaf_policy_group.py85
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_link_level.py5
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_pim.py444
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_storm_control.py434
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_key_policy.py325
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_keychain_policy.py276
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l2out.py4
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l2out_extepg.py6
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l2out_extepg_to_contract.py4
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l2out_logical_interface_path.py4
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l2out_logical_interface_profile.py2
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l2out_logical_node_profile.py2
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l3out.py88
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l3out_bfd_interface_profile.py367
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l3out_bfd_multihop_interface_profile.py366
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l3out_bgp_peer.py163
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l3out_dhcp_relay_label.py354
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l3out_eigrp_interface_profile.py392
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l3out_extepg.py4
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l3out_extepg_to_contract.py99
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l3out_extsubnet.py6
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l3out_floating_svi.py475
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l3out_floating_svi_path.py491
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l3out_floating_svi_path_secondary_ip.py398
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l3out_floating_svi_secondary_ip.py362
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l3out_hsrp_group.py393
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l3out_hsrp_interface_profile.py320
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l3out_hsrp_secondary_vip.py344
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l3out_interface.py121
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l3out_interface_secondary_ip.py6
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l3out_logical_interface_profile.py202
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l3out_logical_interface_profile_ospf_policy.py19
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l3out_logical_interface_vpc_member.py2
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l3out_logical_node.py48
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l3out_logical_node_profile.py40
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l3out_static_routes.py4
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l3out_static_routes_nexthop.py2
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_l3out_to_sr_mpls_infra_l3out.py355
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_maintenance_group_node.py2
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_match_route_destination.py2
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_netflow_exporter_policy.py490
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_netflow_monitor_policy.py300
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_netflow_monitor_to_exporter.py290
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_netflow_record_policy.py313
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_node_block.py390
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_node_mgmt_epg.py6
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_ntp_policy.py6
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_ntp_server.py4
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_pim_route_map_entry.py329
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_pim_route_map_policy.py276
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_qos_custom_policy.py284
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_qos_dot1p_class.py355
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_qos_dscp_class.py356
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_rest.py48
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_snmp_client.py2
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_snmp_client_group.py2
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_snmp_community_policy.py2
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_snmp_policy.py4
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_snmp_user.py4
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_static_node_mgmt_address.py6
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_subject_label.py746
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_switch_leaf_selector.py30
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_switch_policy_vpc_protection_group.py2
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_syslog_group.py6
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_syslog_remote_dest.py5
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_syslog_source.py2
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_system.py9
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_tag.py6
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_tenant_action_rule_profile.py232
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_vmm_controller.py22
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_vmm_vswitch_policy.py4
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_vrf_multicast.py702
-rw-r--r--ansible_collections/cisco/aci/plugins/modules/aci_vzany_to_contract.py4
153 files changed, 26079 insertions, 539 deletions
diff --git a/ansible_collections/cisco/aci/plugins/doc_fragments/aci.py b/ansible_collections/cisco/aci/plugins/doc_fragments/aci.py
index e6b18a289..aaedff669 100644
--- a/ansible_collections/cisco/aci/plugins/doc_fragments/aci.py
+++ b/ansible_collections/cisco/aci/plugins/doc_fragments/aci.py
@@ -2,6 +2,7 @@
# Copyright: (c) 2017, Dag Wieers (@dagwieers) <dag@wieers.com>
# Copyright: (c) 2017, Swetha Chunduri (@schunduri)
+# Copyright: (c) 2024, Samita Bhattacharjee (@samiib) <samitab@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
@@ -94,6 +95,15 @@ options:
- Path to a file that will be used to dump the ACI JSON configuration objects generated by the module.
- If the value is not specified in the task, the value of environment variable C(ACI_OUTPUT_PATH) will be used instead.
type: str
+ suppress_verification:
+ description:
+ - If C(true), a verifying GET will not be sent after a POST update to APIC.
+ - If the value is not specified in the task, the value of environment variable C(ACI_NO_VERIFICATION) will be used instead.
+ - The default value is C(false).
+ - WARNING - This causes the current return value to be set to the proposed value.
+ - The current object including default values will be unverifiable in a single task.
+ type: bool
+ aliases: [ no_verification, no_verify, suppress_verify ]
seealso:
- ref: aci_guide
description: Detailed information on how to manage your ACI infrastructure using Ansible.
diff --git a/ansible_collections/cisco/aci/plugins/filter/listify.py b/ansible_collections/cisco/aci/plugins/filter/listify.py
new file mode 100644
index 000000000..2bb090b25
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/filter/listify.py
@@ -0,0 +1,295 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2017, Ramses Smeyers <rsmeyers@cisco.com>
+# Copyright: (c) 2023, Shreyas Srish <ssrish@cisco.com>
+# Copyright: (c) 2024, Akini Ross <akinross@cisco.com>
+# GNU General Public License v3.0+ (see COPYING 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"""
+ name: aci_listify
+ short_description: Flattens the nested dictionaries representing the ACI model data.
+ description:
+ - This filter flattens and transforms the input data into a list.
+ - See the Examples section below.
+ options:
+ data:
+ description: This option represents the ACI model data which is a list of dictionaries or a dictionary with any level of nesting data.
+ type: raw
+ required: True
+ keys:
+ description: Comma separated keys of type string denoting the ACI objects.
+ required: True
+"""
+
+EXAMPLES = r"""
+- name: Set vars
+ ansible.builtin.set_fact:
+ data:
+ tenant:
+ - name: ansible_test
+ description: Created using listify
+ app:
+ - name: app_test
+ epg:
+ - name: web
+ bd: web_bd
+ - name: app
+ bd: app_bd
+ bd:
+ - name: bd_test
+ subnet:
+ - name: 10.10.10.1
+ mask: 24
+ scope:
+ - public
+ - shared
+ vrf: vrf_test
+ - name: bd_test2
+ subnet:
+ - name: 20.20.20.1
+ mask: 24
+ scope: public
+ vrf: vrf_test
+ vrf:
+ - name: vrf_test
+ policies:
+ protocol:
+ bfd:
+ - name: BFD-ON
+ description: Enable BFD
+ admin_state: enabled
+ detection_multiplier: 3
+ min_tx_interval: 50
+ min_rx_interval: 50
+ echo_rx_interval: 50
+ echo_admin_state: enabled
+ sub_interface_optimization_state: enabled
+ ospf:
+ interface:
+ - name: OSPF-P2P-IntPol
+ network_type: p2p
+ priority: 1
+ - name: OSPF-Broadcast-IntPol
+ network_type: bcast
+ priority: 1
+
+- name: Create tenants
+ cisco.aci.aci_tenant:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: '{{ item.tenant_name }}'
+ description: '{{ item.tenant_description }}'
+ with_items: '{{ data|cisco.aci.aci_listify("tenant") }}'
+
+- name: Create VRFs
+ cisco.aci.aci_vrf:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: '{{ item.tenant_name }}'
+ vrf_name: '{{ item.tenant_vrf_name }}'
+ with_items: '{{ data|cisco.aci.aci_listify("tenant","vrf") }}'
+
+- name: Create BDs
+ cisco.aci.aci_bd:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: '{{ item.tenant_name }}'
+ vrf: '{{ item.tenant_bd_vrf }}'
+ bd: '{{ item.tenant_bd_name }}'
+ enable_routing: yes
+ with_items: '{{ data|cisco.aci.aci_listify("tenant","bd") }}'
+
+- name: Create BD subnets
+ cisco.aci.aci_bd_subnet:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: '{{ item.tenant_name }}'
+ bd: '{{ item.tenant_bd_name }}'
+ gateway: '{{ item.tenant_bd_subnet_name }}'
+ mask: '{{ item.tenant_bd_subnet_mask }}'
+ scope: '{{ item.tenant_bd_subnet_scope }}'
+ with_items: '{{ data|cisco.aci.aci_listify("tenant","bd","subnet") }}'
+
+- name: Create APs
+ cisco.aci.aci_ap:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: '{{ item.tenant_name }}'
+ app_profile: '{{ item.tenant_app_name }}'
+ with_items: '{{ data|cisco.aci.aci_listify("tenant","app") }}'
+
+- name: Create EPGs
+ cisco.aci.aci_epg:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: '{{ item.tenant_name }}'
+ app_profile: '{{ item.tenant_app_name }}'
+ epg: '{{ item.tenant_app_epg_name }}'
+ bd: '{{ item.tenant_app_epg_bd }}'
+ with_items: '{{ data|cisco.aci.aci_listify("tenant","app","epg") }}'
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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
+"""
+
+
+# This function takes a dictionary and a series of keys,
+# and returns a list of dictionaries using recursive helper function 'listify_worker'
+def listify(d, *keys):
+ return list(listify_worker(d, keys, 0, {}, ""))
+
+
+# This function walks through a dictionary 'd', depth-first,
+# using the keys provided, and generates a new dictionary for each key:value pair encountered
+def listify_worker(d, keys, depth, cache, prefix):
+ # The prefix in the code is used to store the path of keys traversed in the nested dictionary,
+ # which helps to generate unique keys for each value when flattening the dictionary.
+ prefix += keys[depth] + "_"
+
+ if keys[depth] in d:
+ for item in d[keys[depth]]:
+ cache_work = cache.copy()
+ if isinstance(item, dict):
+ for k, v in item.items():
+ if isinstance(v, list) and all(isinstance(x, (str, int, float, bool, bytes)) for x in v) or not isinstance(v, (dict, list)):
+ # The cache in this code is a temporary storage that holds key-value pairs as the function navigates through the nested dictionary.
+ # It helps to generate the final output by remembering the traversed path in each recursive call.
+ cache_key = prefix + k
+ cache_value = v
+ cache_work[cache_key] = cache_value
+ # If we're at the deepest level of keys
+ if len(keys) - 1 == depth:
+ yield cache_work
+ else:
+ for k, v in item.items():
+ if k == keys[depth + 1] and isinstance(v, (dict, list)):
+ for result in listify_worker({k: v}, keys, depth + 1, cache_work, prefix):
+ yield result
+ # Conditional to support nested dictionaries which are detected by item is string
+ elif isinstance(item, str) and isinstance(d[keys[depth]], dict):
+ for result in listify_worker({item: d[keys[depth]][item]}, keys, depth + 1, cache_work, prefix):
+ yield result
+
+
+class FilterModule(object):
+ """Ansible core jinja2 filters"""
+
+ def filters(self):
+ return {
+ "aci_listify": listify,
+ }
diff --git a/ansible_collections/cisco/aci/plugins/httpapi/aci.py b/ansible_collections/cisco/aci/plugins/httpapi/aci.py
index a0474576a..dfab2c14e 100644
--- a/ansible_collections/cisco/aci/plugins/httpapi/aci.py
+++ b/ansible_collections/cisco/aci/plugins/httpapi/aci.py
@@ -102,19 +102,6 @@ class HttpApi(HttpApiBase):
exc_login.path = path
raise
- def logout(self):
- method = "POST"
- path = "/api/aaaLogout.json"
- payload = {"aaaUser": {"attributes": {"name": self.connection.get_option("remote_user")}}}
- data = json.dumps(payload)
- try:
- response, response_data = self.connection.send(path, data, method=method)
- except Exception as exc_logout:
- msg = "Error on attempt to logout from APIC. {0}".format(exc_logout)
- raise ConnectionError(self._return_info("", method, path, msg))
- self.connection._auth = None
- self._verify_response(response, method, path, response_data)
-
def set_parameters(self):
connection_parameters = {}
for key in CONNECTION_KEYS:
diff --git a/ansible_collections/cisco/aci/plugins/module_utils/aci.py b/ansible_collections/cisco/aci/plugins/module_utils/aci.py
index 9c6e2db2d..88b49cd6e 100644
--- a/ansible_collections/cisco/aci/plugins/module_utils/aci.py
+++ b/ansible_collections/cisco/aci/plugins/module_utils/aci.py
@@ -15,6 +15,8 @@
# Copyright: (c) 2020, Anvitha Jain (@anvitha-jain) <anvjain@cisco.com>
# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com>
# Copyright: (c) 2023, Shreyas Srish (@shrsr) <ssrish@cisco.com>
+# Copyright: (c) 2023, Tim Cragg (@timcragg) <tcragg@cisco.com>
+# Copyright: (c) 2024, Samita Bhattacharjee (@samiib) <samitab@cisco.com>
# All rights reserved.
# Redistribution and use in source and binary forms, with or without modification,
@@ -134,6 +136,7 @@ def aci_argument_spec():
use_ssl=dict(type="bool", fallback=(env_fallback, ["ACI_USE_SSL"])),
validate_certs=dict(type="bool", fallback=(env_fallback, ["ACI_VALIDATE_CERTS"])),
output_path=dict(type="str", fallback=(env_fallback, ["ACI_OUTPUT_PATH"])),
+ suppress_verification=dict(type="bool", aliases=["no_verification", "no_verify", "suppress_verify"], fallback=(env_fallback, ["ACI_NO_VERIFICATION"])),
)
@@ -320,6 +323,64 @@ def integrate_url(httpapi_url, local_path):
return {"protocol": parse_url.scheme, "host": parse_url.netloc, "path": local_path}
+def action_rule_set_comm_spec():
+ return dict(
+ community=dict(type="str"),
+ criteria=dict(type="str", choices=["append", "none", "replace"]),
+ )
+
+
+def action_rule_set_dampening_spec():
+ return dict(
+ half_life=dict(type="int"),
+ max_suppress_time=dict(type="int"),
+ reuse=dict(type="int"),
+ suppress=dict(type="int"),
+ )
+
+
+def associated_netflow_exporter_epg_spec():
+ return dict(
+ tenant=dict(type="str"),
+ ap=dict(type="str"),
+ epg=dict(type="str"),
+ )
+
+
+def associated_netflow_exporter_extepg_spec():
+ return dict(
+ tenant=dict(type="str"),
+ l3out=dict(type="str"),
+ extepg=dict(type="str"),
+ )
+
+
+def associated_netflow_exporter_vrf_spec():
+ return dict(
+ tenant=dict(type="str"),
+ vrf=dict(type="str"),
+ )
+
+
+def pim_interface_profile_spec():
+ return dict(
+ tenant=dict(type="str", aliases=["tenant_name"]),
+ pim=dict(type="str", aliases=["pim_interface_policy", "name"]),
+ )
+
+
+def igmp_interface_profile_spec():
+ return dict(tenant=dict(type="str", aliases=["tenant_name"]), igmp=dict(type="str", aliases=["igmp_interface_policy", "name"]))
+
+
+def storm_control_policy_rate_spec():
+ return dict(
+ rate=dict(type="str"),
+ burst_rate=dict(type="str"),
+ rate_type=dict(type="str", choices=["percentage", "pps"], required=True),
+ )
+
+
class ACIModule(object):
def __init__(self, module):
self.module = module
@@ -356,6 +417,9 @@ class ACIModule(object):
self.imdata = None
self.totalCount = None
+ # get no verify flag
+ self.suppress_verification = self.params.get("suppress_verification")
+
# Ensure protocol is set
self.define_protocol()
@@ -779,8 +843,10 @@ class ACIModule(object):
subclass_3=None,
subclass_4=None,
subclass_5=None,
+ subclass_6=None,
child_classes=None,
config_only=True,
+ rsp_subtree="full",
):
"""
This method is used to retrieve the appropriate URL path and filter_string to make the request to the APIC.
@@ -796,6 +862,7 @@ class ACIModule(object):
:type subclass_3: dict
:type subclass_4: dict
:type subclass_5: dict
+ :type subclass_6: dict
:type child_classes: list
:return: The path and filter_string needed to build the full URL.
"""
@@ -806,7 +873,9 @@ class ACIModule(object):
else:
self.child_classes = set(child_classes)
- if subclass_5 is not None:
+ if subclass_6 is not None:
+ self._construct_url_7(root_class, subclass_1, subclass_2, subclass_3, subclass_4, subclass_5, subclass_6, config_only)
+ elif subclass_5 is not None:
self._construct_url_6(root_class, subclass_1, subclass_2, subclass_3, subclass_4, subclass_5, config_only)
elif subclass_4 is not None:
self._construct_url_5(root_class, subclass_1, subclass_2, subclass_3, subclass_4, config_only)
@@ -828,10 +897,12 @@ class ACIModule(object):
# Append child_classes to filter_string if filter string is empty
self.update_qs(
{
- "rsp-subtree": "full",
+ "rsp-subtree": rsp_subtree,
"rsp-subtree-class": ",".join(sorted(self.child_classes)),
}
)
+ elif rsp_subtree == "children":
+ self.update_qs({"rsp-subtree": rsp_subtree})
def _construct_url_1(self, obj, config_only=True):
"""
@@ -1077,7 +1148,7 @@ class ACIModule(object):
def _construct_url_6(self, root, quad, ter, sec, parent, obj, config_only=True):
"""
- This method is used by construct_url when the object is the fourth-level class.
+ This method is used by construct_url when the object is the fifth-level class.
"""
root_rn = root.get("aci_rn")
root_obj = root.get("module_object")
@@ -1145,6 +1216,85 @@ class ACIModule(object):
# Query for a specific object of the module's class
self.path = "api/mo/uni/{0}/{1}/{2}/{3}/{4}/{5}.json".format(root_rn, quad_rn, ter_rn, sec_rn, parent_rn, obj_rn)
+ def _construct_url_7(self, root, quin, quad, ter, sec, parent, obj, config_only=True):
+ """
+ This method is used by construct_url when the object is the sixth-level class.
+ """
+ root_rn = root.get("aci_rn")
+ root_obj = root.get("module_object")
+ quin_rn = quin.get("aci_rn")
+ quin_obj = quin.get("module_object")
+ quad_rn = quad.get("aci_rn")
+ quad_obj = quad.get("module_object")
+ ter_rn = ter.get("aci_rn")
+ ter_obj = ter.get("module_object")
+ sec_rn = sec.get("aci_rn")
+ sec_obj = sec.get("module_object")
+ parent_rn = parent.get("aci_rn")
+ parent_obj = parent.get("module_object")
+ obj_class = obj.get("aci_class")
+ obj_rn = obj.get("aci_rn")
+ obj_filter = obj.get("target_filter")
+ mo = obj.get("module_object")
+
+ if self.child_classes is None:
+ self.child_classes = [obj_class]
+
+ if self.module.params.get("state") in ("absent", "present"):
+ # State is absent or present
+ self.path = "api/mo/uni/{0}/{1}/{2}/{3}/{4}/{5}/{6}.json".format(root_rn, quin_rn, quad_rn, ter_rn, sec_rn, parent_rn, obj_rn)
+ if config_only:
+ self.update_qs({"rsp-prop-include": "config-only"})
+ self.obj_filter = obj_filter
+ # TODO: Add all missing cases
+ elif root_obj is None:
+ self.child_classes.add(obj_class)
+ self.path = "api/class/{0}.json".format(obj_class)
+ self.update_qs({"query-target-filter": self.build_filter(obj_class, obj_filter)})
+ elif quin_obj is None:
+ self.child_classes.add(obj_class)
+ self.path = "api/mo/uni/{0}.json".format(root_rn)
+ # NOTE: No need to select by root_filter
+ # self.update_qs({'query-target-filter': self.build_filter(root_class, root_filter)})
+ # TODO: Filter by quin_filter, parent and obj_filter
+ self.update_qs({"rsp-subtree-filter": self.build_filter(obj_class, obj_filter)})
+ elif quad_obj is None:
+ self.child_classes.add(obj_class)
+ self.path = "api/mo/uni/{0}/{1}.json".format(root_rn, quin_rn)
+ # NOTE: No need to select by root_filter
+ # self.update_qs({'query-target-filter': self.build_filter(root_class, root_filter)})
+ # TODO: Filter by quin_filter, parent and obj_filter
+ self.update_qs({"rsp-subtree-filter": self.build_filter(obj_class, obj_filter)})
+ elif ter_obj is None:
+ self.child_classes.add(obj_class)
+ self.path = "api/mo/uni/{0}/{1}/{2}.json".format(root_rn, quin_rn, quad_rn)
+ # NOTE: No need to select by quad_filter
+ # self.update_qs({'query-target-filter': self.build_filter(quin_class, quin_filter)})
+ # TODO: Filter by ter_filter, parent and obj_filter
+ self.update_qs({"rsp-subtree-filter": self.build_filter(obj_class, obj_filter)})
+ elif sec_obj is None:
+ self.child_classes.add(obj_class)
+ self.path = "api/mo/uni/{0}/{1}/{2}/{3}.json".format(root_rn, quin_rn, quad_rn, ter_rn)
+ # NOTE: No need to select by ter_filter
+ # self.update_qs({'query-target-filter': self.build_filter(ter_class, ter_filter)})
+ # TODO: Filter by sec_filter, parent and obj_filter
+ self.update_qs({"rsp-subtree-filter": self.build_filter(obj_class, obj_filter)})
+ elif parent_obj is None:
+ self.child_classes.add(obj_class)
+ self.path = "api/mo/uni/{0}/{1}/{2}/{3}/{4}.json".format(root_rn, quin_rn, quad_rn, ter_rn, sec_rn)
+ # NOTE: No need to select by sec_filter
+ # self.update_qs({'query-target-filter': self.build_filter(sec_class, sec_filter)})
+ # TODO: Filter by parent_filter and obj_filter
+ self.update_qs({"rsp-subtree-filter": self.build_filter(obj_class, obj_filter)})
+ elif mo is None:
+ self.child_classes.add(obj_class)
+ self.path = "api/mo/uni/{0}/{1}/{2}/{3}/{4}/{5}.json".format(root_rn, quin_rn, quad_rn, ter_rn, sec_rn, parent_rn)
+ # NOTE: No need to select by parent_filter
+ # self.update_qs({'query-target-filter': self.build_filter(parent_class, parent_filter)})
+ else:
+ # Query for a specific object of the module's class
+ self.path = "api/mo/uni/{0}/{1}/{2}/{3}/{4}/{5}/{6}.json".format(root_rn, quin_rn, quad_rn, ter_rn, sec_rn, parent_rn, obj_rn)
+
def delete_config(self):
"""
This method is used to handle the logic when the modules state is equal to absent. The method only pushes a change if
@@ -1161,7 +1311,7 @@ class ACIModule(object):
self.result["changed"] = True
self.method = "DELETE"
- def get_diff(self, aci_class):
+ def get_diff(self, aci_class, required_properties=None):
"""
This method is used to get the difference between the proposed and existing configurations. Each module
should call the get_existing method before this method, and add the proposed config to the module results
@@ -1183,6 +1333,8 @@ class ACIModule(object):
# add name back to config only if the configs do not match
if config:
# TODO: If URLs are built with the object's name, then we should be able to leave off adding the name back
+ if required_properties and isinstance(required_properties, dict):
+ config.update(required_properties)
config = {aci_class: {"attributes": config}}
# check for updates to child configs and update new config dictionary
@@ -1369,23 +1521,30 @@ class ACIModule(object):
# add child objects to proposed
if child_configs:
- children = []
- for child in child_configs:
- child_copy = deepcopy(child)
- has_value = False
- for root_key in child_copy.keys():
- for final_keys, values in child_copy[root_key]["attributes"].items():
- if values is None:
- child[root_key]["attributes"].pop(final_keys)
- else:
- child[root_key]["attributes"][final_keys] = str(values)
- has_value = True
- if has_value:
- children.append(child)
+ children = self.handle_child_configs(child_configs)
if children:
self.proposed[aci_class].update(dict(children=children))
+ def handle_child_configs(self, child_configs):
+ children = []
+ for child in child_configs:
+ child_copy = deepcopy(child)
+ has_value = False
+ for class_name in child_copy.keys():
+ for attribute, value in child_copy[class_name]["attributes"].items():
+ if value is None:
+ child[class_name]["attributes"].pop(attribute)
+ else:
+ child[class_name]["attributes"][attribute] = str(value)
+ has_value = True
+ if child_copy[class_name].get("children") is not None:
+ has_value = True
+ child[class_name]["children"] = self.handle_child_configs(child_copy[class_name]["children"])
+ if has_value:
+ children.append(child)
+ return children
+
def post_config(self, parent_class=None):
"""
This method is used to handle the logic when the modules state is equal to present. The method only pushes a change if
@@ -1438,7 +1597,15 @@ class ACIModule(object):
if "state" in self.params:
self.original = self.existing
if self.params.get("state") in ("absent", "present"):
- self.get_existing()
+ if self.suppress_verification:
+ if self.result["changed"]:
+ self.result["current_verified"] = False
+ self.existing = [self.proposed]
+ else:
+ self.result["current_verified"] = True
+ # exisiting already equals the previous
+ else:
+ self.get_existing()
# if self.module._diff and self.original != self.existing:
# self.result['diff'] = dict(
diff --git a/ansible_collections/cisco/aci/plugins/module_utils/annotation_unsupported.py b/ansible_collections/cisco/aci/plugins/module_utils/annotation_unsupported.py
new file mode 100644
index 000000000..6e34889fb
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/module_utils/annotation_unsupported.py
@@ -0,0 +1,853 @@
+# Code generated by release_script GitHub action; DO NOT EDIT MANUALLY.
+ANNOTATION_UNSUPPORTED = [
+ "topRoot",
+ "monPol",
+ "monATarget",
+ "monTarget",
+ "moTopProps",
+ "moModifiable",
+ "moOwnable",
+ "moResolvable",
+ "moASubj",
+ "actionACont",
+ "taskExec",
+ "namingNamedObject",
+ "namingNamedIdentifiedObject",
+ "conditionInfo",
+ "conditionRetP",
+ "conditionRecord",
+ "conditionLoggable",
+ "faultInfo",
+ "relnInst",
+ "relnTo",
+ "relnFrom",
+ "statsItem",
+ "statsAColl",
+ "statsAThrP",
+ "relnTaskRef",
+ "hvsNode",
+ "qosACong",
+ "qosAQueue",
+ "qosABuffer",
+ "qosASched",
+ "qosClassification",
+ "qosADscpClass",
+ "qosADot1PClass",
+ "lacpALagPol",
+ "pconsRef",
+ "eventARetP",
+ "faultAThrValue",
+ "faultARetP",
+ "configABackupP",
+ "dnsAProfile",
+ "dnsAProv",
+ "dnsADomain",
+ "dnsALbl",
+ "sysdebugRepository",
+ "sysdebugFile",
+ "sysdebugLogBehavior",
+ "firmwareSource",
+ "firmwareAFwStatusCont",
+ "firmwareARunning",
+ "firmwareAFwP",
+ "maintAMaintP",
+ "maintUserNotif",
+ "fabricComp",
+ "fabricANode",
+ "fabricALink",
+ "ruleDefinition",
+ "ruleItem",
+ "ruleRequirement",
+ "ruleSizeRequirement",
+ "stpAIfPol",
+ "haHaTest",
+ "rtctrlAMatchRule",
+ "rtctrlAMatchIpRule",
+ "rtctrlAMatchRtType",
+ "rtctrlASubnet",
+ "rtctrlAAttrP",
+ "rtctrlASetRule",
+ "rtctrlASetTag",
+ "rtctrlASetComm",
+ "rtctrlASetRtMetric",
+ "rtctrlASetPref",
+ "rtctrlASetNh",
+ "rtctrlASetOspfFwdAddr",
+ "rtctrlASetOspfNssa",
+ "bgpAAsP",
+ "bgpACtxPol",
+ "bgpAPeerPfxPol",
+ "bgpAPeerP",
+ "bgpAExtP",
+ "cdpAIfPol",
+ "fabricProtoIfPol",
+ "fabricL2IfPol",
+ "fabricL3IfPol",
+ "lldpAIfPol",
+ "fabricProtoPol",
+ "fabricProtoComp",
+ "fabricL2ProtoPol",
+ "fabricL3ProtoPol",
+ "fabricL2ProtoComp",
+ "fabricL3ProtoComp",
+ "fabricProtoInstPol",
+ "fabricUtilInstPol",
+ "fabricL2InstPol",
+ "fabricL3InstPol",
+ "fabricProtoDomPol",
+ "fabricL2DomPol",
+ "fabricL3DomPol",
+ "fabricL3CtxPol",
+ "l2AInstPol",
+ "fabricMaintPol",
+ "fabricNodeGrp",
+ "fabricAPodBlk",
+ "fabricANodeBlk",
+ "fabricAPortBlk",
+ "fabricSelector",
+ "fabricANodeS",
+ "fabricNodeS",
+ "fabricACardS",
+ "fabricCardS",
+ "fabricAPortS",
+ "fabricPortS",
+ "fabricIntfPol",
+ "fabricAProfile",
+ "fabricProfile",
+ "fabricPolGrp",
+ "fabricNodeP",
+ "fabricCardP",
+ "fabricPortP",
+ "fabricAPortPGrp",
+ "fabricANodePGrp",
+ "fabricACardPGrp",
+ "fabricSpAPortPGrp",
+ "fabricLeAPortPGrp",
+ "fabricAProtPol",
+ "fabricANodePEp",
+ "fabricPol",
+ "fabricInfrP",
+ "fabricInfrExP",
+ "fabricDom",
+ "fabricDef",
+ "fabricAPolGrp",
+ "vsvcAProvLbl",
+ "vsvcAConsLbl",
+ "compASvcVM",
+ "compNic",
+ "compPNic",
+ "compEntity",
+ "compElement",
+ "compContE",
+ "compObj",
+ "compCont",
+ "compProvP",
+ "compDomP",
+ "compCtrlrP",
+ "compAccessP",
+ "compUsrAccP",
+ "compHost",
+ "compPHost",
+ "vzACollection",
+ "vzACtrct",
+ "vzABrCP",
+ "vzAIf",
+ "vzAFilterable",
+ "vzAFilterableUnit",
+ "vzASubj",
+ "vzATerm",
+ "vzASTerm",
+ "vzALbl",
+ "vzACompLbl",
+ "vzAnyToCollection",
+ "vzAFilter",
+ "vzAFiltEntry",
+ "ospfACtxPol",
+ "ospfAIfP",
+ "ospfAExtP",
+ "dhcpARelayP",
+ "dhcpALbl",
+ "dhcpAInfraProvP",
+ "poolElement",
+ "poolPoolable",
+ "poolPoolMember",
+ "poolPool",
+ "pkiItem",
+ "aaaDefinition",
+ "commDefinition",
+ "pkiDefinition",
+ "aaaSystemUser",
+ "aaaBanner",
+ "aaaUserAction",
+ "aaaARetP",
+ "commComp",
+ "commWeb",
+ "commShell",
+ "aaaRealm",
+ "aaaConfig",
+ "aaaAuthMethod",
+ "aaaEp",
+ "aaaAProvider",
+ "aaaProviderGroup",
+ "adcomATsInfoUnit",
+ "adcomARwi",
+ "healthARetP",
+ "healthAInst",
+ "igmpASnoopPol",
+ "sysfileEp",
+ "sysfileRepository",
+ "sysfileInstance",
+ "fileARemoteHost",
+ "fileARemotePath",
+ "monProtoP",
+ "monSecAuthP",
+ "monGroup",
+ "monSubj",
+ "monSrc",
+ "conditionCondP",
+ "ctrlrDom",
+ "l2extADomP",
+ "l2extALNodeP",
+ "l2extAIfP",
+ "l2extAInstPSubnet",
+ "extnwEPg",
+ "extnwOut",
+ "extnwDomP",
+ "extnwAInstPSubnet",
+ "extnwALNodeP",
+ "extnwALIfP",
+ "l3extADomP",
+ "l3extALNodeP",
+ "l3extAIfP",
+ "l3extAMember",
+ "l3extAInstPSubnet",
+ "trigSchedWindowP",
+ "trigInst",
+ "trigWindow",
+ "trigSchedWindow",
+ "trigExecutable",
+ "trigTriggerable",
+ "trigSingleTriggerable",
+ "fvACont",
+ "fvADeplCont",
+ "fvL2Dom",
+ "fvABD",
+ "fvABDPol",
+ "fvAEpRetPol",
+ "fvComp",
+ "fvATg",
+ "fvEPgToCollection",
+ "fvADomP",
+ "fvEPg",
+ "fvCEPg",
+ "fvAREpPCtrct",
+ "fvDom",
+ "fvL3Dom",
+ "fvACtx",
+ "fvNwEp",
+ "fvATp",
+ "fvEp",
+ "fvPEp",
+ "fvAEpDef",
+ "fvTo",
+ "fvFrom",
+ "mgmtAZone",
+ "mgmtAInstPSubnet",
+ "eqptdiagpTestSet",
+ "eqptdiagpTestSetBoot",
+ "eqptdiagpTestSetHealth",
+ "eqptdiagpTestSetOd",
+ "eqptdiagpPortTestSetOd",
+ "eqptdiagpPortTestSetBt",
+ "eqptdiagpPortTestSetHl",
+ "eqptdiagpLpTsOd",
+ "eqptdiagpFpTsOd",
+ "eqptdiagpCardTestSetOd",
+ "eqptdiagpSupCTsOd",
+ "eqptdiagpSysCTsOd",
+ "eqptdiagpFcTsOd",
+ "eqptdiagpLcTsOd",
+ "eqptdiagpExtChCardTsOd",
+ "eqptdiagpPol",
+ "eqptdiagpHealthPol",
+ "eqptdiagpASynthObj",
+ "oamExec",
+ "pingAExec",
+ "tracerouteAExec",
+ "bgpAf",
+ "dhcpAddr",
+ "dhcpNode",
+ "dhcpResp",
+ "eqptALPort",
+ "dbgACRulePCommon",
+ "dbgacTenantSpaceCmn",
+ "dbgacEpgCmn",
+ "dbgacFromEpgCmn",
+ "dbgacToEpgCmn",
+ "dbgacFromEpCmn",
+ "dbgacToEpCmn",
+ "dbgexpExportP",
+ "dbgexpNodeStatus",
+ "spanASrcGrp",
+ "spanASrc",
+ "spanASpanLbl",
+ "spanADest",
+ "spanAVSrc",
+ "spanAVSrcGrp",
+ "spanAVDestGrp",
+ "spanAVDest",
+ "svccorePol",
+ "svccoreACore",
+ "traceroutepTrP",
+ "syntheticObject",
+ "syntheticAContext",
+ "syntheticATestObj",
+ "syntheticTLTestObj",
+ "syntheticCTestObj",
+ "monExportP",
+ "ipARouteP",
+ "ipANexthopP",
+ "infraFexBlk",
+ "infraANodeS",
+ "infraNodeGrp",
+ "infraPortS",
+ "infraEPg",
+ "infraACEPg",
+ "infraAPEPg",
+ "infraANode",
+ "infraAIpP",
+ "infraProfile",
+ "infraPolGrp",
+ "infraAccBaseGrp",
+ "infraFexGrp",
+ "infraAccGrp",
+ "infraLbl",
+ "infraAPEp",
+ "infraACEp",
+ "infraAFunc",
+ "infraGeNode",
+ "infraADomP",
+ "infraDomP",
+ "infraExP",
+ "datetimeAPol",
+ "datetimeANtpAuthKey",
+ "datetimeANtpProv",
+ "fvnsAAddrBlk",
+ "fvnsAEncapBlk",
+ "fvnsAInstP",
+ "fvnsAVxlanInstP",
+ "fvnsAAddrInstP",
+ "polAttTgt",
+ "snmpAPol",
+ "snmpACommunityP",
+ "snmpAUserP",
+ "snmpAClientGrpP",
+ "snmpAClientP",
+ "snmpACtxP",
+ "fvDef",
+ "fvNp",
+ "fvUp",
+ "polNToRef",
+ "polNFromRef",
+ "polObj",
+ "polDef",
+ "polDefRoot",
+ "polComp",
+ "polInstr",
+ "polCont",
+ "polDom",
+ "polCtrlr",
+ "polCompl",
+ "polComplElem",
+ "polConsElem",
+ "polLbl",
+ "polProvLbl",
+ "polConsLbl",
+ "polIf",
+ "polProvIf",
+ "polConsIf",
+ "polRelnHolder",
+ "polNs",
+ "polAConfIssues",
+ "vnsAGraph",
+ "vnsANode",
+ "vnsAFuncNode",
+ "vnsAFolder",
+ "vnsACCfgRel",
+ "vnsAParam",
+ "vnsATerm",
+ "vnsATermNode",
+ "vnsAbsTermNode",
+ "vnsALDevCtx",
+ "vnsALIfCtx",
+ "vnsAConn",
+ "vnsAFuncConn",
+ "vnsATermConn",
+ "vnsAConnection",
+ "vnsAL4L7ServiceFault",
+ "vnsACCfg",
+ "vnsALDevIf",
+ "vnsALDev",
+ "vnsALIf",
+ "vnsALDevLIf",
+ "vnsDevItem",
+ "fabricAPathIssues",
+ "conditionSevAsnP",
+ "fvAStCEp",
+ "fabricNodeToPolicy",
+ "aaaADomainRef",
+ "fvAEpTaskAggr",
+ "vzToRFltP",
+ "fvAToBD",
+ "frmwrkARelDelCont",
+ "infraDomainToNs",
+ "infraToAInstP",
+ "aaaARbacRule",
+ "statsDebugItem",
+ "vzInterfaceToCollection",
+ "spanAToCEp",
+ "fabricAOOSReln",
+ "l4AVxlanInstPol",
+ "fabricVxlanInstPol",
+ "fabricL1IfPol",
+ "frmwrkARelDelControl",
+ "spanACEpDef",
+ "eptrkEpRslt",
+ "mcpAIfPol",
+ "ipmcsnoopRtrIf",
+ "bfdAf",
+ "bgpALocalAsnP",
+ "bgpACtxAfPol",
+ "l3extADefaultRouteLeakP",
+ "fvAStIp",
+ "rtctrlASetRtMetricType",
+ "vnsAEPpInfo",
+ "ndAIfPol",
+ "ndAPfxPol",
+ "eigrpACtxAfPol",
+ "eigrpAStubP",
+ "eigrpAIfP",
+ "eigrpAExtP",
+ "l3extAIp",
+ "fabricProtoConsFrom",
+ "fabricProtoConsTo",
+ "fabricAPathS",
+ "infraAAccBndlGrp",
+ "fabricNodeToPathOverridePolicy",
+ "adcomARwiAdvanced",
+ "fvAClassifier",
+ "fvACrtrn",
+ "fvAttr",
+ "fvAVmAttr",
+ "fvAIpAttr",
+ "fvAMacAttr",
+ "fvAProtoAttr",
+ "polADependentOn",
+ "vnsAVRoutingNetworks",
+ "l3extARouteTagPol",
+ "nwsAFwPol",
+ "fabricL4IfPol",
+ "fvAVip",
+ "fvAAREpPUpdate",
+ "conditionSummary",
+ "polAPrToPol",
+ "polAObjToPolReln",
+ "fvACrRule",
+ "fvASCrtrn",
+ "fvnsAVlanInstP",
+ "vzAnyToInterface",
+ "fvEPgToInterface",
+ "fabricPodGrp",
+ "fabricAPodS",
+ "infraPodGrp",
+ "vnsAMgmt",
+ "fabricPolicyGrpToMonitoring",
+ "plannerIPs",
+ "plannerAObject",
+ "plannerAEpg",
+ "compAPltfmP",
+ "compAVmmPltfmP",
+ "compAVmmSecP",
+ "bgpARRP",
+ "bgpARtTargetP",
+ "bgpARtTarget",
+ "l3extAFabricExtRoutingP",
+ "fvAFabricExtConnP",
+ "fvAPodConnP",
+ "fvAPeeringP",
+ "fvANode",
+ "plannerATmpl",
+ "nwsASrc",
+ "nwsASyslogSrc",
+ "throttlerASub",
+ "qosADscpTrans",
+ "fvARsToRemote",
+ "vnsOrchReq",
+ "vnsOrchResp",
+ "fcprARs",
+ "dbgexpTechSupOnDBase",
+ "infraGeSnNode",
+ "l3extAConsLbl",
+ "l3extAProvLbl",
+ "trigATriggeredWindow",
+ "qosADppPol",
+ "bfdAInstPol",
+ "bfdAIfPol",
+ "bfdAIfP",
+ "plannerADomainTmpl",
+ "plannerAEpgDomain",
+ "vmmACapObj",
+ "vmmACapInfo",
+ "fvARsToRemoteFC",
+ "rtctrlAMatchCommFactor",
+ "rtctrlAMatchCommTerm",
+ "rtctrlAMatchCommRegexTerm",
+ "rtctrlASetDamp",
+ "rtctrlASetWeight",
+ "hvsContE",
+ "hvsUsegContE",
+ "compAPvlanP",
+ "usegAUsegEPg",
+ "fvAStAttr",
+ "fvADyAttr",
+ "mgmtAIp",
+ "faultARsToRemote",
+ "analyticsACfgSrv",
+ "infraAAccGrp",
+ "infraSpAccGrp",
+ "infraANodeP",
+ "infraPortP",
+ "infraAPathS",
+ "ipmcsnoopMcSrc",
+ "ipmcsnoopTgtIf",
+ "analyticsACluster",
+ "rtdmcAIfPol",
+ "rtdmcARtMapPol",
+ "rtdmcAExtP",
+ "rtdmcACtxPol",
+ "rtdmcARPPol",
+ "rtdmcAAutoRPPol",
+ "rtdmcABSRPPol",
+ "rtdmcAStaticRPPol",
+ "rtdmcAStaticRPEntry",
+ "rtdmcARPGrpRangePol",
+ "rtdmcARegTrPol",
+ "rtdmcAResPol",
+ "rtdmcAPatPol",
+ "rtdmcAASMPatPol",
+ "rtdmcASGRangeExpPol",
+ "rtdmcASharedRangePol",
+ "rtdmcASSMPatPol",
+ "rtdmcASSMRangePol",
+ "rtdmcABidirPatPol",
+ "pimAIfP",
+ "rtdmcARtMapEntry",
+ "rtdmcAJPFilterPol",
+ "rtdmcANbrFilterPol",
+ "rtdmcAMAFilter",
+ "rtdmcABSRFilter",
+ "rtdmcAFilterPol",
+ "fvAEPgPathAtt",
+ "fvnsAVsanInstP",
+ "ipmcAIfPol",
+ "ipmcAStRepPol",
+ "ipmcAStateLPol",
+ "ipmcARepPol",
+ "ipmcACtxPol",
+ "ipmcASSMXlateP",
+ "igmpAIfP",
+ "vmmEpgAggr",
+ "apPluginName",
+ "rtdmcAIfPolCont",
+ "fabricL2PortSecurityPol",
+ "fcAPinningP",
+ "fcAPinningLbl",
+ "fabricAONodeS",
+ "infraAONodeS",
+ "analyticsRemoteNode",
+ "analyticsTarget",
+ "fabricASubPortBlk",
+ "bgpARtTargetInstrP",
+ "hsrpAIfPol",
+ "hsrpAGroupPol",
+ "hsrpAGroupP",
+ "hsrpASecVip",
+ "hsrpAIfP",
+ "netflowARecordPol",
+ "netflowAExporterPol",
+ "netflowARsInterfaceToMonitor",
+ "netflowARsMonitorToRecord",
+ "netflowARsMonitorToExporter",
+ "netflowAMonitorPol",
+ "igmpASnoopStaticGroup",
+ "igmpASnoopAccessGroup",
+ "netflowAFabExporterPol",
+ "fabricQinqIfPol",
+ "orchsEntity",
+ "orchsElement",
+ "vnsNATReq",
+ "vnsLBReq",
+ "aclACL",
+ "aclL3ACE",
+ "apDockerName",
+ "hostprotASubj",
+ "macsecAAIfPol",
+ "macsecAIfPol",
+ "macsecAAParamPol",
+ "macsecAParamPol",
+ "macsecAAKeyChainPol",
+ "macsecAAKeyPol",
+ "macsecAKeyChainPol",
+ "macsecAKeyPol",
+ "fvAIntersiteConnP",
+ "fvAIntersiteConnPDef",
+ "fvASiteConnP",
+ "coppAProfile",
+ "coppACustomValues",
+ "infraNodeS",
+ "rtctrlASetASPath",
+ "rtctrlASetASPathASN",
+ "fvADnsAttr",
+ "dnsepgFault",
+ "dnsepgASvrGrp",
+ "dnsepgAMgmt",
+ "dnsepgASvr",
+ "dnsepgADomain",
+ "ipANexthopEpP",
+ "vmmInjectedObject",
+ "poeAIfPol",
+ "iaclAProfile",
+ "telemetryAServer",
+ "snmpATrapFwdServerP",
+ "dwdmAOptChnlIfPol",
+ "vzARuleOwner",
+ "telemetryAServerPol",
+ "telemetryARemoteServer",
+ "telemetryAFlowServers",
+ "telemetryAServerP",
+ "plannerAEpgFilter",
+ "callhomeASrc",
+ "callhomeADest",
+ "callhomeAGroup",
+ "fvAEpAnycast",
+ "tagTag",
+ "tagAnnotation",
+ "tagASelector",
+ "infraFcAccGrp",
+ "infraAFcAccBndlGrp",
+ "vsanARsVsanPathAtt",
+ "vsanARtVsanPathAtt",
+ "vzSubjectToFilter",
+ "telemetryAStreamEnable",
+ "cloudsecASaKeyP",
+ "rtdmcAInterVRFPol",
+ "rtdmcAInterVRFEntry",
+ "cloudsecAControl",
+ "adepgAResElement",
+ "adepgAElement",
+ "adepgACont",
+ "adepgAOrgUnit",
+ "adepgEntity",
+ "adepgContE",
+ "fvAIdAttr",
+ "edmObj",
+ "edmCont",
+ "edmGroupP",
+ "edmMgrP",
+ "edmEntity",
+ "edmElement",
+ "edmContE",
+ "authASvrGroup",
+ "authASvr",
+ "authBaseUsrAccP",
+ "cloudsecASaKeyPLocal",
+ "cloudsecASaKeyPRemote",
+ "cloudsecASaKeyStatus",
+ "cloudsecASaKeyStatusLocal",
+ "cloudsecASaKeyStatusRemote",
+ "cloudsecASpKeySt",
+ "cloudsecACapability",
+ "aaaRbacAnnotation",
+ "lacpAEnhancedLagPol",
+ "compAHvHealth",
+ "mldASnoopPol",
+ "fvAExtRoutes",
+ "fvAExtRoutableRemoteSitePodSubnet",
+ "fvAEpNlb",
+ "extdevSDWanASlaPol",
+ "eigrpAAuthIfP",
+ "fvAAKeyChainPol",
+ "fvAAKeyPol",
+ "fvAKeyChainPol",
+ "fvAKeyPol",
+ "fvSyntheticIp",
+ "edmACapFlags",
+ "cloudABgpPeerP",
+ "cloudABgpAsP",
+ "cloudARouterP",
+ "cloudAIntNetworkP",
+ "cloudAExtNetworkP",
+ "cloudAHostRouterPol",
+ "cloudAHostBootstrapPol",
+ "cloudAVpnGwPol",
+ "cloudAHostIfP",
+ "cloudALoopbackIfP",
+ "cloudAL3IfP",
+ "cloudAIpv4AddrP",
+ "cloudAL3TunnelIfP",
+ "cloudAIpSecTunnelIfP",
+ "cloudAOspfIfP",
+ "cloudAOspfAreaP",
+ "cloudACtxProfile",
+ "cloudACidr",
+ "cloudASubnet",
+ "cloudAAwsLogGroup",
+ "cloudAAwsFlowLogPol",
+ "cloudAProvider",
+ "cloudAAwsProvider",
+ "cloudAAEPg",
+ "cloudAEPSelector",
+ "cloudAEPSelectorDef",
+ "cloudADomP",
+ "genericsARule",
+ "ipsecAIsakmpPhase1Pol",
+ "ipsecAIsakmpPhase2Pol",
+ "resolutionARsToRemote",
+ "cloudtemplateASubnetPool",
+ "fvAACrtrn",
+ "fvAUsegAssocBD",
+ "cloudALDev",
+ "cloudAListener",
+ "cloudAPool",
+ "cloudAListenerRule",
+ "cloudARuleCondition",
+ "cloudARuleAction",
+ "cloudACertStore",
+ "cloudACertificate",
+ "arpAIfPol",
+ "compNameIdentEntity",
+ "edmAOperCont",
+ "edmAStatsCont",
+ "cloudASvcPol",
+ "hcloudATgStats",
+ "statsANWStatsObj",
+ "statsATunnel",
+ "cloudAController",
+ "cloudAApicSubnet",
+ "cloudAApicSubnetPool",
+ "cloudABaseEPg",
+ "cloudASvcEPg",
+ "statsAALbStats",
+ "mldASnoopStaticGroup",
+ "mldASnoopAccessGroup",
+ "datetimeANtpIFFKey",
+ "hcloudRouterStateOper",
+ "vmmAUplinkP",
+ "vmmAUplinkPCont",
+ "cloudAAFilter",
+ "fvASDWanPrefixTaskAggr",
+ "cloudAProvResP",
+ "bfdAMhInstPol",
+ "bfdAMhIfPol",
+ "fvAEPSelector",
+ "ptpAACfg",
+ "ptpACfg",
+ "fabricL2BDPol",
+ "rtdmcABDPol",
+ "rtdmcABDFilter",
+ "ptpAProfile",
+ "mdpADomP",
+ "mdpADomainPeeringPol",
+ "mdpAPeeringDomain",
+ "mdpANodeP",
+ "mdpAClassId",
+ "mdpATenant",
+ "mplsAExtP",
+ "mplsAIfP",
+ "mplsALabelPol",
+ "mplsANodeSidP",
+ "qosAMplsIngressRule",
+ "qosMplsMarking",
+ "qosAMplsEgressRule",
+ "cloudAGatewayRouterP",
+ "cloudATransitHubGwPol",
+ "cloudAL3IntTunnelIfP",
+ "cloudABdiId",
+ "mplsASrgbLabelPol",
+ "bfdAMhNodePol",
+ "bfdANodeP",
+ "leakASubnet",
+ "rtctrlASetNhUnchanged",
+ "mdpAService",
+ "cloudALIf",
+ "cloudAParamPol",
+ "cloudAComputePol",
+ "cloudAMgmtPol",
+ "cloudANWParams",
+ "fvRtScopeFrom",
+ "cloudACtxUnderlayP",
+ "cloudAHealthProbe",
+ "leakARouteCont",
+ "netflowAVmmExporterPol",
+ "cloudABrownfield",
+ "cloudAMapping",
+ "cloudASelectedEP",
+ "statsANlbStats",
+ "mdpAEntity",
+ "dbgANodeInst",
+ "snmpACtrlrInst",
+ "cloudAFrontendIPv4Addr",
+ "qosAUburst",
+ "telemetryAFteEvents",
+ "telemetryAFteEventsTcpFlags",
+ "telemetryAFteEventsExt",
+ "cloudACloudSvcEPg",
+ "hcloudASvcResBase",
+ "bgpADomainIdBase",
+ "fvAEpTag",
+ "bgpASiteOfOriginP",
+ "fvAEPSelectorDef",
+ "vmmCFaultInfo",
+ "synceAAIfPol",
+ "synceAIfPol",
+ "rtctrlASetRedistMultipath",
+ "cloudANextHopIp",
+ "cloudAVrfRouteLeakPol",
+ "hcloudALeakedPfx",
+ "leakAPrefix",
+ "fvARogueExceptionMac",
+ "bfdAMicroBfdP",
+ "hcloudAIntPfx",
+ "hcloudAExtPfx",
+ "cloudAVpnNetworkP",
+ "snmpUser",
+ "cloudAVirtualWanP",
+ "fvAFBRGroup",
+ "fvAFBRoute",
+ "fvAFBRMember",
+ "rtctrlASetPolicyTag",
+ "fvACtxRtSummPol",
+ "fvARtSummSubnet",
+ "fvAIntraVrfFabricImpRtctrlP",
+ "fvAFabricExpRtctrlP",
+ "cloudAVip",
+ "rtctrlAMatchAsPathRegexTerm",
+ "cloudAGcpFlowLogPol",
+ "statsAGcpNWStatsObj",
+ "cloudABfdPol",
+ "cloudABfdP",
+ "bgpACtxAddlPathPol",
+ "xcvrOpticsIfPol",
+ "xcvrOpticsFabIfPol",
+ "hostprotANamespace",
+ "fvARouteDeployP",
+ "rtdmcACSWPol",
+ "rtdmcACSWEntry",
+ "analyticsTo",
+ "analyticsFrom",
+ "dmemotltestAbsObject",
+ "bgpAsnmpBgpTraps",
+ "l3extARogueExceptionMac",
+ "l3extARogueExceptionMacGroup",
+ "vzAFiltPZEntry",
+]
diff --git a/ansible_collections/cisco/aci/plugins/module_utils/constants.py b/ansible_collections/cisco/aci/plugins/module_utils/constants.py
index 165b63431..26818ff64 100644
--- a/ansible_collections/cisco/aci/plugins/module_utils/constants.py
+++ b/ansible_collections/cisco/aci/plugins/module_utils/constants.py
@@ -97,4 +97,340 @@ EP_LOOP_PROTECTION_ACTION_MAPPING = {"bd": "bd-learn-disable", "port": "port-dis
FABRIC_POD_SELECTOR_TYPE_MAPPING = dict(all="ALL", range="range")
-TLS_MAPPING = {"tls_v1.0": "TLSv1", "tls_v1.1": "TLSv1.1", "tls_v1.2": "TLSv1.2"}
+OPFLEX_TLS_MAPPING = {"tls_v1.0": "TLSv1", "tls_v1.1": "TLSv1.1", "tls_v1.2": "TLSv1.2"}
+
+HTTP_TLS_MAPPING = {"tls_v1.0": "TLSv1", "tls_v1.1": "TLSv1.1", "tls_v1.2": "TLSv1.2", "tls_v1.3": "TLSv1.3"}
+
+ACI_ACCESS_SWITCH_POLICY_GROUP_CLASS_MAPPING = dict(
+ spine=dict(
+ class_name="infraSpineAccNodePGrp",
+ rn="infra/funcprof/spaccnodepgrp-{0}",
+ copp_pre_filter_policy=dict(class_name="infraRsIaclSpineProfile", tn_name="tnIaclSpineProfileName"),
+ bfd_ipv4_policy=dict(class_name="infraRsSpineBfdIpv4InstPol", tn_name="tnBfdIpv4InstPolName"),
+ bfd_ipv6_policy=dict(class_name="infraRsSpineBfdIpv6InstPol", tn_name="tnBfdIpv6InstPolName"),
+ copp_policy=dict(class_name="infraRsSpineCoppProfile", tn_name="tnCoppSpineProfileName"),
+ cdp_policy=dict(class_name="infraRsSpinePGrpToCdpIfPol", tn_name="tnCdpIfPolName"),
+ lldp_policy=dict(class_name="infraRsSpinePGrpToLldpIfPol", tn_name="tnLldpIfPolName"),
+ usb_configuration_policy=dict(class_name="infraRsSpineTopoctrlUsbConfigProfilePol", tn_name="tnTopoctrlUsbConfigProfilePolName"),
+ ),
+ leaf=dict(
+ class_name="infraAccNodePGrp",
+ rn="infra/funcprof/accnodepgrp-{0}",
+ copp_pre_filter_policy=dict(class_name="infraRsIaclLeafProfile", tn_name="tnIaclLeafProfileName"),
+ bfd_ipv4_policy=dict(class_name="infraRsBfdIpv4InstPol", tn_name="tnBfdIpv4InstPolName"),
+ bfd_ipv6_policy=dict(class_name="infraRsBfdIpv6InstPol", tn_name="tnBfdIpv6InstPolName"),
+ copp_policy=dict(class_name="infraRsLeafCoppProfile", tn_name="tnCoppLeafProfileName"),
+ cdp_policy=dict(class_name="infraRsLeafPGrpToCdpIfPol", tn_name="tnCdpIfPolName"),
+ lldp_policy=dict(class_name="infraRsLeafPGrpToLldpIfPol", tn_name="tnLldpIfPolName"),
+ usb_configuration_policy=dict(class_name="infraRsLeafTopoctrlUsbConfigProfilePol", tn_name="tnTopoctrlUsbConfigProfilePolName"),
+ ),
+)
+
+PIM_SETTING_CONTROL_STATE_MAPPING = {"fast": "fast-conv", "strict": "strict-rfc-compliant"}
+
+ACI_CLASS_MAPPING = dict(
+ consumer={
+ "class": "fvRsCons",
+ "rn": "rscons-",
+ "name": "tnVzBrCPName",
+ },
+ provider={
+ "class": "fvRsProv",
+ "rn": "rsprov-",
+ "name": "tnVzBrCPName",
+ },
+ taboo={
+ "class": "fvRsProtBy",
+ "rn": "rsprotBy-",
+ "name": "tnVzTabooName",
+ },
+ interface={
+ "class": "fvRsConsIf",
+ "rn": "rsconsIf-",
+ "name": "tnVzCPIfName",
+ },
+ intra_epg={
+ "class": "fvRsIntraEpg",
+ "rn": "rsintraEpg-",
+ "name": "tnVzBrCPName",
+ },
+)
+
+PROVIDER_MATCH_MAPPING = dict(
+ all="All",
+ at_least_one="AtleastOne",
+ at_most_one="AtmostOne",
+ none="None",
+)
+
+CONTRACT_LABEL_MAPPING = dict(
+ consumer="vzConsLbl",
+ provider="vzProvLbl",
+)
+
+SUBJ_LABEL_MAPPING = dict(
+ consumer="vzConsSubjLbl",
+ provider="vzProvSubjLbl",
+)
+
+SUBJ_LABEL_RN = dict(
+ consumer="conssubjlbl-",
+ provider="provsubjlbl-",
+)
+
+MATCH_ACTION_RULE_SET_METRIC_TYPE_MAPPING = {"ospf_type_1": "ospf-type1", "ospf_type_2": "ospf-type2", "": ""}
+
+MATCH_EIGRP_INTERFACE_POLICY_DELAY_UNIT_MAPPING = dict(picoseconds="pico", tens_of_microseconds="tens-of-micro")
+
+MATCH_EIGRP_INTERFACE_POLICY_CONTROL_STATE_MAPPING = dict(bfd="bfd", nexthop_self="nh-self", passive="passive", split_horizon="split-horizon")
+
+MATCH_TARGET_COS_MAPPING = {
+ "background": "0",
+ "best_effort": "1",
+ "excellent_effort": "2",
+ "critical_applications": "3",
+ "video": "4",
+ "voice": "5",
+ "internetwork_control": "6",
+ "network_control": "7",
+ "unspecified": "unspecified",
+}
+
+MATCH_PIM_INTERFACE_POLICY_CONTROL_STATE_MAPPING = dict(multicast_domain_boundary="border", strict_rfc_compliant="strict-rfc-compliant", passive="passive")
+
+MATCH_PIM_INTERFACE_POLICY_AUTHENTICATION_TYPE_MAPPING = dict(none="none", md5_hmac="ah-md5")
+
+MATCH_COLLECT_NETFLOW_RECORD_MAPPING = dict(
+ bytes_counter="count-bytes",
+ pkts_counter="count-pkts",
+ pkt_disposition="pkt-disp",
+ sampler_id="sampler-id",
+ source_interface="src-intf",
+ tcp_flags="tcp-flags",
+ first_pkt_timestamp="ts-first",
+ recent_pkt_timestamp="ts-recent",
+)
+
+MATCH_MATCH_NETFLOW_RECORD_MAPPING = dict(
+ destination_ipv4_v6="dst-ip",
+ destination_ipv4="dst-ipv4",
+ destination_ipv6="dst-ipv6",
+ destination_mac="dst-mac",
+ destination_port="dst-port",
+ ethertype="ethertype",
+ ip_protocol="proto",
+ source_ipv4_v6="src-ip",
+ source_ipv4="src-ipv4",
+ source_ipv6="src-ipv6",
+ source_mac="src-mac",
+ source_port="src-port",
+ ip_tos="tos",
+ unspecified="unspecified",
+ vlan="vlan",
+)
+
+MATCH_SOURCE_IP_TYPE_NETFLOW_EXPORTER_MAPPING = dict(
+ custom_source_ip="custom-src-ip",
+ inband_management_ip="inband-mgmt-ip",
+ out_of_band_management_ip="oob-mgmt-ip",
+ ptep="ptep",
+)
+
+ECC_CURVE = {"P256": "prime256v1", "P384": "secp384r1", "P521": "secp521r1", "none": "none"}
+
+THROTTLE_UNIT = dict(requests_per_second="r/s", requests_per_minute="r/m")
+
+SSH_CIPHERS = dict(
+ aes128_ctr="aes128-ctr",
+ aes192_ctr="aes192-ctr",
+ aes256_ctr="aes256-ctr",
+ aes128_gcm="aes128-gcm@openssh.com",
+ aes256_gcm="aes256-gcm@openssh.com",
+ chacha20="chacha20-poly1305@openssh.com",
+)
+
+SSH_MACS = dict(
+ sha1="hmac-sha1",
+ sha2_256="hmac-sha2-256",
+ sha2_512="hmac-sha2-512",
+ sha2_256_etm="hmac-sha2-256-etm@openssh.com",
+ sha2_512_etm="hmac-sha2-512-etm@openssh.com",
+)
+
+KEX_ALGORITHMS = dict(
+ dh_sha1="diffie-hellman-group14-sha1",
+ dh_sha256="diffie-hellman-group14-sha256",
+ dh_sha512="diffie-hellman-group16-sha512",
+ curve_sha256="curve25519-sha256",
+ curve_sha256_libssh="curve25519-sha256@libssh.org",
+ ecdh_256="ecdh-sha2-nistp256",
+ ecdh_384="ecdh-sha2-nistp384",
+ ecdh_521="ecdh-sha2-nistp521",
+)
+
+USEG_ATTRIBUTE_MAPPING = dict(
+ ip=dict(attribute_type="ip", attribute_class="fvIpAttr", rn_format="ipattr-{0}"),
+ mac=dict(attribute_type="mac", attribute_class="fvMacAttr", rn_format="macattr-{0}"),
+ dns=dict(attribute_type="dns", attribute_class="fvDnsAttr", rn_format="dnsattr-{0}"),
+ ad_group=dict(attribute_type="ad", attribute_class="fvIdGroupAttr", rn_format="idgattr-[{0}]"),
+ vm_custom_attr=dict(attribute_type="custom-label", attribute_class="fvVmAttr", rn_format="vmattr-{0}"),
+ vm_vmm_domain=dict(attribute_type="domain", attribute_class="fvVmAttr", rn_format="vmattr-{0}"),
+ vm_operating_system=dict(attribute_type="guest-os", attribute_class="fvVmAttr", rn_format="vmattr-{0}"),
+ vm_hypervisor_id=dict(attribute_type="hv", attribute_class="fvVmAttr", rn_format="vmattr-{0}"),
+ vm_datacenter=dict(attribute_type="rootContName", attribute_class="fvVmAttr", rn_format="vmattr-{0}"),
+ vm_id=dict(attribute_type="vm", attribute_class="fvVmAttr", rn_format="vmattr-{0}"),
+ vm_name=dict(attribute_type="vm-name", attribute_class="fvVmAttr", rn_format="vmattr-{0}"),
+ vm_folder=dict(attribute_type="vm-folder", attribute_class="fvVmAttr", rn_format="vmattr-{0}"),
+ vm_folder_path=dict(attribute_type="vmfolder-path", attribute_class="fvVmAttr", rn_format="vmattr-{0}"),
+ vm_vnic=dict(attribute_type="vnic", attribute_class="fvVmAttr", rn_format="vmattr-{0}"),
+ vm_tag=dict(attribute_type="tag", attribute_class="fvVmAttr", rn_format="vmattr-{0}"),
+)
+
+OPERATOR_MAPPING = dict(equals="equals", contains="contains", starts_with="startsWith", ends_with="endsWith")
+
+MATCH_STORM_CONTROL_POLICY_TYPE_MAPPING = dict(all_types="Invalid", unicast_broadcast_multicast="Valid")
+
+POLICY_LABEL_COLORS = [
+ "alice_blue",
+ "antique_white",
+ "aqua",
+ "aquamarine",
+ "azure",
+ "beige",
+ "bisque",
+ "black",
+ "blanched_almond",
+ "blue",
+ "blue_violet",
+ "brown",
+ "burlywood",
+ "cadet_blue",
+ "chartreuse",
+ "chocolate",
+ "coral",
+ "cornflower_blue",
+ "cornsilk",
+ "crimson",
+ "cyan",
+ "dark_blue",
+ "dark_cyan",
+ "dark_goldenrod",
+ "dark_gray",
+ "dark_green",
+ "dark_khaki",
+ "dark_magenta",
+ "dark_olive_green",
+ "dark_orange",
+ "dark_orchid",
+ "dark_red",
+ "dark_salmon",
+ "dark_sea_green",
+ "dark_slate_blue",
+ "dark_slate_gray",
+ "dark_turquoise",
+ "dark_violet",
+ "deep_pink",
+ "deep_sky_blue",
+ "dim_gray",
+ "dodger_blue",
+ "fire_brick",
+ "floral_white",
+ "forest_green",
+ "fuchsia",
+ "gainsboro",
+ "ghost_white",
+ "gold",
+ "goldenrod",
+ "gray",
+ "green",
+ "green_yellow",
+ "honeydew",
+ "hot_pink",
+ "indian_red",
+ "indigo",
+ "ivory",
+ "khaki",
+ "lavender",
+ "lavender_blush",
+ "lawn_green",
+ "lemon_chiffon",
+ "light_blue",
+ "light_coral",
+ "light_cyan",
+ "light_goldenrod_yellow",
+ "light_gray",
+ "light_green",
+ "light_pink",
+ "light_salmon",
+ "light_sea_green",
+ "light_sky_blue",
+ "light_slate_gray",
+ "light_steel_blue",
+ "light_yellow",
+ "lime",
+ "lime_green",
+ "linen",
+ "magenta",
+ "maroon",
+ "medium_aquamarine",
+ "medium_blue",
+ "medium_orchid",
+ "medium_purple",
+ "medium_sea_green",
+ "medium_slate_blue",
+ "medium_spring_green",
+ "medium_turquoise",
+ "medium_violet_red",
+ "midnight_blue",
+ "mint_cream",
+ "misty_rose",
+ "moccasin",
+ "navajo_white",
+ "navy",
+ "old_lace",
+ "olive",
+ "olive_drab",
+ "orange",
+ "orange_red",
+ "orchid",
+ "pale_goldenrod",
+ "pale_green",
+ "pale_turquoise",
+ "pale_violet_red",
+ "papaya_whip",
+ "peachpuff",
+ "peru",
+ "pink",
+ "plum",
+ "powder_blue",
+ "purple",
+ "red",
+ "rosy_brown",
+ "royal_blue",
+ "saddle_brown",
+ "salmon",
+ "sandy_brown",
+ "sea_green",
+ "seashell",
+ "sienna",
+ "silver",
+ "sky_blue",
+ "slate_blue",
+ "slate_gray",
+ "snow",
+ "spring_green",
+ "steel_blue",
+ "tan",
+ "teal",
+ "thistle",
+ "tomato",
+ "turquoise",
+ "violet",
+ "wheat",
+ "white",
+ "white_smoke",
+ "yellow",
+ "yellow_green",
+]
+
+MATCH_ACCESS_POLICIES_SELECTOR_TYPE = dict(range="range", all="ALL")
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_aaa_certificate_authority.py b/ansible_collections/cisco/aci/plugins/modules/aci_aaa_certificate_authority.py
new file mode 100644
index 000000000..673515185
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_aaa_certificate_authority.py
@@ -0,0 +1,290 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2024, Akini Ross (@akinross) <akinross@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": "certified"}
+
+DOCUMENTATION = r"""
+---
+module: aci_aaa_certificate_authority
+short_description: Manage AAA Certificate Authorities (pki:TP)
+description:
+- Manage AAA Certificate Authorities on Cisco ACI fabrics.
+options:
+ name:
+ description:
+ - The name of the Certificate Authority.
+ type: str
+ aliases: [ certificate_authority, cert_authority, cert_authority_name, certificate_authority_name ]
+ cloud_tenant:
+ description:
+ - The name of the cloud tenant.
+ - This attribute is only applicable for Cloud APIC.
+ type: str
+ aliases: [ tenant, tenant_name ]
+ description:
+ description:
+ - The description of the Certificate Authority.
+ type: str
+ aliases: [ descr ]
+ certificate_chain:
+ description:
+ - The PEM-encoded chain of trust from the trustpoint to a trusted root authority.
+ type: str
+ aliases: [ cert_data, certificate_data, cert, certificate ]
+ 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(cloud_tenant) used must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant) module can be used for this.
+seealso:
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(pki:TP).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Akini Ross (@akinross)
+"""
+
+EXAMPLES = r"""
+- name: Create a Certificate Authority
+ cisco.aci.aci_aaa_certificate_authority:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ name: example_authority
+ certificate_chain: '{{ lookup("file", "pki/example_authority.crt") }}'
+ state: present
+ delegate_to: localhost
+
+- name: Query a Certificate Authority
+ cisco.aci.aci_aaa_certificate_authority:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ name: example_authority
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all Certificate Authorities
+ cisco.aci.aci_aaa_certificate_authority:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Delete a Certificate Authority
+ cisco.aci.aci_aaa_certificate_authority:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ name: example_authority
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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(
+ name=dict(
+ type="str", aliases=["certificate_authority", "cert_authority", "cert_authority_name", "certificate_authority_name"]
+ ), # Not required for querying all objects
+ cloud_tenant=dict(type="str", aliases=["tenant", "tenant_name"]),
+ description=dict(type="str", aliases=["descr"]),
+ certificate_chain=dict(type="str", aliases=["cert_data", "certificate_data", "cert", "certificate"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ name_alias=dict(type="str"),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["name"]],
+ ["state", "present", ["name", "certificate_chain"]],
+ ],
+ )
+
+ name = module.params.get("name")
+ cloud_tenant = module.params.get("cloud_tenant")
+ description = module.params.get("description")
+ certificate_chain = module.params.get("certificate_chain")
+ state = module.params.get("state")
+ name_alias = module.params.get("name_alias")
+
+ aci = ACIModule(module)
+ aci_class = "pkiTP"
+ parent_class = "cloudCertStore" if cloud_tenant else "pkiEp"
+ parent_rn = "tn-{0}/certstore".format(cloud_tenant) if cloud_tenant else "userext/pkiext"
+
+ aci.construct_url(
+ root_class=dict(
+ aci_class=parent_class,
+ aci_rn=parent_rn,
+ ),
+ subclass_1=dict(
+ aci_class=aci_class,
+ aci_rn="tp-{0}".format(name),
+ module_object=name,
+ target_filter={"name": name},
+ ),
+ )
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class=aci_class,
+ class_config=dict(
+ name=name,
+ descr=description,
+ certChain=certificate_chain,
+ nameAlias=name_alias,
+ ),
+ )
+
+ aci.get_diff(aci_class=aci_class)
+
+ # Only wrap the payload in parent class if cloud_tenant is set to avoid apic error
+ aci.post_config(parent_class=parent_class if cloud_tenant else None)
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_aaa_key_ring.py b/ansible_collections/cisco/aci/plugins/modules/aci_aaa_key_ring.py
new file mode 100644
index 000000000..2aa2649c7
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_aaa_key_ring.py
@@ -0,0 +1,339 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2024, Akini Ross (@akinross) <akinross@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": "certified"}
+
+DOCUMENTATION = r"""
+---
+module: aci_aaa_key_ring
+short_description: Manage AAA Key Rings (pki:KeyRing)
+description:
+- Manage AAA Key Rings on Cisco ACI fabrics.
+options:
+ name:
+ description:
+ - The name of the Key Ring.
+ type: str
+ aliases: [ key_ring, key_ring_name ]
+ cloud_tenant:
+ description:
+ - The name of the cloud tenant.
+ - This attribute is only applicable for Cloud APIC.
+ type: str
+ aliases: [ tenant, tenant_name ]
+ description:
+ description:
+ - The description of the Key Ring.
+ type: str
+ aliases: [ descr ]
+ certificate:
+ description:
+ - The certificate of the Key Ring.
+ - The certificate contains a public key and signed information for verifying the identity.
+ type: str
+ aliases: [ cert_data, certificate_data, cert ]
+ modulus:
+ description:
+ - The modulus is the length of the key in bits.
+ type: int
+ choices: [ 512, 1024, 1536, 2048 ]
+ certificate_authority:
+ description:
+ - The name of the Certificate Authority.
+ type: str
+ aliases: [ cert_authority, cert_authority_name, certificate_authority_name ]
+ key:
+ description:
+ - The private key for the certificate.
+ type: str
+ key_type:
+ description:
+ - The type of the private key.
+ - This attribute is only configurable in ACI versions 6.0(2h) and above.
+ type: str
+ choices: [ rsa, ecc ]
+ ecc_curve:
+ description:
+ - The curve of the private key.
+ - This attribute requires O(key_type=ecc).
+ - This attribute is only configurable in ACI versions 6.0(2h) and above.
+ type: str
+ choices: [ P256, P384, P521, none ]
+ aliases: [ curve ]
+ 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(cloud_tenant) used must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant) module can be used for this.
+seealso:
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(pki:KeyRing).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Akini Ross (@akinross)
+"""
+
+EXAMPLES = r"""
+- name: Create a Key Ring
+ cisco.aci.aci_aaa_key_ring:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ name: example_key_ring
+ certificate: '{{ lookup("file", "pki/example_certificate.crt") }}'
+ modulus: 2048
+ certificate_authority: example_certificate_authority
+ key: '{{ lookup("file", "pki/example_key.key") }}'
+ state: present
+ delegate_to: localhost
+
+- name: Query a Key Ring
+ cisco.aci.aci_aaa_key_ring:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ name: example_key_ring
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all Certificate Authorities
+ cisco.aci.aci_aaa_key_ring:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Delete a Key Ring
+ cisco.aci.aci_aaa_key_ring:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ name: example_key_ring
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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
+from ansible_collections.cisco.aci.plugins.module_utils.constants import ECC_CURVE
+
+
+def main():
+ argument_spec = aci_argument_spec()
+ argument_spec.update(aci_annotation_spec())
+ argument_spec.update(aci_owner_spec())
+ argument_spec.update(
+ name=dict(type="str", aliases=["key_ring", "key_ring_name"]), # Not required for querying all objects
+ cloud_tenant=dict(type="str", aliases=["tenant_name", "tenant"]),
+ description=dict(type="str", aliases=["descr"]),
+ certificate=dict(type="str", aliases=["cert_data", "certificate_data", "cert"]),
+ modulus=dict(type="int", choices=[512, 1024, 1536, 2048]),
+ certificate_authority=dict(type="str", aliases=["cert_authority", "cert_authority_name", "certificate_authority_name"]),
+ key=dict(type="str", no_log=True),
+ key_type=dict(type="str", choices=["rsa", "ecc"]),
+ ecc_curve=dict(type="str", choices=["P256", "P384", "P521", "none"], aliases=["curve"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ name_alias=dict(type="str"),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["name"]],
+ ["state", "present", ["name"]],
+ ],
+ )
+
+ name = module.params.get("name")
+ cloud_tenant = module.params.get("cloud_tenant")
+ description = module.params.get("description")
+ certificate = module.params.get("certificate")
+ modulus = "mod{0}".format(module.params.get("modulus")) if module.params.get("modulus") else None
+ certificate_authority = module.params.get("certificate_authority")
+ key = module.params.get("key")
+ key_type = module.params.get("key_type")
+ ecc_curve = ECC_CURVE[module.params.get("ecc_curve")] if module.params.get("ecc_curve") else None
+ state = module.params.get("state")
+ name_alias = module.params.get("name_alias")
+
+ aci = ACIModule(module)
+ aci_class = "pkiKeyRing"
+ parent_class = "cloudCertStore" if cloud_tenant else "pkiEp"
+ parent_rn = "tn-{0}/certstore".format(cloud_tenant) if cloud_tenant else "userext/pkiext"
+
+ aci.construct_url(
+ root_class=dict(
+ aci_class=parent_class,
+ aci_rn=parent_rn,
+ ),
+ subclass_1=dict(
+ aci_class=aci_class,
+ aci_rn="keyring-{0}".format(name),
+ module_object=name,
+ target_filter={"name": name},
+ ),
+ )
+ aci.get_existing()
+
+ if state == "present":
+ class_config = dict(
+ name=name,
+ descr=description,
+ cert=certificate,
+ modulus=modulus,
+ tp=certificate_authority,
+ nameAlias=name_alias,
+ key=key,
+ )
+
+ if key_type:
+ class_config["keyType"] = key_type.upper()
+
+ if ecc_curve:
+ class_config["eccCurve"] = ecc_curve
+
+ aci.payload(aci_class=aci_class, class_config=class_config)
+
+ aci.get_diff(aci_class=aci_class, required_properties=dict(name=name) if cloud_tenant else None)
+
+ # Only wrap the payload in parent class if cloud_tenant is set to avoid apic error
+ aci.post_config(parent_class=parent_class if cloud_tenant else None)
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_aaa_security_default_settings.py b/ansible_collections/cisco/aci/plugins/modules/aci_aaa_security_default_settings.py
new file mode 100644
index 000000000..4ba18fded
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_aaa_security_default_settings.py
@@ -0,0 +1,531 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2024, Akini Ross (@akinross) <akinross@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": "certified"}
+
+DOCUMENTATION = r"""
+---
+module: aci_aaa_security_default_settings
+short_description: Manage AAA Key Rings (pki:Ep)
+description:
+- Manage AAA Key Rings on Cisco ACI fabrics.
+options:
+ password_strength_check:
+ description:
+ - Enable password strength check.
+ - Use C(true) to enable and C(false) to disable.
+ - The APIC defaults to C(true) when unset during creation.
+ type: bool
+ password_strength_profile:
+ description:
+ - The password strength profile (aaa:PwdStrengthProfile).
+ type: dict
+ suboptions:
+ enable:
+ description:
+ - Enable or disable password strength profile.
+ - Use C(true) to enable and C(false) to disable.
+ type: bool
+ required: true
+ type:
+ description:
+ - The type of the password strength profile.
+ - The APIC defaults to C(any_three) when unset during creation.
+ type: str
+ choices: [ custom, any_three ]
+ min_length:
+ description:
+ - The minimum length of the password.
+ - The APIC defaults to C(8) when unset during creation.
+ type: int
+ aliases: [ minimum_length, min ]
+ max_length:
+ description:
+ - The maximum length of the password.
+ - The APIC defaults to C(64) when unset during creation.
+ type: int
+ aliases: [ maximum_length, max ]
+ class_flags:
+ description:
+ - The class flags of the password strength profile.
+ - At least 3 class flags must be specified.
+ - This attribute is only applicable when type is set to O(password_strength_profile.type=custom).
+ - The APIC defaults to C(digits,lowercase,uppercase) when unset during creation.
+ type: list
+ elements: str
+ choices: [ digits, lowercase, specialchars, uppercase ]
+ aliases: [ flags ]
+ password_change:
+ description:
+ - The password change interval (aaa:PwdProfile).
+ type: dict
+ suboptions:
+ enable:
+ description:
+ - Enforce password change interval.
+ - Use C(true) to enable and C(false) to disable.
+ - The APIC defaults to C(true) when unset during creation.
+ type: bool
+ interval:
+ description:
+ - The password change interval in hours.
+ - The APIC defaults to C(48) when unset during creation.
+ type: int
+ allowed_changes:
+ description:
+ - The number of changes allowed within the change interval.
+ - The APIC defaults to C(2) when unset during creation.
+ type: int
+ minimum_period:
+ description:
+ - The minimum period between password changes in hours.
+ - The APIC defaults to C(24) when unset during creation.
+ type: int
+ aliases: [ minimum_period_between_password_changes, min_period ]
+ history_storage_amount:
+ description:
+ - The number of recent user passwords to store.
+ - The APIC defaults to C(5) when unset during creation.
+ type: int
+ aliases: [ history, amount ]
+ lockout:
+ description:
+ - Lockout behaviour after multiple failed login attempts (aaa:BlockLoginProfile).
+ type: dict
+ suboptions:
+ enable:
+ description:
+ - Enable lockout behaviour.
+ - Use C(true) to enable and C(false) to disable.
+ - The APIC defaults to C(false) when unset during creation.
+ type: bool
+ max_attempts:
+ description:
+ - The maximum number of failed attempts before user is locked out.
+ - The APIC defaults to C(5) when unset during creation.
+ type: int
+ aliases: [ max_failed_attempts, failed_attempts, attempts ]
+ window:
+ description:
+ - The time period in which consecutive attempts were failed in minutes.
+ - The APIC defaults to C(5) when unset during creation.
+ type: int
+ aliases: [ max_failed_attempts_window, failed_attempts_window ]
+ duration:
+ description:
+ - The duration of lockout in minutes.
+ - The APIC defaults to C(60) when unset during creation.
+ type: int
+ web_token:
+ description:
+ - The web token related configuration (pki:WebTokenData).
+ type: dict
+ suboptions:
+ timeout:
+ description:
+ - The web token timeout in seconds.
+ - The APIC defaults to C(600) when unset during creation.
+ type: int
+ idle_timeout:
+ description:
+ - The web/console (SSH/Telnet) session idle timeout in seconds.
+ - The APIC defaults to C(1200) when unset during creation.
+ type: int
+ aliases: [ session_idle_timeout ]
+ validity_period:
+ description:
+ - The maximum validity period in hours.
+ - The APIC defaults to C(24) when unset during creation.
+ type: int
+ aliases: [ maximum_validity_period ]
+ refresh:
+ description:
+ - Include refresh in session records.
+ - Use C(true) to include and C(false) to exclude.
+ - The APIC defaults to C(false) when unset during creation.
+ type: bool
+ 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: [ 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
+
+seealso:
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(pki:Ep).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Akini Ross (@akinross)
+"""
+
+EXAMPLES = r"""
+- name: Set AAA Security Default Settings
+ cisco.aci.aci_aaa_security_default_settings:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ password_strength_check: true
+ password_strength_profile:
+ enable: true
+ type: custom
+ min_length: 10
+ max_length: 60
+ class_flags:
+ - digits
+ - lowercase
+ - specialchars
+ - uppercase
+ password_change:
+ enable: true
+ interval: 49
+ allowed_changes: 6
+ minimum_period_between_password_changes: 25
+ history_storage_amount: 6
+ lockout:
+ enable: true
+ max_attempts: 6
+ window: 6
+ duration: 61
+ web_token:
+ timeout: 601
+ idle_timeout: 1201
+ validity_period: 23
+ refresh: true
+ state: present
+ delegate_to: localhost
+
+- name: Set AAA Security Default Settings to Default Values
+ cisco.aci.aci_aaa_security_default_settings:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ password_strength_check: true
+ password_strength_profile:
+ enable: false
+ password_change:
+ enable: true
+ interval: 48
+ allowed_changes: 2
+ minimum_period_between_password_changes: 24
+ history_storage_amount: 5
+ lockout:
+ enable: false
+ max_attempts: 5
+ window: 5
+ duration: 60
+ web_token:
+ timeout: 600
+ idle_timeout: 1200
+ validity_period: 24
+ refresh: false
+ state: present
+ delegate_to: localhost
+
+- name: Query AAA Security Default Settings
+ cisco.aci.aci_aaa_security_default_settings:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+ register: query_result
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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(
+ password_strength_check=dict(type="bool", no_log=False),
+ password_strength_profile=dict(
+ type="dict",
+ no_log=False,
+ options=dict(
+ enable=dict(type="bool", required=True),
+ type=dict(type="str", choices=["custom", "any_three"]),
+ min_length=dict(type="int", aliases=["minimum_length", "min"]),
+ max_length=dict(type="int", aliases=["maximum_length", "max"]),
+ class_flags=dict(type="list", elements="str", choices=["digits", "lowercase", "specialchars", "uppercase"], aliases=["flags"]),
+ ),
+ ),
+ password_change=dict(
+ type="dict",
+ no_log=False,
+ options=dict(
+ enable=dict(type="bool"),
+ interval=dict(type="int"),
+ allowed_changes=dict(type="int"),
+ minimum_period=dict(type="int", aliases=["minimum_period_between_password_changes", "min_period"]),
+ history_storage_amount=dict(type="int", aliases=["history", "amount"]),
+ ),
+ ),
+ lockout=dict(
+ type="dict",
+ options=dict(
+ enable=dict(type="bool"),
+ max_attempts=dict(type="int", aliases=["max_failed_attempts", "failed_attempts", "attempts"]),
+ window=dict(type="int", aliases=["max_failed_attempts_window", "failed_attempts_window"]),
+ duration=dict(type="int"),
+ ),
+ ),
+ web_token=dict(
+ type="dict",
+ no_log=False,
+ options=dict(
+ timeout=dict(type="int"),
+ idle_timeout=dict(type="int", aliases=["session_idle_timeout"]),
+ validity_period=dict(type="int", aliases=["maximum_validity_period"]),
+ refresh=dict(type="bool"),
+ ),
+ ),
+ state=dict(type="str", default="present", choices=["present", "query"]),
+ name_alias=dict(type="str"),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ )
+ aci = ACIModule(module)
+
+ password_strength_check = aci.boolean(module.params.get("password_strength_check"))
+ password_strength_profile = module.params.get("password_strength_profile")
+ password_change = module.params.get("password_change")
+ lockout = module.params.get("lockout")
+ web_token = module.params.get("web_token")
+ state = module.params.get("state")
+ name_alias = module.params.get("name_alias")
+
+ aci_class = "aaaUserEp"
+ child_classes = ["aaaPwdStrengthProfile", "aaaPwdProfile", "aaaBlockLoginProfile", "pkiWebTokenData"]
+
+ aci.construct_url(
+ root_class=dict(
+ aci_class=aci_class,
+ aci_rn="userext",
+ ),
+ child_classes=child_classes,
+ )
+ aci.get_existing()
+
+ if state == "present":
+ child_configs = []
+
+ class_config = dict(
+ pwdStrengthCheck=password_strength_check,
+ nameAlias=name_alias,
+ )
+
+ if password_strength_profile:
+ if password_strength_profile.get("enable"):
+ child_configs.append(
+ dict(
+ aaaPwdStrengthProfile=dict(
+ attributes=dict(
+ pwdStrengthTestType=password_strength_profile.get("type"),
+ pwdMinLength=password_strength_profile.get("min_length"),
+ pwdMaxLength=password_strength_profile.get("max_length"),
+ pwdClassFlags=",".join(sorted(password_strength_profile.get("class_flags"))),
+ ),
+ ),
+ ),
+ )
+ # Delete existing aaaPwdStrengthProfile if enable is set to false and it exists
+ # This is done for setting the correct output for changed state
+ elif len(aci.existing) > 0 and len(aci.existing[0].get("aaaUserEp", {}).get("children", {})) > 3:
+ for child in aci.existing[0].get("aaaUserEp", {}).get("children", {}):
+ if "aaaPwdStrengthProfile" in child.keys():
+ child_configs.append(dict(aaaPwdStrengthProfile=dict(attributes=dict(status="deleted"))))
+ break
+
+ if password_change:
+ child_configs.append(
+ dict(
+ aaaPwdProfile=dict(
+ attributes=dict(
+ changeDuringInterval=aci.boolean(password_change.get("enable"), "enable", "disable"),
+ changeInterval=password_change.get("interval"),
+ changeCount=password_change.get("allowed_changes"),
+ noChangeInterval=password_change.get("minimum_period"),
+ historyCount=password_change.get("history_storage_amount"),
+ ),
+ ),
+ ),
+ )
+
+ if lockout:
+ child_configs.append(
+ dict(
+ aaaBlockLoginProfile=dict(
+ attributes=dict(
+ enableLoginBlock=aci.boolean(lockout.get("enable"), "enable", "disable"),
+ maxFailedAttempts=lockout.get("max_attempts"),
+ maxFailedAttemptsWindow=lockout.get("window"),
+ blockDuration=lockout.get("duration"),
+ ),
+ ),
+ ),
+ )
+
+ if web_token:
+ child_configs.append(
+ dict(
+ pkiEp=dict(
+ attributes=dict(descr=""),
+ children=[
+ dict(
+ pkiWebTokenData=dict(
+ attributes=dict(
+ webtokenTimeoutSeconds=web_token.get("timeout"),
+ uiIdleTimeoutSeconds=web_token.get("idle_timeout"),
+ maximumValidityPeriod=web_token.get("validity_period"),
+ sessionRecordFlags="login,logout,refresh" if web_token.get("refresh") else "login,logout",
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ )
+
+ aci.payload(
+ aci_class=aci_class,
+ class_config=class_config,
+ child_configs=child_configs,
+ )
+
+ aci.get_diff(aci_class=aci_class)
+
+ aci.post_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_aaa_ssh_auth.py b/ansible_collections/cisco/aci/plugins/modules/aci_aaa_ssh_auth.py
index df4732f28..e1eb4b4d7 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_aaa_ssh_auth.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_aaa_ssh_auth.py
@@ -13,7 +13,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_aaa_ssh_auth
-short_description: Manage AAA SSH auth (aaaSshAuth) objects.
+short_description: Manage AAA SSH auth objects (aaa:SshAuth)
description:
- Manage AAA SSH Auth key configuration on Cisco ACI fabrics.
options:
@@ -47,7 +47,7 @@ notes:
The M(cisco.aci.aci_aaa_user) modules can be used for this.
seealso:
- name: APIC Management Information Model reference
- description: More information about the internal APIC class B(aaaSshAuth).
+ description: More information about the internal APIC class B(aaa:SshAuth).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Tim Cragg (@timcragg)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_access_port_block_to_access_port.py b/ansible_collections/cisco/aci/plugins/modules/aci_access_port_block_to_access_port.py
index 646423290..0067d0463 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_access_port_block_to_access_port.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_access_port_block_to_access_port.py
@@ -4,6 +4,7 @@
# Copyright: (c) 2018, Simon Metzger <smnmtzgr@gmail.com>
# Copyright: (c) 2020, Shreyas Srish <ssrish@cisco.com>
# Copyright: (c) 2020, Zak Lantz (@manofcolombia) <zakodewald@gmail.com>
+# Copyright: (c) 2024, Gaspard Micol (@gmicol) <gmicol@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
@@ -15,55 +16,60 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_access_port_block_to_access_port
-short_description: Manage port blocks of Fabric interface policy leaf profile interface selectors (infra:HPortS, infra:PortBlk)
+short_description: Manage Port blocks of Fabric Access Leaf/Spine Interface Port Selectors (infra:PortBlk)
description:
-- Manage port blocks of Fabric interface policy leaf profile interface selectors on Cisco ACI fabrics.
+- Manage Port blocks of Fabric Access Interface Leaf/Spine Port Selectors on Cisco ACI fabrics.
options:
interface_profile:
description:
- - The name of the Fabric access policy leaf interface profile.
+ - The name of the Fabric access policy leaf/spine interface profile.
type: str
- aliases: [ leaf_interface_profile_name, leaf_interface_profile, interface_profile_name ]
+ aliases:
+ - leaf_interface_profile_name
+ - leaf_interface_profile
+ - interface_profile_name
+ - spine_interface_profile
+ - spine_interface_profile_name
access_port_selector:
description:
- - The name of the Fabric access policy leaf interface profile access port selector.
+ - The name of the Fabric access policy leaf/spine interface port selector.
type: str
aliases: [ name, access_port_selector_name ]
port_blk:
description:
- - The name of the Fabric access policy leaf interface profile access port block.
+ - The name of the Fabric access policy interface port block.
type: str
aliases: [ leaf_port_blk_name, leaf_port_blk ]
port_blk_description:
description:
- - The description to assign to the C(leaf_port_blk).
+ - The description for the port block.
type: str
aliases: [ leaf_port_blk_description ]
from_port:
description:
- - The beginning (from-range) of the port range block for the leaf access port block.
+ - The beginning (from-range) of the port range block for the port block.
type: str
aliases: [ from, fromPort, from_port_range ]
to_port:
description:
- - The end (to-range) of the port range block for the leaf access port block.
+ - The end (to-range) of the port range block for the port block.
type: str
aliases: [ to, toPort, to_port_range ]
from_card:
description:
- - The beginning (from-range) of the card range block for the leaf access port block.
+ - The beginning (from-range) of the card range block for the port block.
type: str
aliases: [ from_card_range ]
to_card:
description:
- - The end (to-range) of the card range block for the leaf access port block.
+ - The end (to-range) of the card range block for the port block.
type: str
aliases: [ to_card_range ]
type:
description:
- - The type of access port block to be created under respective access port.
+ - The type of port block to be created under respective access port.
type: str
- choices: [ fex, leaf ]
+ choices: [ fex, leaf, spine ]
default: leaf
state:
description:
@@ -77,18 +83,27 @@ extends_documentation_fragment:
- cisco.aci.annotation
notes:
-- The C(interface_profile) and C(access_port_selector) must exist before using this module in your playbook.
+- If Adding a port block on an access leaf interface port selector of I(type) C(leaf),
+ The I(interface_profile) and I(access_port_selector) must exist before using this module in your playbook.
The M(cisco.aci.aci_interface_policy_leaf_profile) and M(cisco.aci.aci_access_port_to_interface_policy_leaf_profile) modules can be used for this.
+- If Adding a port block on an access interface port selector of C(type) C(spine),
+ The I(interface_profile) and I(access_port_selector) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_access_spine_interface_profile) and M(cisco.aci.aci_access_spine_interface_selector) modules can be used for this.
seealso:
+- module: cisco.aci.aci_interface_policy_leaf_profile
+- module: cisco.aci.aci_access_port_to_interface_policy_leaf_profile
+- module: cisco.aci.aci_access_spine_interface_profile
+- module: cisco.aci.aci_access_spine_interface_selector
- name: APIC Management Information Model reference
- description: More information about the internal APIC classes B(infra:HPortS) and B(infra:PortBlk).
+ description: More information about the internal APIC classes B(infra:PortBlk).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Simon Metzger (@smnmtzgr)
+- Gaspard Micol (@gmicol)
"""
EXAMPLES = r"""
-- name: Associate an access port block (single port) to an interface selector
+- name: Associate a Fabric access policy interface port block (single port) to an interface selector
cisco.aci.aci_access_port_block_to_access_port:
host: apic
username: admin
@@ -101,7 +116,7 @@ EXAMPLES = r"""
state: present
delegate_to: localhost
-- name: Associate an access port block (port range) to an interface selector
+- name: Associate a Fabric access policy interface port block (port range) to an interface selector
cisco.aci.aci_access_port_block_to_access_port:
host: apic
username: admin
@@ -114,7 +129,7 @@ EXAMPLES = r"""
state: present
delegate_to: localhost
-- name: Associate an access port block (single port) to an interface selector of type fex
+- name: Associate a Fabric access policy interface port block (single port) to an interface selector of type fex
cisco.aci.aci_access_port_block_to_access_port:
host: apic
username: admin
@@ -128,7 +143,7 @@ EXAMPLES = r"""
state: present
delegate_to: localhost
-- name: Associate an access port block (port range) to an interface selector of type fex
+- name: Associate a Fabric access policy interface port block (port range) to an interface selector of type fex
cisco.aci.aci_access_port_block_to_access_port:
host: apic
username: admin
@@ -142,7 +157,7 @@ EXAMPLES = r"""
state: present
delegate_to: localhost
-- name: Remove an access port block from an interface selector
+- name: Query Specific Fabric access policy interface port block under given access port selector
cisco.aci.aci_access_port_block_to_access_port:
host: apic
username: admin
@@ -150,12 +165,11 @@ EXAMPLES = r"""
interface_profile: leafintprfname
access_port_selector: accessportselectorname
port_blk: leafportblkname
- from_port: 13
- to_port: 13
- state: absent
+ state: query
delegate_to: localhost
+ register: query_result
-- name: Remove an access port block from an interface selector of type fex
+- name: Query Specific Fabric access policy interface port block under given access port selector of type fex
cisco.aci.aci_access_port_block_to_access_port:
host: apic
username: admin
@@ -164,75 +178,76 @@ EXAMPLES = r"""
interface_profile: leafintprfname_fex
access_port_selector: accessportselectorname_fex
port_blk: leafportblkname_fex
- from_port: 13
- to_port: 13
- state: absent
+ state: query
delegate_to: localhost
+ register: query_result
-- name: Query Specific access port block under given access port selector
+- name: Query all Fabric access policy interface port blocks under given leaf interface profile
cisco.aci.aci_access_port_block_to_access_port:
host: apic
username: admin
password: SomeSecretPassword
interface_profile: leafintprfname
- access_port_selector: accessportselectorname
- port_blk: leafportblkname
state: query
delegate_to: localhost
register: query_result
-- name: Query Specific access port block under given access port selector of type fex
+- name: Query all Fabric access policy interface port blocks under given leaf interface profile of type fex
cisco.aci.aci_access_port_block_to_access_port:
host: apic
username: admin
password: SomeSecretPassword
type: fex
interface_profile: leafintprfname_fex
- access_port_selector: accessportselectorname_fex
- port_blk: leafportblkname_fex
state: query
delegate_to: localhost
register: query_result
-- name: Query all access port blocks under given leaf interface profile
+- name: Query all Fabric access policy interface port blocks in the fabric
cisco.aci.aci_access_port_block_to_access_port:
host: apic
username: admin
password: SomeSecretPassword
- interface_profile: leafintprfname
state: query
delegate_to: localhost
register: query_result
-- name: Query all access port blocks under given leaf interface profile of type fex
+- name: Query all Fabric access policy interface port blocks in the fabric of type fex
cisco.aci.aci_access_port_block_to_access_port:
host: apic
username: admin
password: SomeSecretPassword
type: fex
- interface_profile: leafintprfname_fex
state: query
delegate_to: localhost
register: query_result
-- name: Query all access port blocks in the fabric
+- name: Remove a Fabric access policy interface port block from an interface selector
cisco.aci.aci_access_port_block_to_access_port:
host: apic
username: admin
password: SomeSecretPassword
- state: query
+ interface_profile: leafintprfname
+ access_port_selector: accessportselectorname
+ port_blk: leafportblkname
+ from_port: 13
+ to_port: 13
+ state: absent
delegate_to: localhost
- register: query_result
-- name: Query all access port blocks in the fabric of type fex
+- name: Remove a Fabric access policy interface port block from an interface selector of type fex
cisco.aci.aci_access_port_block_to_access_port:
host: apic
username: admin
password: SomeSecretPassword
type: fex
- state: query
+ interface_profile: leafintprfname_fex
+ access_port_selector: accessportselectorname_fex
+ port_blk: leafportblkname_fex
+ from_port: 13
+ to_port: 13
+ state: absent
delegate_to: localhost
- register: query_result
"""
RETURN = r"""
@@ -348,7 +363,16 @@ def main():
argument_spec = aci_argument_spec()
argument_spec.update(aci_annotation_spec())
argument_spec.update(
- interface_profile=dict(type="str", aliases=["leaf_interface_profile_name", "leaf_interface_profile", "interface_profile_name"]),
+ interface_profile=dict(
+ type="str",
+ aliases=[
+ "leaf_interface_profile_name",
+ "leaf_interface_profile",
+ "interface_profile_name",
+ "spine_interface_profile",
+ "spine_interface_profile_name",
+ ],
+ ),
access_port_selector=dict(type="str", aliases=["name", "access_port_selector_name"]), # Not required for querying all objects
port_blk=dict(type="str", aliases=["leaf_port_blk_name", "leaf_port_blk"]), # Not required for querying all objects
port_blk_description=dict(type="str", aliases=["leaf_port_blk_description"]),
@@ -357,15 +381,15 @@ def main():
from_card=dict(type="str", aliases=["from_card_range"]),
to_card=dict(type="str", aliases=["to_card_range"]),
state=dict(type="str", default="present", choices=["absent", "present", "query"]),
- type=dict(type="str", default="leaf", choices=["fex", "leaf"]), # This parameter is not required for querying all objects
+ type=dict(type="str", default="leaf", choices=["fex", "leaf", "spine"]), # This parameter is not required for querying all objects
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
- ["state", "absent", ["access_port_selector", "port_blk", "interface_profile"]],
- ["state", "present", ["access_port_selector", "port_blk", "from_port", "to_port", "interface_profile"]],
+ ["state", "absent", ["interface_profile", "access_port_selector", "port_blk"]],
+ ["state", "present", ["interface_profile", "access_port_selector", "port_blk", "from_port", "to_port"]],
],
)
@@ -381,26 +405,45 @@ def main():
type_port = module.params.get("type")
aci = ACIModule(module)
+
aci_class = "infraAccPortP"
aci_rn = "accportprof"
if type_port == "fex":
aci_class = "infraFexP"
aci_rn = "fexprof"
- aci.construct_url(
- root_class=dict(
- aci_class=aci_class,
- aci_rn="infra/" + aci_rn + "-{0}".format(interface_profile),
+ subclass_1 = dict(
+ aci_class=aci_class,
+ aci_rn="{0}-{1}".format(aci_rn, interface_profile),
+ module_object=interface_profile,
+ target_filter={"name": interface_profile},
+ )
+ subclass_2 = dict(
+ aci_class="infraHPortS",
+ aci_rn="hports-{0}-typ-range".format(access_port_selector),
+ module_object=access_port_selector,
+ target_filter={"name": access_port_selector},
+ )
+ if type_port == "spine":
+ subclass_1 = dict(
+ aci_class="infraSpAccPortP",
+ aci_rn="spaccportprof-{0}".format(interface_profile),
module_object=interface_profile,
target_filter={"name": interface_profile},
- ),
- subclass_1=dict(
- aci_class="infraHPortS",
- # NOTE: normal rn: hports-{name}-typ-{type}, hence here hardcoded to range for purposes of module
- aci_rn="hports-{0}-typ-range".format(access_port_selector),
+ )
+ subclass_2 = dict(
+ aci_class="infraSHPortS",
+ aci_rn="shports-{0}-typ-range".format(access_port_selector),
module_object=access_port_selector,
target_filter={"name": access_port_selector},
+ )
+ aci.construct_url(
+ root_class=dict(
+ aci_class="infraInfra",
+ aci_rn="infra",
),
- subclass_2=dict(
+ subclass_1=subclass_1,
+ subclass_2=subclass_2,
+ subclass_3=dict(
aci_class="infraPortBlk",
aci_rn="portblk-{0}".format(port_blk),
module_object=port_blk,
@@ -420,7 +463,6 @@ def main():
toPort=to_port,
fromCard=from_card,
toCard=to_card,
- # type='range',
),
)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_access_port_to_interface_policy_leaf_profile.py b/ansible_collections/cisco/aci/plugins/modules/aci_access_port_to_interface_policy_leaf_profile.py
index 7b5c896ad..f2e921394 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_access_port_to_interface_policy_leaf_profile.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_access_port_to_interface_policy_leaf_profile.py
@@ -14,7 +14,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_access_port_to_interface_policy_leaf_profile
-short_description: Manage Fabric interface policy leaf profile interface selectors (infra:HPortS, infra:RsAccBaseGrp, infra:PortBlk)
+short_description: Manage Fabric interface policy leaf profile interface selectors (infra:HPortS, infra:RsAccBaseGrp, and infra:PortBlk)
description:
- Manage Fabric interface policy leaf profile interface selectors on Cisco ACI fabrics.
options:
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_access_spine_interface_profile.py b/ansible_collections/cisco/aci/plugins/modules/aci_access_spine_interface_profile.py
new file mode 100644
index 000000000..a34f269ae
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_access_spine_interface_profile.py
@@ -0,0 +1,279 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Eric Girard <@netgirard>
+# Copyright: (c) 2024, Gaspard Micol (@gmicol) <gmicol@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": "certified",
+}
+
+DOCUMENTATION = r"""
+---
+module: aci_access_spine_interface_profile
+short_description: Manage fabric interface policy spine profiles (infra:SpAccPortP)
+description:
+- Manage fabric interface policy spine profiles on Cisco ACI fabrics.
+options:
+ interface_profile:
+ description:
+ - The name of the Fabric access policy spine interface profile.
+ type: str
+ aliases: [ name, spine_interface_profile_name, spine_interface_profile, interface_profile_name ]
+ description:
+ description:
+ - The description for the Fabric access policy spine interface profile.
+ 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
+
+seealso:
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(infra:SpAccPortP).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Eric Girard (@netgirard)
+- Gaspard Micol (@gmicol)
+"""
+
+EXAMPLES = r"""
+- name: Add a new spine_interface_profile
+ cisco.aci.aci_access_spine_interface_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ interface_profile: spineintprfname
+ description: spineintprfname description
+ state: present
+ delegate_to: localhost
+
+- name: Query a spine_interface_profile
+ cisco.aci.aci_access_spine_interface_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ interface_profile: spineintprfname
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all spine_interface_profiles
+ cisco.aci.aci_access_spine_interface_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+
+- name: Remove a spine_interface_profile
+ cisco.aci.aci_access_spine_interface_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ interface_profile: spineintprfname
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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(
+ interface_profile=dict(
+ type="str",
+ aliases=[
+ "name",
+ "spine_interface_profile_name",
+ "spine_interface_profile",
+ "interface_profile_name",
+ ],
+ ),
+ description=dict(type="str", aliases=["descr"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ name_alias=dict(type="str"),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["interface_profile"]],
+ ["state", "present", ["interface_profile"]],
+ ],
+ )
+
+ interface_profile = module.params.get("interface_profile")
+ description = module.params.get("description")
+ state = module.params.get("state")
+ name_alias = module.params.get("name_alias")
+
+ aci = ACIModule(module)
+
+ aci.construct_url(
+ root_class=dict(
+ aci_class="infraInfra",
+ aci_rn="infra",
+ ),
+ subclass_1=dict(
+ aci_class="infraSpAccPortP",
+ aci_rn="spaccportprof-{0}".format(interface_profile),
+ module_object=interface_profile,
+ target_filter={"name": interface_profile},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class="infraSpAccPortP",
+ class_config=dict(
+ name=interface_profile,
+ descr=description,
+ nameAlias=name_alias,
+ ),
+ )
+
+ aci.get_diff(aci_class="infraSpAccPortP")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_access_spine_interface_profile_to_spine_switch_profile.py b/ansible_collections/cisco/aci/plugins/modules/aci_access_spine_interface_profile_to_spine_switch_profile.py
new file mode 100644
index 000000000..17d8517c1
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_access_spine_interface_profile_to_spine_switch_profile.py
@@ -0,0 +1,292 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Eric Girard <@netgirard>
+# Copyright: (c) 2024, Gaspard Micol (@gmicol) <gmicol@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": "certified",
+}
+
+DOCUMENTATION = r"""
+---
+module: aci_access_spine_interface_profile_to_spine_switch_profile
+short_description: Bind Fabric Access Spine Interface Profiles to Fabric Acces Spine Switch Profiles (infra:RsSpAccPortP)
+description:
+- Bind access spine interface selector profiles to access switch policy spine profiles on Cisco ACI fabrics.
+options:
+ switch_profile:
+ description:
+ - The name of the Fabric Access Spine Switch Profile to which we add a Spine Interface Selector Profile.
+ type: str
+ aliases: [ switch_profile_name, spine_switch_profile, spine_switch_profile_name ]
+ interface_profile:
+ description:
+ - The name of the Fabric Access Spine Interface Profile to be added and associated with the Spine Switch Profile.
+ type: str
+ aliases: [ interface_profile_name, spine_interface_profile, spine_interface_profile_name ]
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+notes:
+- This module requires an existing I(switch_profile).
+ The module M(cisco.aci.aci_access_spine_switch_profile) can be used for this.
+- The I(interface_profile) accepts non existing spine interface profile names.
+ They appear on APIC GUI with a state of "missing-target".
+ The module M(cisco.aci.aci_access_spine_interface_profile) can be used to create them.
+seealso:
+- module: cisco.aci.aci_access_spine_switch_profile
+- module: cisco.aci.aci_access_spine_interface_profile
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(infra:RsSpAccPortP).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Eric Girard (@netgirard)
+- Gaspard Micol (@gmicol)
+"""
+
+EXAMPLES = r"""
+- name: Associating an interface selector profile to a switch policy spine profile
+ cisco.aci.aci_access_spine_interface_profile_to_spine_switch_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ switch_profile: sw_name
+ interface_profile: interface_profile_name
+ state: present
+ delegate_to: localhost
+
+- name: Query an interface selector profile associated with a switch policy spine profile
+ cisco.aci.aci_access_spine_interface_profile_to_spine_switch_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ switch_profile: sw_name
+ interface_profile: interface_profile_name
+ state: query
+ delegate_to: localhost
+
+- name: Query all association of interface selector profiles with a switch policy spine profile
+ cisco.aci.aci_access_spine_interface_profile_to_spine_switch_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+
+- name: Remove an interface selector profile associated with a switch policy spine profile
+ cisco.aci.aci_access_spine_interface_profile_to_spine_switch_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ switch_profile: sw_name
+ interface_profile: interface_profile_name
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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(
+ switch_profile=dict(
+ type="str",
+ aliases=[
+ "switch_profile_name",
+ "spine_switch_profile",
+ "spine_switch_profile_name",
+ ],
+ ), # Not required for querying all objects
+ interface_profile=dict(
+ type="str",
+ aliases=[
+ "interface_profile_name",
+ "spine_interface_profile",
+ "spine_interface_profile_name",
+ ],
+ ), # Not required for querying all objects
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["switch_profile", "interface_profile"]],
+ ["state", "present", ["switch_profile", "interface_profile"]],
+ ],
+ )
+
+ switch_profile = module.params.get("switch_profile")
+ interface_profile = module.params.get("interface_profile")
+ state = module.params.get("state")
+
+ # Defining the interface profile tDn for clarity
+ interface_profile_tDn = "uni/infra/spaccportprof-{0}".format(interface_profile)
+
+ aci = ACIModule(module)
+ aci.construct_url(
+ root_class=dict(
+ aci_class="infraInfra",
+ aci_rn="infra",
+ ),
+ subclass_1=dict(
+ aci_class="infraSpineP",
+ aci_rn="spprof-{0}".format(switch_profile),
+ module_object=switch_profile,
+ target_filter={"name": switch_profile},
+ ),
+ subclass_2=dict(
+ aci_class="infraRsSpAccPortP",
+ aci_rn="rsspAccPortP-[{0}]".format(interface_profile_tDn),
+ module_object=interface_profile,
+ target_filter={"tDn": interface_profile_tDn},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class="infraRsSpAccPortP",
+ class_config=dict(tDn=interface_profile_tDn),
+ )
+
+ aci.get_diff(aci_class="infraRsSpAccPortP")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_access_spine_interface_selector.py b/ansible_collections/cisco/aci/plugins/modules/aci_access_spine_interface_selector.py
new file mode 100644
index 000000000..373a31e76
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_access_spine_interface_selector.py
@@ -0,0 +1,326 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2024, Gaspard Micol (@gmicol) <gmicol@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": "certified"}
+
+DOCUMENTATION = r"""
+---
+module: aci_access_spine_interface_selector
+short_description: Manage Fabric Access Policy Spine Interface Port Selectors (infra:SHPortS)
+description:
+- Manage Fabric Access Policy Spine Interface Port Selectors on Cisco ACI fabrics.
+- This selector is used for applying infrastructure policies on selected ports.
+options:
+ spine_interface_profile:
+ description:
+ - The name of the Fabric access policy spine interface profile.
+ type: str
+ aliases: [ spine_interface_profile_name, interface_profile, interface_profile_name ]
+ spine_interface_selector:
+ description:
+ - The name of the Fabric access spine interface port selector.
+ type: str
+ aliases: [ name, spine_interface_selector_name, interface_selector, interface_selector_name, access_port_selector, access_port_selector_name ]
+ description:
+ description:
+ - The description for the spine interface port selector.
+ type: str
+ policy_group:
+ description:
+ - The name of the fabric access policy group to be associated with the spine interface port selector.
+ type: str
+ aliases: [ policy_group_name ]
+ selector_type:
+ description:
+ - The host port selector type.
+ - If using a port block to specify range of interfaces, the type must be set to C(range).
+ type: str
+ choices: [ all, range ]
+ aliases: [ type ]
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+notes:
+- The I(spine_interface_profile) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_access_spine_interface_profile) module can be used for this.
+- If a I(policy_group) is used, it must exist before using this module in your playbook.
+ The M(cisco.aci.aci_interface_policy_spine_policy_group) module can be used for this.
+seealso:
+- module: cisco.aci.aci_access_port_block_to_access_port
+- module: cisco.aci.aci_interface_policy_spine_policy_group
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC classes B(infra:SHPortS) and B(infra:RsSpAccGrp).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Gaspard Micol (@gmicol)
+"""
+
+EXAMPLES = r"""
+- name: Add a new access spine interface selector
+ cisco.aci.aci_access_spine_interface_selector:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ spine_interface_profile: my_access_spine_interface_profile
+ spine_interface_selector: my_access_spine_interface_selector
+ selector_type: range
+ policy_group: my_access_spine_interface_policy_group
+ state: present
+ delegate_to: localhost
+
+- name: Query a specific access spine interface selector under given spine_interface_profile
+ cisco.aci.aci_access_spine_interface_selector:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ spine_interface_profile: my_access_spine_interface_profile
+ spine_interface_selector: my_access_spine_interface_selector
+ selector_type: range
+ state: query
+ delegate_to: localhost
+
+- name: Query all access spine interface selectors under given spine_interface_profile
+ cisco.aci.aci_access_spine_interface_selector:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ spine_interface_profile: my_access_spine_interface_profile
+ state: query
+ delegate_to: localhost
+
+- name: Query all access spine interface selectors
+ cisco.aci.aci_access_spine_interface_selector:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+
+- name: Remove an access spine interface selector
+ cisco.aci.aci_access_spine_interface_selector:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ spine_interface_profile: my_access_spine_interface_profile
+ spine_interface_selector: my_access_spine_interface_selector
+ selector_type: range
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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
+from ansible_collections.cisco.aci.plugins.module_utils.constants import MATCH_ACCESS_POLICIES_SELECTOR_TYPE
+
+
+def main():
+ argument_spec = aci_argument_spec()
+ argument_spec.update(aci_annotation_spec())
+ argument_spec.update(aci_owner_spec())
+ argument_spec.update(
+ spine_interface_profile=dict(type="str", aliases=["spine_interface_profile_name", "interface_profile", "interface_profile_name"]),
+ spine_interface_selector=dict(
+ type="str",
+ aliases=[
+ "name",
+ "spine_interface_selector_name",
+ "interface_selector",
+ "interface_selector_name",
+ "access_port_selector",
+ "access_port_selector_name",
+ ],
+ ), # Not required for querying all objects
+ description=dict(type="str"),
+ policy_group=dict(type="str", aliases=["policy_group_name"]),
+ selector_type=dict(type="str", choices=list(MATCH_ACCESS_POLICIES_SELECTOR_TYPE.keys()), aliases=["type"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["spine_interface_profile", "spine_interface_selector", "selector_type"]],
+ ["state", "present", ["spine_interface_profile", "spine_interface_selector", "selector_type"]],
+ ],
+ )
+
+ spine_interface_profile = module.params.get("spine_interface_profile")
+ spine_interface_selector = module.params.get("spine_interface_selector")
+ description = module.params.get("description")
+ policy_group = module.params.get("policy_group")
+ selector_type = MATCH_ACCESS_POLICIES_SELECTOR_TYPE.get(module.params.get("selector_type"))
+ state = module.params.get("state")
+
+ child_configs = []
+ if policy_group is not None:
+ child_configs.append(dict(infraRsSpAccGrp=dict(attributes=dict(tDn="uni/infra/funcprof/spaccportgrp-{0}".format(policy_group)))))
+
+ aci = ACIModule(module)
+
+ aci.construct_url(
+ root_class=dict(
+ aci_class="infraInfra",
+ aci_rn="infra",
+ ),
+ subclass_1=dict(
+ aci_class="infraSpAccPortP",
+ aci_rn="spaccportprof-{0}".format(spine_interface_profile),
+ module_object=spine_interface_profile,
+ target_filter={"name": spine_interface_profile},
+ ),
+ subclass_2=dict(
+ aci_class="infraSHPortS",
+ aci_rn="shports-{0}-typ-{1}".format(spine_interface_selector, selector_type),
+ module_object=spine_interface_selector,
+ target_filter={"name": spine_interface_selector},
+ ),
+ child_classes=["infraRsSpAccGrp"],
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class="infraSHPortS",
+ class_config=dict(
+ descr=description,
+ name=spine_interface_selector,
+ type=selector_type,
+ ),
+ child_configs=child_configs,
+ )
+
+ aci.get_diff(aci_class="infraSHPortS")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_access_spine_switch_profile.py b/ansible_collections/cisco/aci/plugins/modules/aci_access_spine_switch_profile.py
new file mode 100644
index 000000000..22d4756a7
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_access_spine_switch_profile.py
@@ -0,0 +1,277 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Eric Girard <@netgirard>
+# Copyright: (c) 2024, Gaspard Micol (@gmicol) <gmicol@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": "certified",
+}
+
+DOCUMENTATION = r"""
+---
+module: aci_access_spine_switch_profile
+short_description: Manage Fabric Access Spine Switch Profiles (infra:SpineP)
+description:
+- Manage Fabric access switch policy spine profiles on Cisco ACI fabrics.
+options:
+ switch_profile:
+ description:
+ - The name of the Fabric Access Spine Switch Profile.
+ type: str
+ aliases: [ switch_profile_name, name, spine_switch_profile, spine_switch_profile_name ]
+ description:
+ description:
+ - The description for the Fabric Access Spine Switch Profile.
+ 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
+
+seealso:
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(infra:SpineP).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Eric Girard (@netgirard)
+- Gaspard Micol (@gmicol)
+"""
+
+EXAMPLES = r"""
+- name: Add a new Access Spine Switch Profile
+ cisco.aci.aci_access_spine_switch_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ switch_profile: sw_name
+ description: sw_description
+ state: present
+ delegate_to: localhost
+
+- name: Query an Access Spine Switch Profile
+ cisco.aci.aci_access_spine_switch_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ switch_profile: sw_name
+ state: query
+ delegate_to: localhost
+
+- name: Query all Access Spine Switch Profiles
+ cisco.aci.aci_access_spine_switch_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+
+- name: Remove an Access Spine Switch Profile
+ cisco.aci.aci_access_spine_switch_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ switch_profile: sw_name
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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(
+ switch_profile=dict(
+ type="str",
+ aliases=[
+ "name",
+ "switch_profile_name",
+ "spine_switch_profile",
+ "spine_switch_profile_name",
+ ],
+ ), # Not required for querying all objects
+ description=dict(type="str", aliases=["descr"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ name_alias=dict(type="str"),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["switch_profile"]],
+ ["state", "present", ["switch_profile"]],
+ ],
+ )
+
+ switch_profile = module.params.get("switch_profile")
+ description = module.params.get("description")
+ state = module.params.get("state")
+ name_alias = module.params.get("name_alias")
+
+ aci = ACIModule(module)
+ aci.construct_url(
+ root_class=dict(
+ aci_class="infraInfra",
+ aci_rn="infra",
+ ),
+ subclass_1=dict(
+ aci_class="infraSpineP",
+ aci_rn="spprof-{0}".format(switch_profile),
+ module_object=switch_profile,
+ target_filter={"name": switch_profile},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class="infraSpineP",
+ class_config=dict(
+ name=switch_profile,
+ descr=description,
+ nameAlias=name_alias,
+ ),
+ )
+
+ aci.get_diff(aci_class="infraSpineP")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_access_spine_switch_selector.py b/ansible_collections/cisco/aci/plugins/modules/aci_access_spine_switch_selector.py
new file mode 100644
index 000000000..c7cee4b5e
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_access_spine_switch_selector.py
@@ -0,0 +1,321 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Eric Girard <@netgirard>
+# Copyright: (c) 2024, Gaspard Micol (@gmicol) <gmicol@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": "certified",
+}
+
+DOCUMENTATION = r"""
+---
+module: aci_access_spine_switch_selector
+short_description: Manage Fabric Access Policy Spine Switch Port Selectors (infra:SpineS)
+description:
+- Manage Fabric Access Policy Spine Switch Port Selectors on Cisco ACI fabrics.
+options:
+ spine_switch_profile:
+ description:
+ - The name of the Fabric access policy spine switch profile.
+ type: str
+ aliases: [ spine_switch_profile_name, switch_profile, switch_profile_name ]
+ spine_switch_selector:
+ description:
+ - The name of the Fabric access spine switch port selector.
+ type: str
+ aliases: [ name, spine_switch_selector_name, switch_selector, switch_selector_name, access_port_selector, access_port_selector_name ]
+ description:
+ description:
+ - The description for the spine switch port selector.
+ type: str
+ policy_group:
+ description:
+ - The name of the fabric access policy group to be associated with the spine switch port selector.
+ type: str
+ aliases: [ policy_group_name ]
+ selector_type:
+ description:
+ - The host port selector type.
+ - If using a port block to specify range of switches, the type must be set to C(range).
+ type: str
+ choices: [ all, range ]
+ aliases: [ type ]
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+notes:
+- The I(spine_switch_profile) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_access_spine_switch_profile) module can be used for this.
+- If a I(policy_group) is used, it must exist before using this module in your playbook.
+ The M(cisco.aci.aci_switch_policy_group) module can be used for this.
+seealso:
+- module: cisco.aci.aci_access_spine_switch_profile
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC classes B(infra:SpineS) and B(infra:RsAccNodePGrp).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Eric Girard (@netgirard)
+- Gaspard Micol (@gmicol)
+"""
+
+EXAMPLES = r"""
+- name: Add a switch policy spine profile selector (with policy group)
+ cisco.aci.aci_access_spine_switch_selector:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ spine_switch_profile: sw_name
+ spine_switch_selector: spine_selector_name
+ selector_type: range
+ policy_group: somepolicygroupname
+ state: present
+ delegate_to: localhost
+
+- name: Query a switch policy spine profile selector
+ cisco.aci.aci_access_spine_switch_selector:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ spine_switch_profile: sw_name
+ spine_switch_selector: spine_selector_name
+ selector_type: range
+ state: query
+ delegate_to: localhost
+
+- name: Query all switch policy spine profile selectors
+ cisco.aci.aci_access_spine_switch_selector:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+
+- name: Remove a switch policy spine profile selector
+ cisco.aci.aci_access_spine_switch_selector:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ spine_switch_profile: sw_name
+ spine_switch_selector: spine_selector_name
+ selector_type: range
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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
+from ansible_collections.cisco.aci.plugins.module_utils.constants import MATCH_ACCESS_POLICIES_SELECTOR_TYPE
+
+
+def main():
+ argument_spec = aci_argument_spec()
+ argument_spec.update(aci_annotation_spec())
+ argument_spec.update(aci_owner_spec())
+ argument_spec.update(
+ spine_switch_profile=dict(type="str", aliases=["spine_switch_profile_name", "switch_profile", "switch_profile_name"]),
+ spine_switch_selector=dict(
+ type="str",
+ aliases=[
+ "name",
+ "spine_switch_selector_name",
+ "switch_selector",
+ "switch_selector_name",
+ "access_port_selector",
+ "access_port_selector_name",
+ ],
+ ), # Not required for querying all objects
+ description=dict(type="str"),
+ policy_group=dict(type="str", aliases=["policy_group_name"]),
+ selector_type=dict(type="str", choices=list(MATCH_ACCESS_POLICIES_SELECTOR_TYPE.keys()), aliases=["type"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["spine_switch_profile", "spine_switch_selector", "selector_type"]],
+ ["state", "present", ["spine_switch_profile", "spine_switch_selector", "selector_type"]],
+ ],
+ )
+
+ spine_switch_profile = module.params.get("spine_switch_profile")
+ spine_switch_selector = module.params.get("spine_switch_selector")
+ description = module.params.get("description")
+ policy_group = module.params.get("policy_group")
+ selector_type = MATCH_ACCESS_POLICIES_SELECTOR_TYPE.get(module.params.get("selector_type"))
+ state = module.params.get("state")
+
+ child_configs = []
+ if policy_group is not None:
+ child_configs.append(dict(infraRsSpineAccNodePGrp=dict(attributes=dict(tDn="uni/infra/funcprof/spaccnodepgrp-{0}".format(policy_group)))))
+
+ aci = ACIModule(module)
+
+ aci.construct_url(
+ root_class=dict(
+ aci_class="infraInfra",
+ aci_rn="infra",
+ ),
+ subclass_1=dict(
+ aci_class="infraSpineP",
+ aci_rn="spprof-{0}".format(spine_switch_profile),
+ module_object=spine_switch_profile,
+ target_filter={"name": spine_switch_profile},
+ ),
+ subclass_2=dict(
+ aci_class="infraSpineS",
+ aci_rn="spines-{0}-typ-{1}".format(spine_switch_selector, selector_type),
+ module_object=spine_switch_selector,
+ target_filter={"name": spine_switch_selector},
+ ),
+ child_classes=["infraRsSpineAccNodePGrp"],
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class="infraSpineS",
+ class_config=dict(
+ descr=description,
+ name=spine_switch_selector,
+ type=selector_type,
+ ),
+ child_configs=child_configs,
+ )
+
+ aci.get_diff(aci_class="infraSpineS")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_access_sub_port_block_to_access_port.py b/ansible_collections/cisco/aci/plugins/modules/aci_access_sub_port_block_to_access_port.py
index 8073c6ca2..a3006ad4c 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_access_sub_port_block_to_access_port.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_access_sub_port_block_to_access_port.py
@@ -13,7 +13,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_access_sub_port_block_to_access_port
-short_description: Manage sub port blocks of Fabric interface policy leaf profile interface selectors (infra:HPortS, infra:SubPortBlk)
+short_description: Manage sub port blocks of Fabric interface policy leaf profile interface selectors (infra:HPortS and infra:SubPortBlk)
description:
- Manage sub port blocks of Fabric interface policy leaf profile interface selectors on Cisco ACI fabrics.
seealso:
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_access_switch_policy_group.py b/ansible_collections/cisco/aci/plugins/modules/aci_access_switch_policy_group.py
new file mode 100644
index 000000000..d1ed40408
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_access_switch_policy_group.py
@@ -0,0 +1,600 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Tim Cragg (@timcragg)
+# Copyright: (c) 2023, Akini Ross (@akinross)
+# 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_access_switch_policy_group
+short_description: Manage Access Switch Policy Groups (infra:AccNodePGrp and infra:SpineAccNodePGrp).
+description:
+- Manage Access Switch Policy Groups on Cisco ACI fabrics.
+options:
+ name:
+ description:
+ - The name of the access switch policy group.
+ aliases: [ policy_group ]
+ type: str
+ description:
+ description:
+ - The description of the access switch policy group.
+ type: str
+ switch_type:
+ description:
+ - Whether this is a leaf or spine policy group
+ type: str
+ choices: [ leaf, spine ]
+ required: true
+ spanning_tree_policy:
+ description:
+ - The spanning tree policy bound to the access switch policy group.
+ - Only available in APIC version 5.2 or later.
+ - Only available when I(switch_type=leaf).
+ - The APIC defaults to C("") which results in the target DN set to the default policy when unset during creation.
+ type: str
+ bfd_ipv4_policy:
+ description:
+ - The BFD IPv4 policy bound to the access switch policy group.
+ - The APIC defaults to C("") which results in the target DN set to the default policy when unset during creation.
+ type: str
+ bfd_ipv6_policy:
+ description:
+ - The BFD IPv6 policy bound to the access switch policy group.
+ - The APIC defaults to C("") which results in the target DN set to the default policy when unset during creation.
+ type: str
+ bfd_multihop_ipv4_policy:
+ description:
+ - The BFD multihop IPv4 policy bound to the access switch policy group.
+ - Only available in APIC version 5.x or later.
+ - Only available when I(switch_type=leaf).
+ - The APIC defaults to C("") which results in the target DN set to the default policy when unset during creation.
+ type: str
+ bfd_multihop_ipv6_policy:
+ description:
+ - The BFD multihop IPv6 policy bound to the access switch policy group.
+ - Only available in APIC version 5.x or later.
+ - Only available when I(switch_type=leaf).
+ - The APIC defaults to C("") which results in the target DN set to the default policy when unset during creation.
+ type: str
+ fibre_channel_node_policy:
+ description:
+ - The fibre channel node policy bound to the access switch policy group.
+ - Only available when I(switch_type=leaf).
+ - The APIC defaults to C("") which results in the target DN set to the default policy when unset during creation.
+ type: str
+ poe_node_policy:
+ description:
+ - The PoE node policy bound to the access switch policy group.
+ - Only available when I(switch_type=leaf).
+ - The APIC defaults to C("") which results in the target DN set to the default policy when unset during creation.
+ type: str
+ fibre_channel_san_policy:
+ description:
+ - The fibre channel SAN policy bound to the access switch policy group.
+ - Only available when I(switch_type=leaf).
+ - The APIC defaults to C("") which results in the target DN set to the default policy when unset during creation.
+ type: str
+ monitoring_policy:
+ description:
+ - The monitoring policy bound to the access switch policy group.
+ - Only available when I(switch_type=leaf).
+ - The APIC defaults to C("") which results in the target DN set to the default policy when unset during creation.
+ type: str
+ netflow_node_policy:
+ description:
+ - The netflow node policy bound to the access switch policy group.
+ - Only available when I(switch_type=leaf).
+ - The APIC defaults to C("") which results in the target DN set to the default policy when unset during creation.
+ type: str
+ copp_policy:
+ description:
+ - The CoPP policy bound to the access switch policy group.
+ - The APIC defaults to C("") which results in the target DN set to the default policy when unset during creation.
+ type: str
+ forward_scale_profile_policy:
+ description:
+ - The forward scale profile policy bound to the access switch policy group.
+ - Only available when I(switch_type=leaf).
+ - The APIC defaults to C("") which results in the target DN set to the default policy when unset during creation.
+ type: str
+ fast_link_failover_policy:
+ description:
+ - The fast link failover policy bound to the access switch policy group.
+ - Only available when I(switch_type=leaf).
+ - The APIC defaults to C("") which results in the target DN set to the default policy when unset during creation.
+ type: str
+ node_802_1x_authentication_policy:
+ description:
+ - The 802.1x node authentication policy bound to the access switch policy group.
+ - Only available when I(switch_type=leaf).
+ - The APIC defaults to C("") which results in the target DN set to the default policy when unset during creation.
+ type: str
+ copp_pre_filter_policy:
+ description:
+ - The CoPP pre-filter policy bound to the access switch policy group.
+ - The APIC defaults to C("") which results in the target DN set to the default policy when unset during creation.
+ type: str
+ equipment_flash_policy:
+ description:
+ - The equipment flash policy bound to the access switch policy group.
+ - Only available when I(switch_type=leaf).
+ - The APIC defaults to C("") which results in the target DN set to the default policy when unset during creation.
+ type: str
+ cdp_policy:
+ description:
+ - The CDP policy bound to the access switch policy group.
+ - The APIC defaults to C("") which results in the target DN set to the default policy when unset during creation.
+ type: str
+ lldp_policy:
+ description:
+ - The LLDP policy bound to the access switch policy group.
+ - The APIC defaults to C("") which results in the target DN set to the default policy when unset during creation.
+ type: str
+ sync_e_node_policy:
+ description:
+ - The SyncE node policy bound to the access switch policy group.
+ - Only available in APIC version 5.x or later.
+ - Only available when I(switch_type=leaf).
+ - The APIC defaults to C("") which results in the target DN set to the default policy when unset during creation.
+ type: str
+ ptp_node_policy:
+ description:
+ - The PTP node policy bound to the access switch policy group.
+ - Only available in APIC version 5.2 or later.
+ - Only available when I(switch_type=leaf).
+ - The APIC defaults to C("") which results in the target DN set to the default policy when unset during creation.
+ type: str
+ usb_configuration_policy:
+ description:
+ - The USB configuration policy bound to the access switch policy group.
+ - Only available in APIC version 5.2 or later.
+ - The APIC defaults to C("") which results in the target DN set to the default policy when unset during creation.
+ type: str
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+seealso:
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(infra:AccNodePGrp) and B(infra:SpineAccNodePGrp).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Tim Cragg (@timcragg)
+- Akini Ross (@akinross)
+"""
+
+EXAMPLES = r"""
+- name: Create Leaf Access Switch Policy Group
+ cisco.aci.aci_access_switch_policy_group:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ name: ansible_pol_grp_spine
+ switch_type: leaf
+ spanning_tree_policy: example_spanning_tree_policy
+ bfd_ipv4_policy: example_bfd_ipv4_policy
+ bfd_ipv6_policy: example_bfd_ipv6_policy
+ fibre_channel_node_policy: example_fibre_channel_node_policy
+ poe_node_policy: example_poe_node_policy
+ fibre_channel_san_policy: example_fibre_channel_san_policy
+ monitoring_policy: example_monitoring_policy
+ copp_policy: example_copp_policy
+ forward_scale_profile_policy: example_forward_scale_profile_policy
+ fast_link_failover_policy: example_fast_link_failover_policy
+ node_802_1x_authentication_policy: example_node_802_1x_authentication_policy
+ copp_pre_filter_policy: example_copp_pre_filter_policy
+ equipment_flash_policy: example_equipment_flash_policy
+ cdp_policy: example_cdp_policy
+ lldp_policy: example_lldp_policy
+ state: present
+ delegate_to: localhost
+
+- name: Create Spine Access Switch Policy Group
+ cisco.aci.aci_access_switch_policy_group:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ name: ansible_pol_grp_leaf
+ switch_type: spine
+ bfd_ipv4_policy: example_bfd_ipv4_policy
+ bfd_ipv6_policy: example_bfd_ipv6_policy
+ copp_policy: example_copp_policy
+ copp_pre_filter_policy: example_copp_pre_filter_policy
+ cdp_policy: example_cdp_policy
+ lldp_policy: example_lldp_policy
+ state: present
+ delegate_to: localhost
+
+- name: Delete Leaf Access Switch Policy Group
+ cisco.aci.aci_access_switch_policy_group:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ name: ansible_pol_grp_leaf
+ switch_type: leaf
+ state: absent
+ delegate_to: localhost
+
+- name: Query Leaf Access Switch Policy Group
+ cisco.aci.aci_access_switch_policy_group:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ name: ansible_pol_grp_leaf
+ switch_type: leaf
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query All Leaf Access Switch Policy Groups
+ cisco.aci.aci_access_switch_policy_group:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ switch_type: leaf
+ state: query
+ delegate_to: localhost
+ register: query_result
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+ 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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class "/></imdata>'
+ 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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+ 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
+from ansible_collections.cisco.aci.plugins.module_utils.constants import ACI_ACCESS_SWITCH_POLICY_GROUP_CLASS_MAPPING
+
+
+def main():
+ argument_spec = aci_argument_spec()
+ argument_spec.update(aci_annotation_spec())
+ argument_spec.update(aci_owner_spec())
+ argument_spec.update(
+ name=dict(type="str", aliases=["policy_group"]),
+ description=dict(type="str"),
+ switch_type=dict(type="str", choices=["leaf", "spine"], required=True),
+ spanning_tree_policy=dict(type="str"),
+ bfd_ipv4_policy=dict(type="str"),
+ bfd_ipv6_policy=dict(type="str"),
+ bfd_multihop_ipv4_policy=dict(type="str"),
+ bfd_multihop_ipv6_policy=dict(type="str"),
+ fibre_channel_node_policy=dict(type="str"),
+ poe_node_policy=dict(type="str"),
+ fibre_channel_san_policy=dict(type="str"),
+ monitoring_policy=dict(type="str"),
+ netflow_node_policy=dict(type="str"),
+ copp_policy=dict(type="str"),
+ forward_scale_profile_policy=dict(type="str"),
+ fast_link_failover_policy=dict(type="str"),
+ node_802_1x_authentication_policy=dict(type="str"),
+ copp_pre_filter_policy=dict(type="str"),
+ equipment_flash_policy=dict(type="str"),
+ cdp_policy=dict(type="str"),
+ lldp_policy=dict(type="str"),
+ sync_e_node_policy=dict(type="str"),
+ ptp_node_policy=dict(type="str"),
+ usb_configuration_policy=dict(type="str"),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["name"]],
+ ["state", "present", ["name"]],
+ ],
+ )
+ name = module.params.get("name")
+ description = module.params.get("description")
+ switch_type = module.params.get("switch_type")
+ spanning_tree_policy = module.params.get("spanning_tree_policy")
+ bfd_ipv4_policy = module.params.get("bfd_ipv4_policy")
+ bfd_ipv6_policy = module.params.get("bfd_ipv6_policy")
+ bfd_multihop_ipv4_policy = module.params.get("bfd_multihop_ipv4_policy")
+ bfd_multihop_ipv6_policy = module.params.get("bfd_multihop_ipv6_policy")
+ fibre_channel_node_policy = module.params.get("fibre_channel_node_policy")
+ poe_node_policy = module.params.get("poe_node_policy")
+ fibre_channel_san_policy = module.params.get("fibre_channel_san_policy")
+ monitoring_policy = module.params.get("monitoring_policy")
+ netflow_node_policy = module.params.get("netflow_node_policy")
+ copp_policy = module.params.get("copp_policy")
+ forward_scale_profile_policy = module.params.get("forward_scale_profile_policy")
+ fast_link_failover_policy = module.params.get("fast_link_failover_policy")
+ node_802_1x_authentication_policy = module.params.get("node_802_1x_authentication_policy")
+ copp_pre_filter_policy = module.params.get("copp_pre_filter_policy")
+ equipment_flash_policy = module.params.get("equipment_flash_policy")
+ cdp_policy = module.params.get("cdp_policy")
+ lldp_policy = module.params.get("lldp_policy")
+ sync_e_node_policy = module.params.get("sync_e_node_policy")
+ ptp_node_policy = module.params.get("ptp_node_policy")
+ usb_configuration_policy = module.params.get("usb_configuration_policy")
+ state = module.params.get("state")
+
+ aci = ACIModule(module)
+
+ if switch_type == "spine" and not all(
+ v is None
+ for v in [
+ spanning_tree_policy,
+ bfd_multihop_ipv4_policy,
+ bfd_multihop_ipv6_policy,
+ fibre_channel_node_policy,
+ poe_node_policy,
+ fibre_channel_san_policy,
+ monitoring_policy,
+ netflow_node_policy,
+ forward_scale_profile_policy,
+ fast_link_failover_policy,
+ node_802_1x_authentication_policy,
+ equipment_flash_policy,
+ sync_e_node_policy,
+ ptp_node_policy,
+ ]
+ ):
+ aci.fail_json(msg="Unsupported policy provided for spine switch type.")
+
+ class_name = ACI_ACCESS_SWITCH_POLICY_GROUP_CLASS_MAPPING.get(switch_type).get("class_name")
+
+ aci.construct_url(
+ root_class=dict(
+ aci_class=class_name,
+ aci_rn=ACI_ACCESS_SWITCH_POLICY_GROUP_CLASS_MAPPING.get(switch_type).get("rn").format(name),
+ module_object=name,
+ target_filter={"name": name},
+ ),
+ rsp_subtree="children",
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ child_configs = []
+ if forward_scale_profile_policy is not None:
+ child_configs.append({"infraRsTopoctrlFwdScaleProfPol": {"attributes": {"tnTopoctrlFwdScaleProfilePolName": forward_scale_profile_policy}}})
+ if usb_configuration_policy is not None:
+ child_configs.append(
+ {
+ ACI_ACCESS_SWITCH_POLICY_GROUP_CLASS_MAPPING.get(switch_type)
+ .get("usb_configuration_policy")
+ .get("class_name"): {
+ "attributes": {
+ ACI_ACCESS_SWITCH_POLICY_GROUP_CLASS_MAPPING.get(switch_type)
+ .get("usb_configuration_policy")
+ .get("tn_name"): usb_configuration_policy
+ }
+ }
+ }
+ )
+ if lldp_policy is not None:
+ child_configs.append(
+ {
+ ACI_ACCESS_SWITCH_POLICY_GROUP_CLASS_MAPPING.get(switch_type)
+ .get("lldp_policy")
+ .get("class_name"): {
+ "attributes": {ACI_ACCESS_SWITCH_POLICY_GROUP_CLASS_MAPPING.get(switch_type).get("lldp_policy").get("tn_name"): lldp_policy}
+ }
+ }
+ )
+ if cdp_policy is not None:
+ child_configs.append(
+ {
+ ACI_ACCESS_SWITCH_POLICY_GROUP_CLASS_MAPPING.get(switch_type)
+ .get("cdp_policy")
+ .get("class_name"): {
+ "attributes": {ACI_ACCESS_SWITCH_POLICY_GROUP_CLASS_MAPPING.get(switch_type).get("cdp_policy").get("tn_name"): cdp_policy}
+ }
+ }
+ )
+ if bfd_ipv4_policy is not None:
+ child_configs.append(
+ {
+ ACI_ACCESS_SWITCH_POLICY_GROUP_CLASS_MAPPING.get(switch_type)
+ .get("bfd_ipv4_policy")
+ .get("class_name"): {
+ "attributes": {ACI_ACCESS_SWITCH_POLICY_GROUP_CLASS_MAPPING.get(switch_type).get("bfd_ipv4_policy").get("tn_name"): bfd_ipv4_policy}
+ }
+ }
+ )
+ if bfd_ipv6_policy is not None:
+ child_configs.append(
+ {
+ ACI_ACCESS_SWITCH_POLICY_GROUP_CLASS_MAPPING.get(switch_type)
+ .get("bfd_ipv6_policy")
+ .get("class_name"): {
+ "attributes": {ACI_ACCESS_SWITCH_POLICY_GROUP_CLASS_MAPPING.get(switch_type).get("bfd_ipv6_policy").get("tn_name"): bfd_ipv6_policy}
+ }
+ }
+ )
+ if sync_e_node_policy is not None:
+ child_configs.append({"infraRsSynceInstPol": {"attributes": {"tnSynceInstPolName": sync_e_node_policy}}})
+ if poe_node_policy is not None:
+ child_configs.append({"infraRsPoeInstPol": {"attributes": {"tnPoeInstPolName": poe_node_policy}}})
+ if bfd_multihop_ipv4_policy is not None:
+ child_configs.append({"infraRsBfdMhIpv4InstPol": {"attributes": {"tnBfdMhIpv4InstPolName": bfd_multihop_ipv4_policy}}})
+ if bfd_multihop_ipv6_policy is not None:
+ child_configs.append({"infraRsBfdMhIpv6InstPol": {"attributes": {"tnBfdMhIpv6InstPolName": bfd_multihop_ipv6_policy}}})
+ if equipment_flash_policy is not None:
+ child_configs.append({"infraRsEquipmentFlashConfigPol": {"attributes": {"tnEquipmentFlashConfigPolName": equipment_flash_policy}}})
+ if monitoring_policy is not None:
+ child_configs.append({"infraRsMonNodeInfraPol": {"attributes": {"tnMonInfraPolName": monitoring_policy}}})
+ if fibre_channel_node_policy is not None:
+ child_configs.append({"infraRsFcInstPol": {"attributes": {"tnFcInstPolName": fibre_channel_node_policy}}})
+ if fast_link_failover_policy is not None:
+ child_configs.append(
+ {"infraRsTopoctrlFastLinkFailoverInstPol": {"attributes": {"tnTopoctrlFastLinkFailoverInstPolName": fast_link_failover_policy}}}
+ )
+ if spanning_tree_policy is not None:
+ child_configs.append({"infraRsMstInstPol": {"attributes": {"tnStpInstPolName": spanning_tree_policy}}})
+ if fibre_channel_san_policy is not None:
+ child_configs.append({"infraRsFcFabricPol": {"attributes": {"tnFcFabricPolName": fibre_channel_san_policy}}})
+ if copp_policy is not None:
+ child_configs.append(
+ {
+ ACI_ACCESS_SWITCH_POLICY_GROUP_CLASS_MAPPING.get(switch_type)
+ .get("copp_policy")
+ .get("class_name"): {
+ "attributes": {ACI_ACCESS_SWITCH_POLICY_GROUP_CLASS_MAPPING.get(switch_type).get("copp_policy").get("tn_name"): copp_policy}
+ }
+ }
+ )
+ if node_802_1x_authentication_policy is not None:
+ child_configs.append({"infraRsL2NodeAuthPol": {"attributes": {"tnL2NodeAuthPolName": node_802_1x_authentication_policy}}})
+ if copp_pre_filter_policy is not None:
+ child_configs.append(
+ {
+ ACI_ACCESS_SWITCH_POLICY_GROUP_CLASS_MAPPING.get(switch_type)
+ .get("copp_pre_filter_policy")
+ .get("class_name"): {
+ "attributes": {
+ ACI_ACCESS_SWITCH_POLICY_GROUP_CLASS_MAPPING.get(switch_type).get("copp_pre_filter_policy").get("tn_name"): copp_pre_filter_policy
+ }
+ }
+ }
+ )
+ if netflow_node_policy is not None:
+ child_configs.append({"infraRsNetflowNodePol": {"attributes": {"tnNetflowNodePolName": netflow_node_policy}}})
+ if ptp_node_policy is not None:
+ child_configs.append({"infraRsPtpInstPol": {"attributes": {"tnPtpInstPolName": ptp_node_policy}}})
+
+ if child_configs == []:
+ child_configs = None
+
+ aci.payload(
+ aci_class=class_name,
+ class_config=dict(
+ descr=description,
+ ),
+ child_configs=child_configs,
+ )
+
+ aci.get_diff(aci_class=class_name)
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_action_rule_additional_communities.py b/ansible_collections/cisco/aci/plugins/modules/aci_action_rule_additional_communities.py
new file mode 100644
index 000000000..c6bd998d9
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_action_rule_additional_communities.py
@@ -0,0 +1,304 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@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": "certified"}
+
+DOCUMENTATION = r"""
+---
+module: aci_action_rule_additional_communities
+short_description: Manage Action Rules based on Additional Communities (rtctrl:SetAddComm)
+description:
+- Set additional communities for the action rule profiles on Cisco ACI fabrics.
+options:
+ tenant:
+ description:
+ - The name of the tenant.
+ type: str
+ aliases: [ tenant_name ]
+ action_rule:
+ description:
+ - The name of the action rule profile.
+ type: str
+ aliases: [ action_rule_name ]
+ community:
+ description:
+ - The community value.
+ type: str
+ criteria:
+ description:
+ - The community criteria.
+ - The option to append or replace the community value.
+ type: str
+ choices: [ append, replace, none ]
+ description:
+ description:
+ - The description for the action rule profile.
+ 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
+
+notes:
+- The C(tenant) and the C(action_rule) used must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant) and M(cisco.aci.aci_tenant_action_rule_profile) modules can be used for this.
+seealso:
+- module: cisco.aci.aci_tenant
+- module: cisco.aci.aci_tenant_action_rule_profile
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(rtctrl:SetAddComm).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Gaspard Micol (@gmicol)
+"""
+
+EXAMPLES = r"""
+- name: Create an additional communities action rule
+ cisco.aci.aci_action_rule_additional_communities:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ action_rule: my_action_rule
+ tenant: prod
+ community: no-advertise
+ criteria: replace
+ state: present
+ delegate_to: localhost
+
+- name: Delete an additional communities action rule
+ cisco.aci.aci_action_rule_additional_communities:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ action_rule: my_action_rule
+ tenant: prod
+ community: no-advertise
+ state: absent
+ delegate_to: localhost
+
+- name: Query all additional communities action rules
+ cisco.aci.aci_action_rule_additional_communities:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query an additional communities action rule
+ cisco.aci.aci_action_rule_additional_communities:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ action_rule: my_action_rule
+ tenant: prod
+ community: no-advertise
+ state: query
+ delegate_to: localhost
+ register: query_result
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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
+
+
+def main():
+ argument_spec = aci_argument_spec()
+ argument_spec.update(aci_annotation_spec())
+ argument_spec.update(
+ tenant=dict(type="str", aliases=["tenant_name"]), # Not required for querying all objects
+ action_rule=dict(type="str", aliases=["action_rule_name"]), # Not required for querying all objects
+ community=dict(type="str"),
+ criteria=dict(type="str", choices=["append", "replace", "none"]),
+ description=dict(type="str", aliases=["descr"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ name_alias=dict(type="str"),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["action_rule", "tenant", "community"]],
+ ["state", "present", ["action_rule", "tenant", "community"]],
+ ],
+ )
+
+ community = module.params.get("community")
+ criteria = module.params.get("criteria")
+ description = module.params.get("description")
+ state = module.params.get("state")
+ tenant = module.params.get("tenant")
+ action_rule = module.params.get("action_rule")
+ 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="rtctrlAttrP",
+ aci_rn="attr-{0}".format(action_rule),
+ module_object=action_rule,
+ target_filter={"name": action_rule},
+ ),
+ subclass_2=dict(
+ aci_class="rtctrlSetAddComm",
+ aci_rn="saddcomm-{0}".format(community),
+ module_object=community,
+ target_filter={"community": community},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class="rtctrlSetAddComm",
+ class_config=dict(
+ community=community,
+ setCriteria=criteria,
+ descr=description,
+ nameAlias=name_alias,
+ ),
+ )
+
+ aci.get_diff(aci_class="rtctrlSetAddComm")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_action_rule_set_as_path.py b/ansible_collections/cisco/aci/plugins/modules/aci_action_rule_set_as_path.py
new file mode 100644
index 000000000..580cc4cff
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_action_rule_set_as_path.py
@@ -0,0 +1,304 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@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": "certified"}
+
+DOCUMENTATION = r"""
+---
+module: aci_action_rule_set_as_path
+short_description: Manage the AS Path action rules (rtctrl:SetASPath)
+description:
+- Set AS path action rule for the action rule profiles on Cisco ACI fabrics.
+options:
+ tenant:
+ description:
+ - The name of the tenant.
+ type: str
+ aliases: [ tenant_name ]
+ action_rule:
+ description:
+ - The name of the action rule profile.
+ type: str
+ aliases: [ action_rule_name ]
+ last_as:
+ description:
+ - The last AS number value.
+ type: int
+ aliases: [ last_as_number ]
+ criteria:
+ description:
+ - The option to append the specified AS number or to prepend the last AS numbers to the AS Path.
+ type: str
+ choices: [ prepend, prepend-last-as ]
+ description:
+ description:
+ - The description for the action rule profile.
+ 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
+
+notes:
+- The C(tenant) and the C(action_rule) used must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant) and M(cisco.aci.aci_tenant_action_rule_profile) modules can be used for this.
+seealso:
+- module: cisco.aci.aci_tenant
+- module: cisco.aci.aci_tenant_action_rule_profile
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(rtctrl:SetASPath).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Gaspard Micol (@gmicol)
+"""
+
+EXAMPLES = r"""
+- name: Create a Set AS path action rule
+ cisco.aci.aci_action_rule_set_as_path:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ action_rule: my_action_rule
+ tenant: prod
+ last_as: 0
+ criteria: prepend
+ state: present
+ delegate_to: localhost
+
+- name: Delete a Set AS path action rule
+ cisco.aci.aci_action_rule_set_as_path:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ action_rule: my_action_rule
+ tenant: prod
+ criteria: prepend
+ state: absent
+ delegate_to: localhost
+
+- name: Query all Set AS path action rules
+ cisco.aci.aci_action_rule_set_as_path:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query a Set AS path action rule
+ cisco.aci.aci_action_rule_set_as_path:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ action_rule: my_action_rule
+ tenant: prod
+ criteria: prepend
+ state: query
+ delegate_to: localhost
+ register: query_result
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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
+
+
+def main():
+ argument_spec = aci_argument_spec()
+ argument_spec.update(aci_annotation_spec())
+ argument_spec.update(
+ tenant=dict(type="str", aliases=["tenant_name"]), # Not required for querying all objects
+ action_rule=dict(type="str", aliases=["action_rule_name"]), # Not required for querying all objects
+ last_as=dict(type="int", aliases=["last_as_number"]),
+ criteria=dict(type="str", choices=["prepend", "prepend-last-as"]),
+ description=dict(type="str", aliases=["descr"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ name_alias=dict(type="str"),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["action_rule", "tenant", "criteria"]],
+ ["state", "present", ["action_rule", "tenant", "criteria"]],
+ ],
+ )
+
+ last_as = module.params.get("last_as_number")
+ criteria = module.params.get("criteria")
+ description = module.params.get("description")
+ state = module.params.get("state")
+ tenant = module.params.get("tenant")
+ action_rule = module.params.get("action_rule")
+ 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="rtctrlAttrP",
+ aci_rn="attr-{0}".format(action_rule),
+ module_object=action_rule,
+ target_filter={"name": action_rule},
+ ),
+ subclass_2=dict(
+ aci_class="rtctrlSetASPath",
+ aci_rn="saspath-{0}".format(criteria),
+ module_object=criteria,
+ target_filter={"criteria": criteria},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class="rtctrlSetASPath",
+ class_config=dict(
+ lastnum=last_as,
+ criteria=criteria,
+ descr=description,
+ nameAlias=name_alias,
+ ),
+ )
+
+ aci.get_diff(aci_class="rtctrlSetASPath")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_action_rule_set_as_path_asn.py b/ansible_collections/cisco/aci/plugins/modules/aci_action_rule_set_as_path_asn.py
new file mode 100644
index 000000000..fdc675ddb
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_action_rule_set_as_path_asn.py
@@ -0,0 +1,312 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@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": "certified"}
+
+DOCUMENTATION = r"""
+---
+module: aci_action_rule_set_as_path_asn
+short_description: Manage the AS Path ASN (rtctrl:SetASPathASN)
+description:
+- Set the ASN for the AS Path action rules on Cisco ACI fabrics.
+- Only used if the AS Path action rule is set to C(prepend).
+options:
+ tenant:
+ description:
+ - The name of the tenant.
+ type: str
+ aliases: [ tenant_name ]
+ action_rule:
+ description:
+ - The name of the action rule profile.
+ type: str
+ aliases: [ action_rule_name ]
+ asn:
+ description:
+ - The ASN number.
+ type: int
+ order:
+ description:
+ - The ASN order.
+ type: int
+ description:
+ description:
+ - The description for the action rule profile.
+ 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
+
+notes:
+- The C(tenant) and the C(action_rule) used must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant) and M(cisco.aci.aci_tenant_action_rule_profile) modules can be used for this.
+- A Set AS Path action rule with criteria set to C(prepend) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_action_rule_set_as_path) modules can be used for this.
+seealso:
+- module: cisco.aci.aci_tenant
+- module: cisco.aci.aci_tenant_action_rule_profile
+- module: cisco.aci.aci_action_rule_set_as_path
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(rtctrl:SetASPathASN).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Gaspard Micol (@gmicol)
+"""
+
+EXAMPLES = r"""
+- name: Create a Set AS Path ASN action rule
+ cisco.aci.aci_action_rule_set_as_path_asn:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ action_rule: my_action_rule
+ tenant: prod
+ order: 1
+ asn: 1
+ state: present
+ delegate_to: localhost
+
+- name: Delete a Set AS Path ASN action rule
+ cisco.aci.aci_action_rule_set_as_path_asn:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ action_rule: my_action_rule
+ tenant: prod
+ order: 1
+ state: absent
+ delegate_to: localhost
+
+- name: Query all Set AS Path ASN action rules
+ cisco.aci.aci_action_rule_set_as_path_asn:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query a Set AS Path ASN action rule
+ cisco.aci.aci_action_rule_set_as_path_asn:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ action_rule: my_action_rule
+ tenant: prod
+ order: 1
+ state: query
+ delegate_to: localhost
+ register: query_result
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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
+
+
+def main():
+ argument_spec = aci_argument_spec()
+ argument_spec.update(aci_annotation_spec())
+ argument_spec.update(
+ tenant=dict(type="str", aliases=["tenant_name"]), # Not required for querying all objects
+ action_rule=dict(type="str", aliases=["action_rule_name"]), # Not required for querying all objects
+ asn=dict(type="int"),
+ order=dict(type="int"),
+ description=dict(type="str", aliases=["descr"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ name_alias=dict(type="str"),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["action_rule", "tenant", "order"]],
+ ["state", "present", ["action_rule", "tenant", "order"]],
+ ],
+ )
+
+ asn = module.params.get("asn")
+ order = module.params.get("order")
+ description = module.params.get("description")
+ state = module.params.get("state")
+ tenant = module.params.get("tenant")
+ action_rule = module.params.get("action_rule")
+ 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="rtctrlAttrP",
+ aci_rn="attr-{0}".format(action_rule),
+ module_object=action_rule,
+ target_filter={"name": action_rule},
+ ),
+ subclass_2=dict(
+ aci_class="rtctrlSetASPath",
+ aci_rn="saspath-prepend",
+ module_object="prepend",
+ target_filter={"criteria": "prepend"},
+ ),
+ subclass_3=dict(
+ aci_class="rtctrlSetASPathASN",
+ aci_rn="asn-{0}".format(order),
+ module_object=order,
+ target_filter={"asn": order},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class="rtctrlSetASPathASN",
+ class_config=dict(
+ asn=asn,
+ order=order,
+ descr=description,
+ nameAlias=name_alias,
+ ),
+ )
+
+ aci.get_diff(aci_class="rtctrlSetASPathASN")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_aep.py b/ansible_collections/cisco/aci/plugins/modules/aci_aep.py
index aa77d8f4f..04ecf58f6 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_aep.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_aep.py
@@ -13,7 +13,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_aep
-short_description: Manage attachable Access Entity Profile (AEP) objects (infra:AttEntityP, infra:ProvAcc)
+short_description: Manage attachable Access Entity Profile (AEP) objects (infra:AttEntityP and infra:ProvAcc)
description:
- Connect to external virtual and physical domains by using
attachable Access Entity Profiles (AEP) on Cisco ACI fabrics.
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_aep_to_epg.py b/ansible_collections/cisco/aci/plugins/modules/aci_aep_to_epg.py
index c77417073..2bba28c5b 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_aep_to_epg.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_aep_to_epg.py
@@ -12,7 +12,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_aep_to_epg
-short_description: Bind EPG to AEP (infra:RsFuncToEpg).
+short_description: Bind EPG to AEP (infra:RsFuncToEpg)
description:
- Bind EPG to AEP.
options:
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_bd.py b/ansible_collections/cisco/aci/plugins/modules/aci_bd.py
index 13d9d1938..d01304cb7 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_bd.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_bd.py
@@ -1,6 +1,8 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+# Copyright: (c) 2017, Jacob McGill (@jmcgill298)
+# Copyright: (c) 2024, Samita Bhattacharjee (@samitab) <samitab@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
@@ -147,6 +149,103 @@ options:
description:
- The L3 Out that contains the associated Route Profile.
type: str
+ host_based_routing:
+ description:
+ - Enables advertising host routes (/32 prefixes) out of the L3OUT(s) that are associated to this BD.
+ - The APIC defaults to C(false) when unset during creation.
+ type: bool
+ aliases: [ advertise_host_routes ]
+ enable_rogue_except_mac:
+ description:
+ - Rogue exception MAC wildcard support for Bridge Domains.
+ - Only available in APIC version 6.0 or later.
+ - The APIC defaults to C(false) when unset during creation.
+ type: bool
+ allow_intersite_bum_traffic:
+ description:
+ - Control whether BUM traffic is allowed between sites.
+ - The APIC defaults to C(false) when unset during creation.
+ type: bool
+ aliases: [allow_bum_traffic]
+ allow_intersite_l2_stretch:
+ description:
+ - Allow L2 Stretch between sites.
+ - The APIC defaults to C(false) when unset during creation.
+ type: bool
+ aliases: [allow_l2_stretch]
+ allow_ipv6_multicast:
+ description:
+ - Flag to indicate if ipv6 multicast is enabled.
+ - The APIC defaults to C(false) when unset during creation.
+ type: bool
+ aliases: [ ipv6_multicast, ipv6_mcast, allow_ipv6_mcast]
+ link_local_address:
+ description:
+ - The override of the system generated IPv6 link-local address.
+ type: str
+ aliases: [ ll_addr_ipv6, ll_addr, link_local]
+ multicast_arp_drop:
+ description:
+ - Enable BD rogue multicast ARP packet drop.
+ - Only available in APIC version 6.0 or later.
+ - The APIC defaults to C(true) when unset during creation.
+ type: bool
+ aliases: [ mcast_arp_drop ]
+ vmac:
+ description:
+ - Virtual MAC address of the BD/SVI. This is used when the BD is extended to multiple sites using L2 Outside.
+ type: str
+ optimize_wan_bandwidth:
+ description:
+ - Optimize WAN Bandwidth improves the network application experience at the branch and makes better use of limited network resources.
+ - The APIC defaults to C(false) when unset during creation.
+ type: bool
+ aliases: [wan_optimization, opt_bandwidth]
+ mld_snoop_policy:
+ description:
+ - The name of the Multicast Listener Discovery (MLD) Snooping Policy the Bridge Domain should use when overriding the default MLD Snooping Policy.
+ - To delete this attribute, pass an empty string.
+ type: str
+ aliases: [mld_snoop, mld_policy]
+ igmp_policy:
+ description:
+ - The name of the IGMP Interface Policy the Bridge Domain should use when overriding the default IGMP Interface Policy.
+ - To delete this attribute, pass an empty string.
+ type: str
+ aliases: [igmp]
+ vlan:
+ description:
+ - The selected VLAN for bridge domain access port encapsulation.
+ - To delete this attribute, pass an empty string.
+ type: str
+ aliases: [encap]
+ monitoring_policy:
+ description:
+ - The name of the Monitoring Policy to apply to the Bridge Domain.
+ - To delete this attribute, pass an empty string.
+ type: str
+ aliases: [mon_pol, monitoring_pol]
+ first_hop_security_policy:
+ description:
+ - The name of the First Hop Security Policy to apply to the Bridge Domain.
+ - To delete this attribute, pass an empty string.
+ type: str
+ aliases: [fhsp, fhs_pol, fhsp_name]
+ pim_source_filter:
+ description:
+ - The name of the PIM Source Filter to apply to the Bridge Domain.
+ - To delete this attribute, pass an empty string.
+ - Only available in APIC version 5.2 or later.
+ type: str
+ aliases: [pim_source]
+ pim_destination_filter:
+ description:
+ - The name of the PIM Destination Filter to apply to the Bridge Domain.
+ - To delete this attribute, pass an empty string.
+ - Only available in APIC version 5.2 or later.
+ type: str
+ aliases: [pim_dest, pim_destination]
+
extends_documentation_fragment:
- cisco.aci.aci
- cisco.aci.annotation
@@ -162,6 +261,7 @@ seealso:
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Jacob McGill (@jmcgill298)
+- Samita Bhattacharjee (@samitab)
"""
EXAMPLES = r"""
@@ -175,6 +275,19 @@ EXAMPLES = r"""
bd: web_servers
mac_address: 00:22:BD:F8:19:FE
vrf: prod_vrf
+ host_based_routing: true
+ allow_intersite_bum_traffic: true
+ allow_intersite_l2_stretch: true
+ allow_ipv6_mcast: true
+ ll_addr: "fe80::1322:33ff:fe44:5566"
+ vmac: "00:AA:BB:CC:DD:03"
+ optimize_wan_bandwidth: true
+ vlan: vlan-101
+ igmp_policy: web_servers_igmp_pol
+ monitoring_policy: web_servers_monitoring_pol
+ igmp_snoop_policy: web_servers_igmp_snoop
+ mld_snoop_policy: web_servers_mld_snoop
+ first_hop_security_policy: web_servers_fhs
state: present
delegate_to: localhost
@@ -205,6 +318,21 @@ EXAMPLES = r"""
state: present
delegate_to: localhost
+- name: Modify a Bridge Domain to remove mld_snoop_policy and first_hop_security_policy
+ cisco.aci.aci_bd:
+ host: "{{ inventory_hostname }}"
+ username: "{{ username }}"
+ password: "{{ password }}"
+ validate_certs: true
+ tenant: prod
+ bd: web_servers
+ arp_flooding: true
+ l2_unknown_unicast: flood
+ mld_snoop_policy: ""
+ first_hop_security_policy: ""
+ state: present
+ delegate_to: localhost
+
- name: Query All Bridge Domains
cisco.aci.aci_bd:
host: "{{ inventory_hostname }}"
@@ -378,6 +506,22 @@ def main():
route_profile=dict(type="str"),
route_profile_l3out=dict(type="str"),
name_alias=dict(type="str"),
+ host_based_routing=dict(type="bool", aliases=["advertise_host_routes"]),
+ enable_rogue_except_mac=dict(type="bool"),
+ allow_intersite_bum_traffic=dict(type="bool", aliases=["allow_bum_traffic"]),
+ allow_intersite_l2_stretch=dict(type="bool", aliases=["allow_l2_stretch"]),
+ allow_ipv6_multicast=dict(type="bool", aliases=["ipv6_multicast", "ipv6_mcast", "allow_ipv6_mcast"]),
+ link_local_address=dict(type="str", aliases=["ll_addr_ipv6", "ll_addr", "link_local"]),
+ multicast_arp_drop=dict(type="bool", aliases=["mcast_arp_drop"]),
+ vmac=dict(type="str"),
+ optimize_wan_bandwidth=dict(type="bool", aliases=["wan_optimization", "opt_bandwidth"]),
+ mld_snoop_policy=dict(type="str", aliases=["mld_snoop", "mld_policy"]),
+ igmp_policy=dict(type="str", aliases=["igmp"]),
+ vlan=dict(type="str", aliases=["encap"]),
+ monitoring_policy=dict(type="str", aliases=["mon_pol", "monitoring_pol"]),
+ first_hop_security_policy=dict(type="str", aliases=["fhsp", "fhs_pol", "fhsp_name"]),
+ pim_source_filter=dict(type="str", aliases=["pim_source"]),
+ pim_destination_filter=dict(type="str", aliases=["pim_dest", "pim_destination"]),
)
module = AnsibleModule(
@@ -422,7 +566,47 @@ def main():
route_profile = module.params.get("route_profile")
route_profile_l3out = module.params.get("route_profile_l3out")
name_alias = module.params.get("name_alias")
+ host_based_routing = aci.boolean(module.params.get("host_based_routing"))
+ enable_rogue_except_mac = aci.boolean(module.params.get("enable_rogue_except_mac"))
+ allow_intersite_bum_traffic = aci.boolean(module.params.get("allow_intersite_bum_traffic"))
+ allow_intersite_l2_stretch = aci.boolean(module.params.get("allow_intersite_l2_stretch"))
+ allow_ipv6_multicast = aci.boolean(module.params.get("allow_ipv6_multicast"))
+ link_local_address = module.params.get("link_local_address")
+ multicast_arp_drop = aci.boolean(module.params.get("multicast_arp_drop"))
+ vmac = module.params.get("vmac")
+ optimize_wan_bandwidth = aci.boolean(module.params.get("optimize_wan_bandwidth"))
+ mld_snoop_policy = module.params.get("mld_snoop_policy")
+ igmp_policy = module.params.get("igmp_policy")
+ vlan = module.params.get("vlan")
+ monitoring_policy = module.params.get("monitoring_policy")
+ first_hop_security_policy = module.params.get("first_hop_security_policy")
+ pim_source_filter = module.params.get("pim_source_filter")
+ pim_destination_filter = module.params.get("pim_destination_filter")
+ child_classes = [
+ "fvRsCtx",
+ "fvRsIgmpsn",
+ "fvRsBDToNdP",
+ "fvRsBdToEpRet",
+ "fvRsBDToProfile",
+ "fvRsMldsn",
+ "igmpIfP",
+ "igmpRsIfPol",
+ "fvAccP",
+ "fvRsABDPolMonPol",
+ "fvRsBDToFhs",
+ ]
+ if pim_source_filter is not None or pim_destination_filter is not None:
+ # Only valid for APIC verion 5.2+
+ child_classes.extend(
+ [
+ "pimBDP",
+ "pimBDFilterPol",
+ "pimBDSrcFilterPol",
+ "pimBDDestFilterPol",
+ "rtdmcRsFilterToRtMapPol",
+ ]
+ )
aci.construct_url(
root_class=dict(
aci_class="fvTenant",
@@ -436,7 +620,7 @@ def main():
module_object=bd,
target_filter={"name": bd},
),
- child_classes=["fvRsCtx", "fvRsIgmpsn", "fvRsBDToNdP", "fvRsBdToEpRet", "fvRsBDToProfile"],
+ child_classes=child_classes,
)
aci.get_existing()
@@ -458,22 +642,52 @@ def main():
unkMacUcastAct=l2_unknown_unicast,
unkMcastAct=l3_unknown_multicast,
nameAlias=name_alias,
+ enableRogueExceptMac=enable_rogue_except_mac,
+ hostBasedRouting=host_based_routing,
+ intersiteBumTrafficAllow=allow_intersite_bum_traffic,
+ intersiteL2Stretch=allow_intersite_l2_stretch,
+ ipv6McastAllow=allow_ipv6_multicast,
+ llAddr=link_local_address,
+ mcastARPDrop=multicast_arp_drop,
+ vmac=vmac,
+ OptimizeWanBandwidth=optimize_wan_bandwidth,
)
if ipv6_l3_unknown_multicast is not None:
class_config["v6unkMcastAct"] = ipv6_l3_unknown_multicast
- aci.payload(
- aci_class="fvBD",
- class_config=class_config,
- child_configs=[
- {"fvRsCtx": {"attributes": {"tnFvCtxName": vrf}}},
- {"fvRsIgmpsn": {"attributes": {"tnIgmpSnoopPolName": igmp_snoop_policy}}},
- {"fvRsBDToNdP": {"attributes": {"tnNdIfPolName": ipv6_nd_policy}}},
- {"fvRsBdToEpRet": {"attributes": {"resolveAct": endpoint_retention_action, "tnFvEpRetPolName": endpoint_retention_policy}}},
- {"fvRsBDToProfile": {"attributes": {"tnL3extOutName": route_profile_l3out, "tnRtctrlProfileName": route_profile}}},
- ],
- )
+ child_configs = [
+ {"fvRsCtx": {"attributes": {"tnFvCtxName": vrf}}},
+ {"fvRsIgmpsn": {"attributes": {"tnIgmpSnoopPolName": igmp_snoop_policy}}},
+ {"fvRsMldsn": {"attributes": {"tnMldSnoopPolName": mld_snoop_policy}}},
+ {"fvRsBDToNdP": {"attributes": {"tnNdIfPolName": ipv6_nd_policy}}},
+ {"fvRsBdToEpRet": {"attributes": {"resolveAct": endpoint_retention_action, "tnFvEpRetPolName": endpoint_retention_policy}}},
+ {"fvRsBDToProfile": {"attributes": {"tnL3extOutName": route_profile_l3out, "tnRtctrlProfileName": route_profile}}},
+ {"fvRsBDToFhs": {"attributes": {"tnFhsBDPolName": first_hop_security_policy}}},
+ {"fvAccP": {"attributes": {"encap": vlan}}},
+ {"fvRsABDPolMonPol": {"attributes": {"tnMonEPGPolName": monitoring_policy}}},
+ ]
+
+ if igmp_policy is not None:
+ igmp_policy_tdn = "" if igmp_policy == "" else "uni/tn-{0}/igmpIfPol-{1}".format(tenant, igmp_policy)
+ child_configs.append({"igmpIfP": {"attributes": {}, "children": [{"igmpRsIfPol": {"attributes": {"tDn": igmp_policy_tdn}}}]}})
+ if pim_source_filter is not None or pim_destination_filter is not None:
+ pim_bd = {"pimBDP": {"attributes": {}, "children": []}}
+ pim_filter_pol = {"pimBDFilterPol": {"attributes": {}, "children": []}}
+ if pim_source_filter is not None:
+ pim_source_filter_tdn = "" if pim_source_filter == "" else "uni/tn-{0}/rtmap-{1}".format(tenant, pim_source_filter)
+ pim_filter_pol["pimBDFilterPol"]["children"].append(
+ {"pimBDSrcFilterPol": {"attributes": {}, "children": [{"rtdmcRsFilterToRtMapPol": {"attributes": {"tDn": pim_source_filter_tdn}}}]}}
+ )
+ if pim_destination_filter is not None:
+ pim_destination_filter_tdn = "" if pim_destination_filter == "" else "uni/tn-{0}/rtmap-{1}".format(tenant, pim_destination_filter)
+ pim_filter_pol["pimBDFilterPol"]["children"].append(
+ {"pimBDDestFilterPol": {"attributes": {}, "children": [{"rtdmcRsFilterToRtMapPol": {"attributes": {"tDn": pim_destination_filter_tdn}}}]}}
+ )
+ pim_bd["pimBDP"]["children"].append(pim_filter_pol)
+ child_configs.append(pim_bd)
+
+ aci.payload(aci_class="fvBD", class_config=class_config, child_configs=child_configs)
aci.get_diff(aci_class="fvBD")
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_bd_rogue_exception_mac.py b/ansible_collections/cisco/aci/plugins/modules/aci_bd_rogue_exception_mac.py
new file mode 100644
index 000000000..8174f00db
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_bd_rogue_exception_mac.py
@@ -0,0 +1,299 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2024, Samita Bhattacharjee (@samitab) <samitab@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": "certified"}
+
+DOCUMENTATION = r"""
+---
+module: aci_bd_rogue_exception_mac
+short_description: Manage Rogue Exception MAC (fv:RogueExceptionMac)
+description:
+- Manage Rogue Exception MACs in BD's on Cisco ACI fabrics.
+- Only available in APIC version 5.2 or later.
+options:
+ bd:
+ description:
+ - The name of the Bridge Domain.
+ type: str
+ aliases: [ bd_name, bridge_domain ]
+ tenant:
+ description:
+ - The name of the Tenant.
+ type: str
+ aliases: [ tenant_name ]
+ mac:
+ description:
+ - MAC address to except from Rogue processing.
+ type: str
+ description:
+ description:
+ - The description for the Rogue Exception MAC.
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+
+notes:
+- The C(tenant) and C(bd) used must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant) module and M(cisco.aci.aci_bd) can be used for these.
+seealso:
+- module: cisco.aci.aci_bd
+- module: cisco.aci.aci_tenant
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(fv:RogueExceptionMac).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Samita Bhattacharjee (@samitab)
+"""
+
+EXAMPLES = r"""
+- name: Create a Rogue Exception MAC
+ cisco.aci.aci_bd_rogue_exception_mac:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: production
+ bd: database
+ mac: "AA:BB:CC:DD:EE:11"
+ description: 1st MAC
+ state: present
+ delegate_to: localhost
+
+- name: Get all Rogue Exception MACs
+ cisco.aci.aci_bd_rogue_exception_mac:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+
+- name: Get all Rogue Exception MACs in specified Tenant
+ cisco.aci.aci_bd_rogue_exception_mac:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: production
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Get specific Rogue Exception MAC
+ cisco.aci.aci_bd_rogue_exception_mac:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: production
+ bd: database
+ mac: "AA:BB:CC:DD:EE:11"
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Remove a Rogue Exception MAC from a Bridge Domain
+ cisco.aci.aci_bd_rogue_exception_mac:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: production
+ bd: database
+ mac: "AA:BB:CC:DD:EE:11"
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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
+
+
+def main():
+ argument_spec = aci_argument_spec()
+ argument_spec.update(aci_annotation_spec())
+ argument_spec.update(
+ bd=dict(type="str", aliases=["bd_name", "bridge_domain"]), # Not required for querying all objects
+ tenant=dict(type="str", aliases=["tenant_name"]), # Not required for querying all objects
+ mac=dict(type="str"), # Not required for querying all objects
+ description=dict(type="str", aliases=["descr"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "present", ["bd", "mac", "tenant"]],
+ ["state", "absent", ["bd", "mac", "tenant"]],
+ ],
+ )
+
+ aci = ACIModule(module)
+
+ description = module.params.get("description")
+ tenant = module.params.get("tenant")
+ bd = module.params.get("bd")
+ mac = module.params.get("mac")
+ state = module.params.get("state")
+
+ 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="fvBD",
+ aci_rn="BD-{0}".format(bd),
+ module_object=bd,
+ target_filter={"name": bd},
+ ),
+ subclass_2=dict(
+ aci_class="fvRogueExceptionMac",
+ aci_rn="rgexpmac-{0}".format(mac),
+ module_object=mac,
+ target_filter={"mac": mac},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class="fvRogueExceptionMac",
+ class_config=dict(
+ descr=description,
+ mac=mac,
+ ),
+ )
+
+ aci.get_diff(aci_class="fvRogueExceptionMac")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_bd_to_netflow_monitor_policy.py b/ansible_collections/cisco/aci/plugins/modules/aci_bd_to_netflow_monitor_policy.py
new file mode 100644
index 000000000..5e79a072c
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_bd_to_netflow_monitor_policy.py
@@ -0,0 +1,292 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2024, Samita Bhattacharjee (@samitab) <samitab@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": "certified"}
+
+DOCUMENTATION = r"""
+---
+module: aci_bd_to_netflow_monitor_policy
+short_description: Bind Bridge Domain to Netflow Monitor Policy (fv:RsBDToNetflowMonitorPol)
+description:
+- Bind Bridge Domain to Netflow Monitor Policy on Cisco ACI fabrics.
+options:
+ bd:
+ description:
+ - The name of the Bridge Domain.
+ type: str
+ aliases: [ bd_name, bridge_domain ]
+ tenant:
+ description:
+ - The name of the Tenant.
+ type: str
+ aliases: [ tenant_name ]
+ netflow_monitor_policy:
+ description:
+ - The name of the Netflow Monitor Policy.
+ type: str
+ aliases: [ netflow_monitor, netflow_monitor_name, name ]
+ filter_type:
+ description:
+ - Choice of filter type while setting NetFlow Monitor Policies.
+ type: str
+ choices: [ce, ipv4, ipv6, unspecified]
+ aliases: [ filter, type ]
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+
+notes:
+- The C(bd) and C(netflow_monitor_policy) parameters should exist before using this module.
+ The M(cisco.aci.aci_bd) and C(aci_netflow_monitor_policy) can be used for this.
+seealso:
+- module: cisco.aci.aci_bd
+- module: cisco.aci.aci_netflow_monitor_policy
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(fv:RsBDToNetflowMonitorPol).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Samita Bhattacharjee (@samitab)
+"""
+
+EXAMPLES = r"""
+- name: Bind Bridge Domain to Netflow Monitor Policy
+ cisco.aci.aci_bd_to_netflow_monitor_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ validate_certs: false
+ bd: web_servers
+ netflow_monitor_policy: prod_netflow_monitor_policy
+ tenant: prod
+ filter_type: ipv4
+ state: present
+ delegate_to: localhost
+
+- name: Query all Bridge Domains bound to Netflow Monitor Policy
+ cisco.aci.aci_bd_to_netflow_monitor_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ validate_certs: true
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query specific Bridge Domain(s) bound to an Netflow Monitor Policy
+ cisco.aci.aci_bd_to_netflow_monitor_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ validate_certs: true
+ bd: web_servers
+ netflow_monitor_policy: prod_netflow_monitor_policy
+ tenant: prod
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Unbind Bridge Domain from Netflow Monitor Policy
+ cisco.aci.aci_bd_to_netflow_monitor_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ validate_certs: true
+ bd: web_servers
+ netflow_monitor_policy: prod_netflow_monitor_policy
+ tenant: prod
+ filter_type: ipv4
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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
+
+
+def main():
+ argument_spec = aci_argument_spec()
+ argument_spec.update(aci_annotation_spec())
+ argument_spec.update(
+ bd=dict(type="str", aliases=["bd_name", "bridge_domain"]), # Not required for querying all objects
+ netflow_monitor_policy=dict(type="str", aliases=["netflow_monitor", "netflow_monitor_name", "name"]), # Not required for querying all objects
+ filter_type=dict(type="str", choices=["ce", "ipv4", "ipv6", "unspecified"], aliases=["filter", "type"]), # Not required for querying all objects
+ tenant=dict(type="str", aliases=["tenant_name"]), # Not required for querying all objects
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "present", ["bd", "netflow_monitor_policy", "tenant", "filter_type"]],
+ ["state", "absent", ["bd", "netflow_monitor_policy", "tenant", "filter_type"]],
+ ],
+ )
+
+ bd = module.params.get("bd")
+ netflow_monitor_policy = module.params.get("netflow_monitor_policy")
+ filter_type = module.params.get("filter_type")
+ state = module.params.get("state")
+ tenant = module.params.get("tenant")
+
+ 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="fvBD",
+ aci_rn="BD-{0}".format(bd),
+ module_object=bd,
+ target_filter={"name": bd},
+ ),
+ subclass_2=dict(
+ aci_class="fvRsBDToNetflowMonitorPol",
+ aci_rn="rsBDToNetflowMonitorPol-[{0}]-{1}".format(netflow_monitor_policy, filter_type),
+ module_object=netflow_monitor_policy,
+ target_filter={"tnNetflowMonitorPolName": netflow_monitor_policy},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class="fvRsBDToNetflowMonitorPol",
+ class_config=dict(tnNetflowMonitorPolName=netflow_monitor_policy, fltType=filter_type),
+ )
+
+ aci.get_diff(aci_class="fvRsBDToNetflowMonitorPol")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_bfd_multihop_node_policy.py b/ansible_collections/cisco/aci/plugins/modules/aci_bfd_multihop_node_policy.py
new file mode 100644
index 000000000..f684ba15d
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_bfd_multihop_node_policy.py
@@ -0,0 +1,320 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Anvitha Jain (@anvjain) <anvjain@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_bfd_multihop_node_policy
+short_description: Manage BFD Multihop Node policies (bfd:MhNodePol)
+description:
+- Manage BFD Multihop Node policy configuration on Cisco ACI fabrics.
+- Only available in APIC version 5.2 or later.
+options:
+ tenant:
+ description:
+ - Name of an existing tenant
+ type: str
+ name:
+ description:
+ - Name of the BFD Multihop Node policy
+ type: str
+ aliases: [ bfd_multihop_node_policy ]
+ description:
+ description:
+ - Description of the BFD Multihop Node policy
+ type: str
+ admin_state:
+ description:
+ - Admin state of the BFD Multihop Node policy
+ - APIC sets the default value to enabled
+ type: str
+ choices: [ enabled, disabled ]
+ detection_multiplier:
+ description:
+ - Detection multiplier of the BFD Multihop Node policy
+ - APIC sets the default value to 3
+ - Allowed range is 1-50
+ type: int
+ min_transmit_interval:
+ description:
+ - Minimum transmit (Tx) interval of the BFD Multihop Node policy
+ - APIC sets the default value to 250
+ - Allowed range is 250-999
+ type: int
+ min_receive_interval:
+ description:
+ - Minimum receive (Rx) interval of the BFD Multihop Node policy
+ - APIC sets the default value to 250
+ - Allowed range is 250-999
+ type: int
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+
+notes:
+- The C(tenant) must exist before using this module in your playbook
+ The M(cisco.aci.aci_tenant) modules can be used for this
+seealso:
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(bfd:MhNodePol)
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+- module: cisco.aci.aci_tenant
+author:
+- Anvitha Jain (@anvjain)
+"""
+
+EXAMPLES = r"""
+- name: Add a new BFD Multihop Node policy
+ cisco.aci.aci_bfd_multihop_node_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: ansible_tenant
+ name: ansible_bfd_multihop_node_policy
+ description: Ansible BFD Multihop Node Policy
+ state: present
+ delegate_to: localhost
+
+- name: Remove a BFD Multihop Node policy
+ cisco.aci.aci_bfd_multihop_node_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: ansible_tenant
+ name: ansible_bfd_multihop_node_policy
+ state: absent
+ delegate_to: localhost
+
+- name: Query a BFD Multihop Node policy
+ cisco.aci.aci_bfd_multihop_node_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: ansible_tenant
+ name: my_dhcp_relay
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all BFD Multihop Node policies in a specific tenant
+ cisco.aci.aci_bfd_multihop_node_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: ansible_tenant
+ state: query
+ delegate_to: localhost
+ register: query_result
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+ 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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class "/></imdata>'
+ 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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+ 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
+
+
+def main():
+ argument_spec = aci_argument_spec()
+ argument_spec.update(aci_annotation_spec())
+ argument_spec.update(
+ name=dict(type="str", aliases=["bfd_multihop_node_policy"]),
+ description=dict(type="str"),
+ admin_state=dict(type="str", choices=["enabled", "disabled"]),
+ detection_multiplier=dict(type="int"),
+ min_transmit_interval=dict(type="int"),
+ min_receive_interval=dict(type="int"),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ tenant=dict(type="str"),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["name", "tenant"]],
+ ["state", "present", ["name", "tenant"]],
+ ],
+ )
+
+ name = module.params.get("name")
+ description = module.params.get("description")
+ state = module.params.get("state")
+ tenant = module.params.get("tenant")
+ admin_state = module.params.get("admin_state")
+ detection_multiplier = module.params.get("detection_multiplier")
+ min_transmit_interval = module.params.get("min_transmit_interval")
+ min_receive_interval = module.params.get("min_receive_interval")
+
+ 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="bfdMhNodePol",
+ aci_rn="bfdMhNodePol-{0}".format(name),
+ module_object=name,
+ target_filter={"name": name},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ class_config = dict(
+ name=name,
+ descr=description,
+ adminSt=admin_state,
+ )
+
+ if detection_multiplier and detection_multiplier not in range(1, 50):
+ aci.fail_json(msg='The "detection_multiplier" must be a value between 1 and 50')
+ else:
+ class_config["detectMult"] = detection_multiplier
+ if min_transmit_interval and min_transmit_interval not in range(250, 999):
+ aci.fail_json(msg='The "min_transmit_interval" must be a value between 250 and 999')
+ else:
+ class_config["minTxIntvl"] = min_transmit_interval
+ if min_receive_interval and min_receive_interval not in range(250, 999):
+ aci.fail_json(msg='The "min_receive_interval" must be a value between 250 and 999')
+ else:
+ class_config["minRxIntvl"] = min_receive_interval
+
+ aci.payload(
+ aci_class="bfdMhNodePol",
+ class_config=class_config,
+ )
+
+ aci.get_diff(aci_class="bfdMhNodePol")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_bgp_address_family_context_policy.py b/ansible_collections/cisco/aci/plugins/modules/aci_bgp_address_family_context_policy.py
new file mode 100644
index 000000000..1d69de6f6
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_bgp_address_family_context_policy.py
@@ -0,0 +1,382 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@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": "certified"}
+
+DOCUMENTATION = r"""
+---
+module: aci_bgp_address_family_context_policy
+short_description: Manage BGP address family context policy (bgp:CtxAfPol)
+description:
+- Manage BGP address family context policies for the Tenants on Cisco ACI fabrics.
+options:
+ tenant:
+ description:
+ - The name of an existing tenant.
+ type: str
+ aliases: [ tenant_name ]
+ address_family_context_policy:
+ description:
+ - The name of the BGP address family context policy.
+ type: str
+ aliases: [ address_family_context_name, name ]
+ host_route_leak:
+ description:
+ - The control state.
+ - The option to enable/disable host route leak.
+ - The APIC defaults to C(false) when unset during creation.
+ type: bool
+ ebgp_distance:
+ description:
+ - The administrative distance of eBGP routes.
+ - The APIC defaults to C(20) when unset during creation.
+ type: int
+ ibgp_distance:
+ description:
+ - The administrative distance of iBGP routes.
+ - The APIC defaults to C(200) when unset during creation.
+ type: int
+ local_distance:
+ description:
+ - The administrative distance of local routes.
+ - The APIC defaults to C(220) when unset during creation.
+ type: int
+ ebgp_max_ecmp:
+ description:
+ - The eBGP max-path.
+ - The APIC defaults to C(16) when unset during creation.
+ type: int
+ ibgp_max_ecmp:
+ description:
+ - The iBGP max-path.
+ - The APIC defaults to C(16) when unset during creation.
+ type: int
+ local_max_ecmp:
+ description:
+ - The maximum number of equal-cost local paths for redist.
+ - The APIC defaults to C(0) when unset during creation.
+ - Can not be configured for APIC version 4.2(7s) and prior.
+ type: int
+ bgp_add_path_capability:
+ description:
+ - The neighbor system capability.
+ - To delete this attribute, pass an empty string.
+ - Can not be configured for APIC version 6.0(2h) and prior.
+ type: str
+ choices: [ receive, send, "" ]
+ description:
+ description:
+ - Description for the BGP protocol profile.
+ 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) used must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant) module 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(bgp:CtxAfPol).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Gaspard Micol (@gmicol)
+"""
+
+EXAMPLES = r"""
+- name: Create a BGP address family context policy
+ cisco.aci.aci_bgp_address_family_context_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ bgp_address_family_context_policy: my_bgp_address_family_context_policy
+ host_route_leak: true
+ ebgp_distance: 40
+ ibgp_distance: 210
+ local_distance: 215
+ ebgp_max_ecmp: 32
+ ibgp_max_ecmp: 32
+ local_max_ecmp: 1
+ bgp_add_path_capability: receive
+ tenant: production
+ state: present
+ delegate_to: localhost
+
+- name: Delete BGP address family context policy's child
+ cisco.aci.aci_bgp_address_family_context_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ bgp_address_family_context_policy: my_bgp_address_family_context_policy
+ bgp_add_path_capability: ""
+ tenant: production
+ state: absent
+ delegate_to: localhost
+
+- name: Delete a BGP address family context policy
+ cisco.aci.aci_bgp_address_family_context_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ bgp_address_family_context_policy: my_bgp_address_family_context_policy
+ tenant: production
+ state: absent
+ delegate_to: localhost
+
+- name: Query all BGP address family context policies
+ cisco.aci.aci_bgp_address_family_context_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query a specific BGP address family context policy
+ cisco.aci.aci_bgp_address_family_context_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ bgp_address_family_context_policy: my_bgp_address_family_context_policy
+ tenant: production
+ state: query
+ delegate_to: localhost
+ register: query_result
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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
+ address_family_context_policy=dict(type="str", aliases=["address_family_context_name", "name"]), # Not required for querying all objects
+ host_route_leak=dict(type="bool"),
+ ebgp_distance=dict(type="int"),
+ ibgp_distance=dict(type="int"),
+ local_distance=dict(type="int"),
+ ebgp_max_ecmp=dict(type="int"),
+ ibgp_max_ecmp=dict(type="int"),
+ local_max_ecmp=dict(type="int"),
+ bgp_add_path_capability=dict(type="str", choices=["receive", "send", ""]),
+ description=dict(type="str", aliases=["descr"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ name_alias=dict(type="str"),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["address_family_context_policy", "tenant"]],
+ ["state", "present", ["address_family_context_policy", "tenant"]],
+ ],
+ )
+
+ aci = ACIModule(module)
+
+ address_family_context_policy = module.params.get("address_family_context_policy")
+ host_route_leak = aci.boolean(module.params.get("host_route_leak"), "host-rt-leak", "")
+ ebgp_distance = module.params.get("ebgp_distance")
+ ibgp_distance = module.params.get("ibgp_distance")
+ local_distance = module.params.get("local_distance")
+ ebgp_max_ecmp = module.params.get("ebgp_max_ecmp")
+ ibgp_max_ecmp = module.params.get("ibgp_max_ecmp")
+ local_max_ecmp = module.params.get("local_max_ecmp")
+ bgp_add_path_capability = module.params.get("bgp_add_path_capability")
+ description = module.params.get("description")
+ state = module.params.get("state")
+ tenant = module.params.get("tenant")
+ name_alias = module.params.get("name_alias")
+
+ child_classes = []
+ if bgp_add_path_capability is not None:
+ child_classes.append("bgpCtxAddlPathPol")
+
+ 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="bgpCtxAfPol",
+ aci_rn="bgpCtxAfP-{0}".format(address_family_context_policy),
+ module_object=address_family_context_policy,
+ target_filter={"name": address_family_context_policy},
+ ),
+ child_classes=child_classes,
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ child_configs = []
+ if bgp_add_path_capability is not None:
+ if bgp_add_path_capability == "" and isinstance(aci.existing, list) and len(aci.existing) > 0:
+ for child in aci.existing[0].get("bgpCtxAfPol", {}).get("children", {}):
+ if child.get("bgpCtxAddlPathPol"):
+ child_configs.append(dict(bgpCtxAddlPathPol=dict(attributes=dict(status="deleted"))))
+ elif bgp_add_path_capability != "":
+ child_configs.append(dict(bgpCtxAddlPathPol=dict(attributes=dict(capability=bgp_add_path_capability))))
+
+ aci.payload(
+ aci_class="bgpCtxAfPol",
+ class_config=dict(
+ name=address_family_context_policy,
+ ctrl=host_route_leak,
+ eDist=ebgp_distance,
+ iDist=ibgp_distance,
+ localDist=local_distance,
+ maxEcmp=ebgp_max_ecmp,
+ maxEcmpIbgp=ibgp_max_ecmp,
+ maxLocalEcmp=local_max_ecmp,
+ descr=description,
+ nameAlias=name_alias,
+ ),
+ child_configs=child_configs,
+ )
+
+ aci.get_diff(aci_class="bgpCtxAfPol")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_bgp_best_path_policy.py b/ansible_collections/cisco/aci/plugins/modules/aci_bgp_best_path_policy.py
index a8b5c0a6a..936442aaa 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_bgp_best_path_policy.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_bgp_best_path_policy.py
@@ -15,7 +15,7 @@ DOCUMENTATION = r"""
module: aci_bgp_best_path_policy
short_description: Manage BGP Best Path policy (bgp:BestPathCtrlPol)
description:
-- Manage BGP Best Path policies for Tenants on Cisco ACI fabrics.
+- Manage BGP Best Path policies for the Tenants on Cisco ACI fabrics.
options:
tenant:
description:
@@ -24,7 +24,7 @@ options:
aliases: [ tenant_name ]
bgp_best_path_policy:
description:
- - The name of the best path policy.
+ - The name of the BGP best path policy.
type: str
aliases: [ bgp_best_path_policy_name, name ]
best_path_control:
@@ -37,7 +37,7 @@ options:
aliases: [as_path_control]
description:
description:
- - Description for the bgp protocol profile.
+ - Description for the BGP best path policy.
type: str
aliases: [ descr ]
state:
@@ -74,7 +74,7 @@ EXAMPLES = r"""
host: apic
username: admin
password: SomeSecretPassword
- bgp_protocol_profile: my_bgp_best_path_policy
+ bgp_best_path_policy: my_bgp_best_path_policy
best_path_control: enable
tenant: production
state: present
@@ -85,7 +85,7 @@ EXAMPLES = r"""
host: apic
username: admin
password: SomeSecretPassword
- bgp_protocol_profile: my_bgp_best_path_policy
+ bgp_best_path_policy: my_bgp_best_path_policy
tenant: production
state: absent
delegate_to: localhost
@@ -104,7 +104,7 @@ EXAMPLES = r"""
host: apic
username: admin
password: SomeSecretPassword
- bgp_protocol_profile: my_bgp_best_path_policy
+ bgp_best_path_policy: my_bgp_best_path_policy
tenant: production
state: query
delegate_to: localhost
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_bgp_peer_prefix_policy.py b/ansible_collections/cisco/aci/plugins/modules/aci_bgp_peer_prefix_policy.py
new file mode 100644
index 000000000..7719fff7a
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_bgp_peer_prefix_policy.py
@@ -0,0 +1,322 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@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": "certified"}
+
+DOCUMENTATION = r"""
+---
+module: aci_bgp_peer_prefix_policy
+short_description: Manage BGP peer prefix policy (bgp:PeerPfxPol)
+description:
+- Manage BGP peer prefix policies for the Tenants on Cisco ACI fabrics.
+options:
+ tenant:
+ description:
+ - The name of an existing tenant.
+ type: str
+ aliases: [ tenant_name ]
+ peer_prefix_policy:
+ description:
+ - The name of the BGP peer prefix policy.
+ type: str
+ aliases: [ peer_prefix_policy_name, name ]
+ action:
+ description:
+ - The action to be performed when the maximum prefix limit is reached.
+ - The APIC defaults to C(reject) when unset during creation.
+ type: str
+ choices: [ log, reject, restart, shut ]
+ maximum_number_prefix:
+ description:
+ - The maximum number of prefixes allowed from the peer.
+ - The APIC defaults to C(20000) when unset during creation.
+ type: int
+ aliases: [ max_prefix, max_num_prefix ]
+ restart_time:
+ description:
+ - The period of time in minutes before restarting the peer when the prefix limit is reached.
+ - Used only if C(action) is set to C(restart).
+ - The APIC defaults to C(infinite) when unset during creation.
+ type: str
+ threshold:
+ description:
+ - The threshold percentage of the maximum number of prefixes before a warning is issued.
+ - For example, if the maximum number of prefixes is 10 and the threshold is 70%, a warning is issued when the number of prefixes exceeds 7 (70%).
+ - The APIC defaults to C(75) when unset during creation.
+ type: int
+ aliases: [ thresh ]
+ description:
+ description:
+ - Description for the BGP peer prefix policy.
+ 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) used must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant) module 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(bgp:PeerPfxPol).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Gaspard Micol (@gmicol)
+"""
+
+EXAMPLES = r"""
+- name: Create a BGP peer prefix policy
+ cisco.aci.aci_bgp_peer_prefix_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ peer_prefix_policy: my_bgp_peer_prefix_policy
+ action: restart
+ restart_time: 10
+ max_prefix: 10000
+ threshold: 80
+ tenant: production
+ state: present
+ delegate_to: localhost
+
+- name: Delete a BGP peer prefix policy
+ cisco.aci.aci_bgp_peer_prefix_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ peer_prefix_policy: my_bgp_peer_prefix_policy
+ tenant: production
+ state: absent
+ delegate_to: localhost
+
+- name: Query all BGP peer prefix policies
+ cisco.aci.aci_bgp_peer_prefix_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query a specific BGP peer prefix policy
+ cisco.aci.aci_bgp_peer_prefix_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ peer_prefix_policy: my_bgp_peer_prefix_policy
+ tenant: production
+ state: query
+ delegate_to: localhost
+ register: query_result
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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
+ peer_prefix_policy=dict(type="str", aliases=["peer_prefix_policy_name", "name"]), # Not required for querying all objects
+ action=dict(type="str", choices=["log", "reject", "restart", "shut"]),
+ maximum_number_prefix=dict(type="int", aliases=["max_prefix", "max_num_prefix"]),
+ restart_time=dict(type="str"),
+ threshold=dict(type="int", aliases=["thresh"]),
+ description=dict(type="str", aliases=["descr"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ name_alias=dict(type="str"),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["peer_prefix_policy", "tenant"]],
+ ["state", "present", ["peer_prefix_policy", "tenant"]],
+ ],
+ )
+
+ peer_prefix_policy = module.params.get("peer_prefix_policy")
+ action = module.params.get("action")
+ maximum_number_prefix = module.params.get("maximum_number_prefix")
+ restart_time = module.params.get("restart_time")
+ threshold = module.params.get("threshold")
+ description = module.params.get("description")
+ state = module.params.get("state")
+ tenant = module.params.get("tenant")
+ 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="bgpPeerPfxPol",
+ aci_rn="bgpPfxP-{0}".format(peer_prefix_policy),
+ module_object=peer_prefix_policy,
+ target_filter={"name": peer_prefix_policy},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class="bgpPeerPfxPol",
+ class_config=dict(
+ name=peer_prefix_policy,
+ action=action,
+ maxPfx=maximum_number_prefix,
+ restartTime=restart_time,
+ thresh=threshold,
+ descr=description,
+ nameAlias=name_alias,
+ ),
+ )
+
+ aci.get_diff(aci_class="bgpPeerPfxPol")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_bgp_route_summarization_policy.py b/ansible_collections/cisco/aci/plugins/modules/aci_bgp_route_summarization_policy.py
new file mode 100644
index 000000000..6e10e92c6
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_bgp_route_summarization_policy.py
@@ -0,0 +1,310 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@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": "certified"}
+
+DOCUMENTATION = r"""
+---
+module: aci_bgp_route_summarization_policy
+short_description: Manage BGP route summarization policy (bgp:RtSummPol)
+description:
+- Manage BGP route summarization policies for the Tenants on Cisco ACI fabrics.
+options:
+ tenant:
+ description:
+ - The name of an existing tenant.
+ type: str
+ aliases: [ tenant_name ]
+ route_summarization_policy:
+ description:
+ - The name of the BGP route summarization policy.
+ type: str
+ aliases: [ route_summarization_policy_name, name ]
+ address_type_af_control:
+ description:
+ - The Ucast/Mcast address type AF control.
+ - The APIC defaults to C(af-ucast) when unset during creation.
+ - Can not be configured for APIC version 4.2(7s) or prior.
+ type: list
+ elements: str
+ choices: [ af-label-ucast, af-ucast, af-mcast ]
+ aliases: [ address_type_control ]
+ control_state:
+ description:
+ - The summary control.
+ - The C(summary_only) option can not be configured for APIC version 4.2(7s) or prior.
+ type: list
+ elements: str
+ choices: [ as-set, summary-only ]
+ aliases: [ summary_control, control ]
+ description:
+ description:
+ - Description for the BGP route summarization policy.
+ 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) used must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant) module 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(bgp:RtSummPol).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Gaspard Micol (@gmicol)
+"""
+
+EXAMPLES = r"""
+- name: Create a BGP route summarization policy
+ cisco.aci.aci_bgp_route_summarization_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ route_summarization_policy: my_route_summarization_policy
+ address_type_af_control: [af-mcast, af-ucast]
+ control_state: [as-set, summary-only]
+ tenant: production
+ state: present
+ delegate_to: localhost
+
+- name: Delete a BGP route summarization policy
+ cisco.aci.aci_bgp_route_summarization_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ route_summarization_policy: my_route_summarization_policy
+ tenant: production
+ state: absent
+ delegate_to: localhost
+
+- name: Query all BGP route summarization policies
+ cisco.aci.aci_bgp_route_summarization_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query a specific BGP route summarization policy
+ cisco.aci.aci_bgp_route_summarization_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ route_summarization_policy: my_route_summarization_policy
+ tenant: production
+ state: query
+ delegate_to: localhost
+ register: query_result
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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
+ route_summarization_policy=dict(type="str", aliases=["route_summarization_policy_name", "name"]), # Not required for querying all objects
+ address_type_af_control=dict(type="list", elements="str", choices=["af-label-ucast", "af-ucast", "af-mcast"], aliases=["address_type_control"]),
+ control_state=dict(type="list", elements="str", choices=["as-set", "summary-only"], aliases=["summary_control", "control"]),
+ description=dict(type="str", aliases=["descr"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ name_alias=dict(type="str"),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["route_summarization_policy", "tenant"]],
+ ["state", "present", ["route_summarization_policy", "tenant"]],
+ ],
+ )
+
+ route_summarization_policy = module.params.get("route_summarization_policy")
+ address_type_af_control = ",".join(module.params.get("address_type_af_control")) if module.params.get("address_type_af_control") else None
+ control_state = ",".join(module.params.get("control_state")) if module.params.get("control_state") else None
+ description = module.params.get("description")
+ state = module.params.get("state")
+ tenant = module.params.get("tenant")
+ 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="bgpRtSummPol",
+ aci_rn="bgprtsum-{0}".format(route_summarization_policy),
+ module_object=route_summarization_policy,
+ target_filter={"name": route_summarization_policy},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ class_config = dict(
+ name=route_summarization_policy,
+ ctrl=control_state,
+ descr=description,
+ nameAlias=name_alias,
+ )
+
+ if address_type_af_control is not None:
+ class_config.update(dict(addrTCtrl=address_type_af_control))
+
+ aci.payload(
+ aci_class="bgpRtSummPol",
+ class_config=class_config,
+ )
+
+ aci.get_diff(aci_class="bgpRtSummPol")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_bgp_rr_asn.py b/ansible_collections/cisco/aci/plugins/modules/aci_bgp_rr_asn.py
index 4eae25e3d..e728e41b6 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_bgp_rr_asn.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_bgp_rr_asn.py
@@ -13,9 +13,9 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_bgp_rr_asn
-short_description: Manage BGP Route Reflector ASN.
+short_description: Manage BGP Route Reflector ASN (bgp:AsP)
description:
-- Manage the BGP Autonomous System Number of the fabric (bgpAsP).
+- Manage the BGP Autonomous System Number of the fabric.
- This module is specifically for fabric BGP, for L3Out BGP use the aci_l3out_bgp_peer module
options:
asn:
@@ -35,7 +35,7 @@ extends_documentation_fragment:
seealso:
- name: APIC Management Information Model reference
- description: More information about the internal APIC class B(bgpAsP).
+ description: More information about the internal APIC class B(bgp:AsP).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Tim Cragg (@timcragg)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_bgp_rr_node.py b/ansible_collections/cisco/aci/plugins/modules/aci_bgp_rr_node.py
index 1f37b769c..90139b026 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_bgp_rr_node.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_bgp_rr_node.py
@@ -13,9 +13,9 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_bgp_rr_node
-short_description: Manage BGP Route Reflector objects.
+short_description: Manage BGP Route Reflector objects (bgp:RRNodePEp)
description:
-- Manage ACI BGP Route Reflector Nodes (bgpRRNodePEp).
+- Manage ACI BGP Route Reflector Nodes.
options:
node_id:
description:
@@ -42,7 +42,7 @@ extends_documentation_fragment:
seealso:
- name: APIC Management Information Model reference
- description: More information about the internal APIC class B(bgpRRNodePEp).
+ description: More information about the internal APIC class B(bgp:RRNodePEp).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Tim Cragg (@timcragg)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_bgp_timers_policy.py b/ansible_collections/cisco/aci/plugins/modules/aci_bgp_timers_policy.py
index c8d6c54b0..9a62a8d4f 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_bgp_timers_policy.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_bgp_timers_policy.py
@@ -15,7 +15,7 @@ DOCUMENTATION = r"""
module: aci_bgp_timers_policy
short_description: Manage BGP timers policy (bgp:CtxPol)
description:
-- Manage BGP timers policies for Tenants on Cisco ACI fabrics.
+- Manage BGP timers policies for the Tenants on Cisco ACI fabrics.
options:
tenant:
description:
@@ -24,7 +24,7 @@ options:
aliases: [ tenant_name ]
bgp_timers_policy:
description:
- - The name of the bgp timers policy.
+ - The name of the BGP timers policy.
type: str
aliases: [ bgp_timers_policy_name, name ]
graceful_restart_controls:
@@ -57,7 +57,7 @@ options:
type: int
description:
description:
- - Description for the bgp protocol profile.
+ - Description for the BGP timers policy.
type: str
aliases: [ descr ]
state:
@@ -94,7 +94,7 @@ EXAMPLES = r"""
host: apic
username: admin
password: SomeSecretPassword
- bgp_protocol_profile: my_bgp_timers_policy
+ bgp_timers_policy: my_bgp_timers_policy
graceful_restart_controls: complete
hold_interval: 360
keepalive_interval: 120
@@ -109,7 +109,7 @@ EXAMPLES = r"""
host: apic
username: admin
password: SomeSecretPassword
- bgp_protocol_profile: my_bgp_timers_policy
+ bgp_timers_policy: my_bgp_timers_policy
tenant: production
state: absent
delegate_to: localhost
@@ -128,7 +128,7 @@ EXAMPLES = r"""
host: apic
username: admin
password: SomeSecretPassword
- bgp_protocol_profile: my_bgp_timers_policy
+ bgp_timers_policy: my_bgp_timers_policy
tenant: production
state: query
delegate_to: localhost
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_cloud_subnet.py b/ansible_collections/cisco/aci/plugins/modules/aci_cloud_subnet.py
index 31845f629..bfdad0a33 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_cloud_subnet.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_cloud_subnet.py
@@ -3,6 +3,7 @@
# Copyright: (c) 2020, nkatarmal-crest <nirav.katarmal@crestdatasys.com>
# Copyright: (c) 2020, Cindy Zhao <cizhao@cisco.com>
+# Copyright: (c) 2024, Samita Bhattacharjee <samitab@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
@@ -21,6 +22,7 @@ notes:
author:
- Nirav (@nirav)
- Cindy Zhao (@cizhao)
+- Samita Bhattacharjee (@samitab)
options:
name:
description:
@@ -54,17 +56,24 @@ options:
- Address of cloud cidr.
type: str
required: true
- availability_zone:
+ aws_availability_zone:
description:
- The cloud zone which is attached to the given cloud context profile.
- - Only used when it is an aws cloud apic.
+ - Only used when it is an AWS Cloud APIC.
type: str
+ aliases: [availability_zone, av_zone, zone]
vnet_gateway:
description:
- Determine if a vNet Gateway Router will be deployed or not.
- - Only used when it is an azure cloud apic.
+ - Only used when it is an Azure Cloud APIC.
type: bool
default: false
+ azure_region:
+ description:
+ - The Azure cloud region to attach this subnet to.
+ - Only used when it is an Azure Cloud APIC.
+ type: str
+ aliases: [az_region]
state:
description:
- Use C(present) or C(absent) for adding or removing.
@@ -78,7 +87,7 @@ extends_documentation_fragment:
"""
EXAMPLES = r"""
-- name: Create aci cloud subnet
+- name: Create AWS aci cloud subnet
cisco.aci.aci_cloud_subnet:
host: apic
username: userName
@@ -87,7 +96,21 @@ EXAMPLES = r"""
tenant: anstest
cloud_context_profile: aws_cloudCtxProfile
cidr: '10.10.0.0/16'
- availability_zone: us-west-1a
+ aws_availability_zone: us-west-1a
+ address: 10.10.0.1
+ delegate_to: localhost
+
+- name: Create Azure aci cloud subnet
+ cisco.aci.aci_cloud_subnet:
+ host: apic
+ username: userName
+ password: somePassword
+ validate_certs: false
+ tenant: anstest
+ cloud_context_profile: azure_cloudCtxProfile
+ cidr: '10.10.0.0/16'
+ azure_region: westus2
+ vnet_gateway: true
address: 10.10.0.1
delegate_to: localhost
@@ -239,16 +262,18 @@ def main():
cloud_context_profile=dict(type="str", required=True),
cidr=dict(type="str", required=True),
state=dict(type="str", default="present", choices=["absent", "present", "query"]),
- availability_zone=dict(type="str"),
+ aws_availability_zone=dict(type="str", aliases=["availability_zone", "av_zone", "zone"]),
+ azure_region=dict(type="str", aliases=["az_region"]),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
- ["state", "absent", ["address"]],
- ["state", "present", ["address"]],
+ ["state", "absent", ["tenant", "cloud_context_profile", "cidr", "address"]],
+ ["state", "present", ["tenant", "cloud_context_profile", "cidr", "address"]],
],
+ mutually_exclusive=[("aws_availability_zone", "azure_region")],
)
name = module.params.get("name")
@@ -260,7 +285,8 @@ def main():
cloud_context_profile = module.params.get("cloud_context_profile")
cidr = module.params.get("cidr")
state = module.params.get("state")
- availability_zone = module.params.get("availability_zone")
+ aws_availability_zone = module.params.get("aws_availability_zone")
+ azure_region = module.params.get("azure_region")
child_configs = []
aci = ACIModule(module)
@@ -283,11 +309,14 @@ def main():
if state == "present":
# in aws cloud apic
- if availability_zone:
- region = availability_zone[:-1]
- tDn = "uni/clouddomp/provp-aws/region-{0}/zone-{1}".format(region, availability_zone)
+ if aws_availability_zone:
+ region = aws_availability_zone[:-1]
+ tDn = "uni/clouddomp/provp-aws/region-{0}/zone-{1}".format(region, aws_availability_zone)
child_configs.append({"cloudRsZoneAttach": {"attributes": {"tDn": tDn}}})
# in azure cloud apic
+ if azure_region:
+ tDn = "uni/clouddomp/provp-azure/region-{0}/zone-default".format(azure_region)
+ child_configs.append({"cloudRsZoneAttach": {"attributes": {"tDn": tDn}}})
if vnet_gateway:
usage = "gateway"
else:
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_config_snapshot.py b/ansible_collections/cisco/aci/plugins/modules/aci_config_snapshot.py
index bc36a5e62..2022c2df9 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_config_snapshot.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_config_snapshot.py
@@ -12,7 +12,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_config_snapshot
-short_description: Manage Config Snapshots (config:Snapshot, config:ExportP)
+short_description: Manage Config Snapshots (config:Snapshot and config:ExportP)
description:
- Manage Config Snapshots on Cisco ACI fabrics.
- Creating new Snapshots is done using the configExportP class.
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_contract_subject_to_service_graph.py b/ansible_collections/cisco/aci/plugins/modules/aci_contract_subject_to_service_graph.py
index eb8f9fa32..f50790bb3 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_contract_subject_to_service_graph.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_contract_subject_to_service_graph.py
@@ -12,7 +12,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_contract_subject_to_service_graph
-short_description: Bind contract subject to service graph (vz:RsSubjGraphAtt).
+short_description: Bind contract subject to service graph (vz:RsSubjGraphAtt)
description:
- Bind contract subject to service graph.
options:
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_dhcp_option.py b/ansible_collections/cisco/aci/plugins/modules/aci_dhcp_option.py
new file mode 100644
index 000000000..1253f85d6
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_dhcp_option.py
@@ -0,0 +1,306 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@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_dhcp_option
+short_description: Manage DHCP Option (dhcp:Option)
+description:
+- Manage DHCP Options for DHCP Option Policies on Cisco ACI fabrics.
+- The DHCP option is used to supply DHCP clients with configuration parameters such as a domain, name server, subnet, and network address.
+ DHCP provides a framework for passing configuration information to clients on a TCP/IP network.
+ The configuration parameters, and other control information, are carried in tagged data items that are stored in the options field of a DHCP message.
+ The data items themselves are also called options. You can view, set, unset, and edit DHCP option values.
+ When you set an option value, the DHCP server replaces any existing value or creates a new one as needed for the given option name.
+options:
+ tenant:
+ description:
+ - The name of an existing tenant.
+ type: str
+ aliases: [ tenant_name ]
+ dhcp_option_policy:
+ description:
+ - The name of an existing DHCP Option Policy.
+ type: str
+ aliases: [ dhcp_option_policy_name ]
+ dhcp_option:
+ description:
+ - The name of the DHCP Option.
+ type: str
+ aliases: [ dhcp_option_name, name ]
+ data:
+ description:
+ - The value of the DHCP Option.
+ type: str
+ id:
+ description:
+ - The DHCP Option ID.
+ type: int
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+notes:
+- The C(tenant) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant) can be used for this.
+seealso:
+- module: cisco.aci.aci_tenant
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC classes
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Gaspard Micol (@gmicol)
+"""
+
+EXAMPLES = r"""
+- name: Add a new DHCP Option
+ cisco.aci.aci_dhcp_option:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ dhcp_option_policy: my_dhcp_option_policy
+ dhcp_option: my_dhcp_option
+ id: 1
+ data: 82
+ state: present
+ delegate_to: localhost
+
+- name: Delete an DHCP Option
+ cisco.aci.aci_dhcp_option:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ dhcp_option_policy: my_dhcp_option_policy
+ dhcp_option: my_dhcp_option
+ state: absent
+ delegate_to: localhost
+
+- name: Query a DHCP Option
+ cisco.aci.aci_dhcp_option:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ dhcp_option_policy: my_dhcp_option_policy
+ dhcp_option: my_dhcp_option
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all DHCP Options in my_dhcp_option_policy
+ cisco.aci.aci_dhcp_option:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ dhcp_option_policy: my_dhcp_option_policy
+ state: query
+ delegate_to: localhost
+ register: query_result
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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"]),
+ dhcp_option_policy=dict(type="str", aliases=["dhcp_option_policy_name"]),
+ dhcp_option=dict(type="str", aliases=["dhcp_option_name", "name"]),
+ data=dict(type="str"),
+ id=dict(type="int"),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["tenant", "dhcp_option_policy", "dhcp_option"]],
+ ["state", "present", ["tenant", "dhcp_option_policy", "dhcp_option"]],
+ ],
+ )
+
+ tenant = module.params.get("tenant")
+ dhcp_option_policy = module.params.get("dhcp_option_policy")
+ dhcp_option = module.params.get("dhcp_option")
+ data = module.params.get("data")
+ id = module.params.get("id")
+ state = module.params.get("state")
+
+ 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="dhcpOptionPol",
+ aci_rn="dhcpoptpol-{0}".format(dhcp_option_policy),
+ module_object=dhcp_option_policy,
+ target_filter={"name": dhcp_option_policy},
+ ),
+ subclass_2=dict(
+ aci_class="dhcpOption",
+ aci_rn="opt-{0}".format(dhcp_option),
+ module_object=dhcp_option,
+ target_filter={"name": dhcp_option},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class="dhcpOption",
+ class_config=dict(
+ name=dhcp_option,
+ data=data,
+ id=id,
+ ),
+ )
+
+ aci.get_diff(aci_class="dhcpOption")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_dhcp_option_policy.py b/ansible_collections/cisco/aci/plugins/modules/aci_dhcp_option_policy.py
new file mode 100644
index 000000000..9e7bd7738
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_dhcp_option_policy.py
@@ -0,0 +1,276 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@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_dhcp_option_policy
+short_description: Manage DHCP Option Policy (dhcp:OptionPol)
+description:
+- Manage DHCP Option Policy for tenants on Cisco ACI fabrics.
+options:
+ tenant:
+ description:
+ - The name of an existing tenant.
+ type: str
+ aliases: [ tenant_name ]
+ dhcp_option_policy:
+ description:
+ - The name of the DHCP Option Policy.
+ type: str
+ aliases: [ dhcp_option_policy_name, name ]
+ description:
+ description:
+ - The description for the DHCP Option Policy.
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+notes:
+- The C(tenant) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant) can be used for this.
+seealso:
+- module: cisco.aci.aci_tenant
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC classes
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Gaspard Micol (@gmicol)
+"""
+
+EXAMPLES = r"""
+- name: Add a new DHCP Option Policy
+ cisco.aci.aci_dhcp_option_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ dhcp_option_policy: my_dhcp_option_policy
+ state: present
+ delegate_to: localhost
+
+- name: Delete an DHCP Option Policy
+ cisco.aci.aci_dhcp_option_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ dhcp_option_policy: my_dhcp_option_policy
+ state: absent
+ delegate_to: localhost
+
+- name: Query a DHCP Option Policy
+ cisco.aci.aci_dhcp_option_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ dhcp_option_policy: my_dhcp_option_policy
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all DHCP Option Policies in my_tenant
+ cisco.aci.aci_dhcp_option_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ state: query
+ delegate_to: localhost
+ register: query_result
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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"]),
+ dhcp_option_policy=dict(type="str", aliases=["dhcp_option_policy_name", "name"]),
+ description=dict(type="str", aliases=["descr"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["tenant", "dhcp_option_policy"]],
+ ["state", "present", ["tenant", "dhcp_option_policy"]],
+ ],
+ )
+
+ tenant = module.params.get("tenant")
+ description = module.params.get("description")
+ dhcp_option_policy = module.params.get("dhcp_option_policy")
+ state = module.params.get("state")
+
+ 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="dhcpOptionPol",
+ aci_rn="dhcpoptpol-{0}".format(dhcp_option_policy),
+ module_object=dhcp_option_policy,
+ target_filter={"name": dhcp_option_policy},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class="dhcpOptionPol",
+ class_config=dict(
+ name=dhcp_option_policy,
+ descr=description,
+ ),
+ )
+
+ aci.get_diff(aci_class="dhcpOptionPol")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_dhcp_relay.py b/ansible_collections/cisco/aci/plugins/modules/aci_dhcp_relay.py
index 9bb8267dd..39351b4aa 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_dhcp_relay.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_dhcp_relay.py
@@ -14,9 +14,9 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_dhcp_relay
-short_description: Manage DHCP relay policies.
+short_description: Manage DHCP relay policies (dhcp:RelayP)
description:
-- Manage DHCP relay policy (dhcpRelayP) configuration on Cisco ACI fabrics.
+- Manage DHCP relay policy configuration on Cisco ACI fabrics.
options:
tenant:
description:
@@ -48,7 +48,7 @@ notes:
The M(cisco.aci.aci_tenant) modules can be used for this.
seealso:
- name: APIC Management Information Model reference
- description: More information about the internal APIC class B(dhcpRelayP).
+ description: More information about the internal APIC class B(dhcp:RelayP).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Tim Cragg (@timcragg)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_dhcp_relay_provider.py b/ansible_collections/cisco/aci/plugins/modules/aci_dhcp_relay_provider.py
index efb9e8e54..2d3dcaf50 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_dhcp_relay_provider.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_dhcp_relay_provider.py
@@ -14,9 +14,9 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_dhcp_relay_provider
-short_description: Manage DHCP relay policy providers.
+short_description: Manage DHCP relay policy providers (dhcp:RsProv)
description:
-- Manage DHCP relay policy providers (dhcpRsProv) configuration on Cisco ACI fabrics.
+- Manage DHCP relay policy providers configuration on Cisco ACI fabrics.
options:
tenant:
description:
@@ -91,7 +91,7 @@ notes:
The M(cisco.aci.aci_tenant) and C(cisco.aci.aci_dhcp_relay) modules can be used for this.
seealso:
- name: APIC Management Information Model reference
- description: More information about the internal APIC class B(dhcpRsProv).
+ description: More information about the internal APIC class B(dhcp:RsProv).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Tim Cragg (@timcragg)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_dns_domain.py b/ansible_collections/cisco/aci/plugins/modules/aci_dns_domain.py
index 4325c7513..11ef520fa 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_dns_domain.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_dns_domain.py
@@ -13,7 +13,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_dns_domain
-short_description: Manage DNS Provider (dnsDomain) objects.
+short_description: Manage DNS Provider objects (dns:Domain)
description:
- Manage DNS Domain configuration on Cisco ACI fabrics.
options:
@@ -49,7 +49,7 @@ notes:
seealso:
- name: APIC Management Information Model reference
- description: More information about the internal APIC class B(dnsDomain).
+ description: More information about the internal APIC class B(dns:Domain).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Tim Cragg (@timcragg)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_dns_profile.py b/ansible_collections/cisco/aci/plugins/modules/aci_dns_profile.py
index 47efb62c4..a4a535a73 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_dns_profile.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_dns_profile.py
@@ -13,7 +13,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_dns_profile
-short_description: Manage DNS Profile (dnsProfile) objects.
+short_description: Manage DNS Profile objects (dns:Profile)
description:
- Manage DNS Profile configuration on Cisco ACI fabrics.
options:
@@ -35,7 +35,7 @@ extends_documentation_fragment:
seealso:
- name: APIC Management Information Model reference
- description: More information about the internal APIC class B(dnsProfile).
+ description: More information about the internal APIC class B(dns:Profile).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Tim Cragg (@timcragg)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_dns_provider.py b/ansible_collections/cisco/aci/plugins/modules/aci_dns_provider.py
index 1fe2c2e60..7b74bd2b6 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_dns_provider.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_dns_provider.py
@@ -13,7 +13,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_dns_provider
-short_description: Manage DNS Provider (dnsProv) objects.
+short_description: Manage DNS Provider objects (dns:Prov)
description:
- Manage DNS Provider configuration on Cisco ACI fabrics.
options:
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_domain.py b/ansible_collections/cisco/aci/plugins/modules/aci_domain.py
index 75509b0ef..ea65805b8 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_domain.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_domain.py
@@ -12,7 +12,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_domain
-short_description: Manage physical, virtual, bridged, routed or FC domain profiles (phys:DomP, vmm:DomP, l2ext:DomP, l3ext:DomP, fc:DomP)
+short_description: Manage physical, virtual, bridged, routed or FC domain profiles (phys:DomP, vmm:DomP, l2ext:DomP, l3ext:DomP, and fc:DomP)
description:
- Manage physical, virtual, bridged, routed or FC domain profiles on Cisco ACI fabrics.
options:
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_encap_pool.py b/ansible_collections/cisco/aci/plugins/modules/aci_encap_pool.py
index 5d5ed7833..360e84c3f 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_encap_pool.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_encap_pool.py
@@ -12,7 +12,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_encap_pool
-short_description: Manage encap pools (fvns:VlanInstP, fvns:VxlanInstP, fvns:VsanInstP)
+short_description: Manage encap pools (fvns:VlanInstP, fvns:VxlanInstP, and fvns:VsanInstP)
description:
- Manage vlan, vxlan, and vsan pools on Cisco ACI fabrics.
options:
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_encap_pool_range.py b/ansible_collections/cisco/aci/plugins/modules/aci_encap_pool_range.py
index 43d34e78d..29da16a7d 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_encap_pool_range.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_encap_pool_range.py
@@ -12,7 +12,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_encap_pool_range
-short_description: Manage encap ranges assigned to pools (fvns:EncapBlk, fvns:VsanEncapBlk)
+short_description: Manage encap ranges assigned to pools (fvns:EncapBlk and fvns:VsanEncapBlk)
description:
- Manage vlan, vxlan, and vsan ranges that are assigned to pools on Cisco ACI fabrics.
options:
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_epg.py b/ansible_collections/cisco/aci/plugins/modules/aci_epg.py
index 9f0eb671a..b9faec64e 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_epg.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_epg.py
@@ -1,6 +1,8 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+# Copyright: (c) 2023, Christian Kolrep <christian.kolrep@dataport.de>
+# Copyright: (c) 2024, Akini Ross <akinross@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
@@ -78,6 +80,17 @@ options:
- Use C(yes) to create uSeg EPG and C(no) is used to create Application EPG.
type: str
choices: [ 'yes', 'no' ]
+ match:
+ description:
+ - The match type of the default Block Statement (fv:Crtrn).
+ - The APIC defaults to C(any) when unset during creation.
+ type: str
+ choices: [ any, all ]
+ precedence:
+ description:
+ - The Block Statement(fv:Crtrn) Precedence to resolve equal matches between micro segmented EPGs.
+ - The APIC defaults to C(0) when unset during creation.
+ type: int
state:
description:
- Use C(present) or C(absent) for adding or removing.
@@ -105,6 +118,8 @@ seealso:
author:
- Swetha Chunduri (@schunduri)
- Shreyas Srish (@shrsr)
+- Christian Kolrep (@Christian-Kolrep)
+- Akini Ross (@akinross)
"""
EXAMPLES = r"""
@@ -123,25 +138,6 @@ EXAMPLES = r"""
state: present
delegate_to: localhost
-- aci_epg:
- host: apic
- username: admin
- password: SomeSecretPassword
- tenant: production
- ap: ticketing
- epg: "{{ item.epg }}"
- description: Ticketing EPG
- bd: "{{ item.bd }}"
- priority: unspecified
- intra_epg_isolation: unenforced
- state: present
- delegate_to: localhost
- with_items:
- - epg: web
- bd: web_bd
- - epg: database
- bd: database_bd
-
- name: Add a new uSeg EPG
cisco.aci.aci_epg:
host: apic
@@ -158,17 +154,22 @@ EXAMPLES = r"""
state: present
delegate_to: localhost
-- name: Remove an EPG
+- name: Add a uSeg EPG with block statement match and precedence
cisco.aci.aci_epg:
host: apic
username: admin
password: SomeSecretPassword
- validate_certs: false
tenant: production
- app_profile: intranet
+ ap: intranet
epg: web_epg
+ description: Web Intranet EPG
+ bd: prod_bd
monitoring_policy: default
- state: absent
+ preferred_group: true
+ useg: 'yes'
+ match: all
+ precedence: 1
+ state: present
delegate_to: localhost
- name: Query an EPG
@@ -213,6 +214,19 @@ EXAMPLES = r"""
state: query
delegate_to: localhost
register: query_result
+
+- name: Remove an EPG
+ cisco.aci.aci_epg:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ validate_certs: false
+ tenant: production
+ app_profile: intranet
+ epg: web_epg
+ monitoring_policy: default
+ state: absent
+ delegate_to: localhost
"""
RETURN = r"""
@@ -342,6 +356,8 @@ def main():
monitoring_policy=dict(type="str"),
custom_qos_policy=dict(type="str"),
useg=dict(type="str", choices=["yes", "no"]),
+ match=dict(type="str", choices=["all", "any"]),
+ precedence=dict(type="int"),
)
module = AnsibleModule(
@@ -369,6 +385,8 @@ def main():
monitoring_policy = module.params.get("monitoring_policy")
custom_qos_policy = module.params.get("custom_qos_policy")
useg = module.params.get("useg")
+ match = module.params.get("match")
+ precedence = module.params.get("precedence")
child_configs = [dict(fvRsBd=dict(attributes=dict(tnFvBDName=bd))), dict(fvRsAEPgMonPol=dict(attributes=dict(tnMonEPGPolName=monitoring_policy)))]
@@ -394,12 +412,17 @@ def main():
module_object=epg,
target_filter={"name": epg},
),
- child_classes=["fvRsBd", "fvRsAEPgMonPol", "fvRsCustQosPol"],
+ child_classes=["fvRsBd", "fvRsAEPgMonPol", "fvRsCustQosPol", "fvCrtrn"],
)
aci.get_existing()
if state == "present":
+ if useg is not None and aci.existing and aci.existing[0]["fvAEPg"]["attributes"]["isAttrBasedEPg"] != useg:
+ module.fail_json(msg="Changing attribute useg on existing EPG is not supported.")
+ if useg == "yes":
+ child_configs.append(dict(fvCrtrn=dict(attributes=dict(name="default", match=match, prec=precedence))))
+
aci.payload(
aci_class="fvAEPg",
class_config=dict(
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_epg_to_contract.py b/ansible_collections/cisco/aci/plugins/modules/aci_epg_to_contract.py
index fe09945a3..9faf882c8 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_epg_to_contract.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_epg_to_contract.py
@@ -1,6 +1,8 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+# Copyright: (c) 2017, Jacob McGill (@jmcgill298)
+# Copyright: (c) 2023, Akini Ross (@akinross) <akinross@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
@@ -12,7 +14,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_epg_to_contract
-short_description: Bind EPGs to Contracts (fv:RsCons, fv:RsProv)
+short_description: Bind EPGs to Contracts (fv:RsCons, fv:RsProv, fv:RsProtBy, fv:RsConsIf, and fv:RsIntraEpg)
description:
- Bind EPGs to Contracts on Cisco ACI fabrics.
notes:
@@ -26,15 +28,15 @@ options:
aliases: [ app_profile, app_profile_name ]
contract:
description:
- - The name of the contract.
+ - The name of the contract or contract interface.
type: str
- aliases: [ contract_name ]
+ aliases: [ contract_name, contract_interface ]
contract_type:
description:
- - Determines if the EPG should Provide or Consume the Contract.
+ - Determines the type of the Contract.
type: str
required: true
- choices: [ consumer, provider ]
+ choices: [ consumer, provider, taboo, interface, intra_epg ]
epg:
description:
- The name of the end point group.
@@ -81,10 +83,11 @@ seealso:
- module: cisco.aci.aci_epg
- module: cisco.aci.aci_contract
- name: APIC Management Information Model reference
- description: More information about the internal APIC classes B(fv:RsCons) and B(fv:RsProv).
+ description: More information about the internal APIC classes B(fv:RsCons), B(fv:RsProv), B(fv:RsProtBy), B(fv:RsConsIf), and B(fv:RsIntraEpg).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Jacob McGill (@jmcgill298)
+- Akini Ross (@akinross)
"""
EXAMPLES = r"""
@@ -248,44 +251,17 @@ url:
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_CLASS_MAPPING = dict(
- consumer={
- "class": "fvRsCons",
- "rn": "rscons-",
- },
- provider={
- "class": "fvRsProv",
- "rn": "rsprov-",
- },
-)
-
-PROVIDER_MATCH_MAPPING = dict(
- all="All",
- at_least_one="AtleastOne",
- at_most_one="AtmostOne",
- none="None",
-)
-
-CONTRACT_LABEL_MAPPING = dict(
- consumer="vzConsLbl",
- provider="vzProvLbl",
-)
-
-SUBJ_LABEL_MAPPING = dict(
- consumer="vzConsSubjLbl",
- provider="vzProvSubjLbl",
-)
+from ansible_collections.cisco.aci.plugins.module_utils.constants import ACI_CLASS_MAPPING, CONTRACT_LABEL_MAPPING, PROVIDER_MATCH_MAPPING, SUBJ_LABEL_MAPPING
def main():
argument_spec = aci_argument_spec()
argument_spec.update(aci_annotation_spec())
argument_spec.update(
- contract_type=dict(type="str", required=True, choices=["consumer", "provider"]),
+ contract_type=dict(type="str", required=True, choices=["consumer", "provider", "taboo", "interface", "intra_epg"]),
ap=dict(type="str", aliases=["app_profile", "app_profile_name"]), # Not required for querying all objects
epg=dict(type="str", aliases=["epg_name"]), # Not required for querying all objects
- contract=dict(type="str", aliases=["contract_name"]), # Not required for querying all objects
+ contract=dict(type="str", aliases=["contract_name", "contract_interface"]), # Not required for querying all objects
priority=dict(type="str", choices=["level1", "level2", "level3", "level4", "level5", "level6", "unspecified"]),
provider_match=dict(type="str", choices=["all", "at_least_one", "at_most_one", "none"]),
state=dict(type="str", default="present", choices=["absent", "present", "query"]),
@@ -318,13 +294,19 @@ def main():
aci_class = ACI_CLASS_MAPPING[contract_type]["class"]
aci_rn = ACI_CLASS_MAPPING[contract_type]["rn"]
- contract_label_class = CONTRACT_LABEL_MAPPING[contract_type]
- subject_label_class = SUBJ_LABEL_MAPPING[contract_type]
+ aci_name = ACI_CLASS_MAPPING[contract_type]["name"]
+ child_classes = []
- if contract_type == "consumer" and provider_match is not None:
+ if contract_type != "provider" and provider_match is not None:
module.fail_json(msg="the 'provider_match' is only configurable for Provided Contracts")
- child_classes = [subject_label_class, contract_label_class]
+ if contract_type in ["taboo", "interface", "intra_epg"] and (contract_label is not None or subject_label is not None):
+ module.fail_json(msg="the 'contract_label' and 'subject_label' are not configurable for {0} contracts".format(contract_type))
+
+ if contract_type not in ["taboo", "interface", "intra_epg"]:
+ contract_label_class = CONTRACT_LABEL_MAPPING.get(contract_type)
+ subject_label_class = SUBJ_LABEL_MAPPING.get(contract_type)
+ child_classes = [subject_label_class, contract_label_class]
aci = ACIModule(module)
aci.construct_url(
@@ -350,7 +332,7 @@ def main():
aci_class=aci_class,
aci_rn="{0}{1}".format(aci_rn, contract),
module_object=contract,
- target_filter={"tnVzBrCPName": contract},
+ target_filter={aci_name: contract},
),
child_classes=child_classes,
)
@@ -359,17 +341,13 @@ def main():
if state == "present":
child_configs = []
- if contract_label:
+ if contract_label is not None:
child_configs.append({contract_label_class: {"attributes": {"name": contract_label}}})
- if subject_label:
+ if subject_label is not None:
child_configs.append({subject_label_class: {"attributes": {"name": subject_label}}})
aci.payload(
aci_class=aci_class,
- class_config=dict(
- matchT=provider_match,
- prio=priority,
- tnVzBrCPName=contract,
- ),
+ class_config={"matchT": provider_match, "prio": priority, aci_name: contract},
child_configs=child_configs,
)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_epg_to_contract_interface.py b/ansible_collections/cisco/aci/plugins/modules/aci_epg_to_contract_interface.py
index bc0ed04fa..ff3a7908c 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_epg_to_contract_interface.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_epg_to_contract_interface.py
@@ -13,7 +13,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_epg_to_contract_interface
-short_description: Bind EPGs to Consumed Contracts Interface (fv:RsConsIf).
+short_description: Bind EPGs to Consumed Contracts Interface (fv:RsConsIf)
description:
- Bind EPGs to Consumed Contracts Interface on Cisco ACI fabrics.
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_epg_to_domain.py b/ansible_collections/cisco/aci/plugins/modules/aci_epg_to_domain.py
index 90f34cc29..1b82f9361 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_epg_to_domain.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_epg_to_domain.py
@@ -137,7 +137,7 @@ options:
description:
- The delimiter.
type: str
- choices: [ "|", "~", "!", "@", "^", "+", "=" ]
+ choices: [ "|", "~", "!", "@", "^", "+", "=", "_" ]
untagged_vlan:
description:
- The access vlan is untagged.
@@ -384,7 +384,7 @@ def main():
vm_provider=dict(type="str", choices=["cloudfoundry", "kubernetes", "microsoft", "openshift", "openstack", "redhat", "vmware"]),
promiscuous=dict(type="str", default="reject", choices=["accept", "reject"]),
custom_epg_name=dict(type="str"),
- delimiter=dict(type="str", choices=["|", "~", "!", "@", "^", "+", "="]),
+ delimiter=dict(type="str", choices=["|", "~", "!", "@", "^", "+", "=", "_"]),
untagged_vlan=dict(type="bool"),
port_binding=dict(type="str", choices=["dynamic", "ephemeral", "static"]),
port_allocation=dict(type="str", choices=["elastic", "fixed"]),
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_epg_useg_attribute_block_statement.py b/ansible_collections/cisco/aci/plugins/modules/aci_epg_useg_attribute_block_statement.py
new file mode 100644
index 000000000..9664b4640
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_epg_useg_attribute_block_statement.py
@@ -0,0 +1,348 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2024, Akini Ross <akinross@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": "certified"}
+
+DOCUMENTATION = r"""
+---
+module: aci_epg_useg_attribute_block_statement
+short_description: Manage EPG useg Attributes Block Statements (fv:SCrtrn)
+description:
+- Manage EPG useg Attributes Block Statements
+options:
+ tenant:
+ description:
+ - The name of an existing tenant.
+ type: str
+ aliases: [ tenant_name ]
+ ap:
+ description:
+ - The name of an existing application network profile.
+ type: str
+ aliases: [ app_profile, app_profile_name ]
+ epg:
+ description:
+ - The name of an existing end point group.
+ type: str
+ aliases: [ epg_name ]
+ parent_block_statements:
+ description:
+ - The list of parent block statements.
+ - The order of the provided list matters, assuming the list ["A", "B"].
+ - The block statement "A" will be the parent of "B"
+ - The block statement "A" will be a child of the default block statement.
+ - The maximum amount of parent block statements is 2.
+ type: list
+ elements: str
+ aliases: [ blocks, parent_blocks ]
+ name:
+ description:
+ - The name of the block statement.
+ type: str
+ aliases: [ block_statement, block_statement_name ]
+ match:
+ description:
+ - The match type of the Block Statement.
+ - The APIC defaults to C(any) when unset during creation.
+ type: str
+ choices: [ any, all ]
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+
+notes:
+- The I(tenant), I(ap) and I(epg) used must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant), M(cisco.aci.aci_ap) and M(cisco.aci.aci_epg) modules can be used for this.
+seealso:
+- module: cisco.aci.aci_tenant
+- module: cisco.aci.aci_ap
+- module: cisco.aci.aci_epg
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(fv:SCrtrn).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Akini Ross (@akinross))
+"""
+
+EXAMPLES = r"""
+- name: Add a new block statement
+ cisco.aci.aci_epg_useg_attribute_block_statement:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: anstest
+ ap: anstest
+ epg: anstest
+ name: block_a
+ state: present
+ delegate_to: localhost
+
+- name: Add a new nested block statement
+ cisco.aci.aci_epg_useg_attribute_block_statement:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: anstest
+ ap: anstest
+ epg: anstest
+ parent_block_statements:
+ - block_a
+ - block_b
+ name: block_c
+ match: any
+ state: present
+ delegate_to: localhost
+
+- name: Query a block statement
+ cisco.aci.aci_epg_useg_attribute_block_statement:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: anstest
+ ap: anstest
+ epg: anstest
+ name: block_a
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all block statements
+ cisco.aci.aci_epg_useg_attribute_block_statement:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Remove an existing block statement
+ cisco.aci.aci_epg_useg_attribute_block_statement:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: anstest
+ ap: anstest
+ epg: anstest
+ name: block_a
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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
+
+
+def main():
+ argument_spec = aci_argument_spec()
+ argument_spec.update(aci_annotation_spec())
+ argument_spec.update(
+ ap=dict(type="str", aliases=["app_profile", "app_profile_name"]), # Not required for querying all objects
+ epg=dict(type="str", aliases=["epg_name"]), # Not required for querying all objects
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ tenant=dict(type="str", aliases=["tenant_name"]), # Not required for querying all objects
+ parent_block_statements=dict(type="list", elements="str", aliases=["parent_blocks", "blocks"]),
+ name=dict(type="str", aliases=["block_statement", "block_statement_name"]),
+ match=dict(type="str", choices=["any", "all"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["ap", "epg", "tenant", "name"]],
+ ["state", "present", ["ap", "epg", "tenant", "name"]],
+ ],
+ )
+
+ aci = ACIModule(module)
+
+ ap = module.params.get("ap")
+ epg = module.params.get("epg")
+ state = module.params.get("state")
+ tenant = module.params.get("tenant")
+ blocks = module.params.get("parent_block_statements")
+ name = module.params.get("name")
+ match = module.params.get("match")
+
+ block_statement_class = "fvSCrtrn"
+
+ if blocks:
+ if len(blocks) > 2:
+ module.fail_json(msg="{0} block statements are provided but the maximum amount of parent_block_statements is 2".format(len(blocks)))
+ parent_blocks_class = block_statement_class
+ parent_blocks_rn = "crtrn/crtrn-{0}".format("/crtrn-".join(blocks))
+ parent_blocks_name = blocks[-1]
+ else:
+ parent_blocks_class = "fvCrtrn"
+ parent_blocks_rn = "crtrn"
+ parent_blocks_name = "default"
+
+ 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="fvAp",
+ aci_rn="ap-{0}".format(ap),
+ module_object=ap,
+ target_filter={"name": ap},
+ ),
+ subclass_2=dict(
+ aci_class="fvAEPg",
+ aci_rn="epg-{0}".format(epg),
+ module_object=epg,
+ target_filter={"name": epg},
+ ),
+ subclass_3=dict(
+ aci_class=parent_blocks_class,
+ aci_rn=parent_blocks_rn,
+ module_object=parent_blocks_name,
+ target_filter={"name": parent_blocks_name},
+ ),
+ subclass_4=dict(
+ aci_class=block_statement_class,
+ aci_rn="crtrn-{0}".format(name),
+ module_object=name,
+ target_filter={"name": name},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(aci_class=block_statement_class, class_config=dict(name=name, match=match))
+
+ aci.get_diff(aci_class=block_statement_class)
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_epg_useg_attribute_simple_statement.py b/ansible_collections/cisco/aci/plugins/modules/aci_epg_useg_attribute_simple_statement.py
new file mode 100644
index 000000000..462a7fcaa
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_epg_useg_attribute_simple_statement.py
@@ -0,0 +1,436 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Christian Kolrep <christian.kolrep@dataport.de>
+# Copyright: (c) 2024, Akini Ross <akinross@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": "certified"}
+
+DOCUMENTATION = r"""
+---
+module: aci_epg_useg_attribute_simple_statement
+short_description: Manage EPG useg Attributes Simple Statements (fv:DnsAttr, fv:IdGroupAttr, fv:IpAttr, fv:MacAttr, and fv:VmAttr)
+description:
+- Manage EPG useg Attributes Simple Statements
+options:
+ tenant:
+ description:
+ - The name of an existing tenant.
+ type: str
+ aliases: [ tenant_name ]
+ ap:
+ description:
+ - The name of an existing application network profile.
+ type: str
+ aliases: [ app_profile, app_profile_name ]
+ epg:
+ description:
+ - The name of an existing end point group.
+ type: str
+ aliases: [ epg_name ]
+ parent_block_statements:
+ description:
+ - The list of parent block statements.
+ - The order of the provided list matters, assuming the list ["A", "B", "C"].
+ - The block statement "A" will be the parent of "B"
+ - The block statement "A" will be a child of the default block statement.
+ - The maximum amount of parent block statements is 3.
+ type: list
+ elements: str
+ aliases: [ blocks, parent_blocks ]
+ name:
+ description:
+ - The name of the EPG useg attribute.
+ type: str
+ aliases: [ useg_attribute_name ]
+ type:
+ description:
+ - The type of the EPG useg attribute
+ type: str
+ required: true
+ choices:
+ - ip
+ - mac
+ - dns
+ - ad_group
+ - vm_custom_attr
+ - vm_vmm_domain
+ - vm_operating_system
+ - vm_hypervisor_id
+ - vm_datacenter
+ - vm_id
+ - vm_name
+ - vm_folder
+ - vm_folder_path
+ - vm_vnic
+ - vm_tag
+ aliases: [ useg_attribute_type ]
+ operator:
+ description:
+ - The operator of the EPG useg attribute.
+ type: str
+ choices: [ equals, contains, starts_with, ends_with ]
+ category:
+ description:
+ - The name of the vmware tag category or vmware custom attribute.
+ type: str
+ aliases: [ custom_attribute ]
+ use_subnet:
+ description:
+ - Whether to use the EPG subnet definition for ip.
+ type: bool
+ value:
+ description:
+ - The value of the EPG useg attribute.
+ type: str
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+
+notes:
+- The I(tenant), I(ap) and I(epg) used must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant), M(cisco.aci.aci_ap) and M(cisco.aci.aci_epg) modules can be used for this.
+seealso:
+- module: cisco.aci.aci_tenant
+- module: cisco.aci.aci_ap
+- module: cisco.aci.aci_epg
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(fv:DnsAttr), B(fv:IdGroupAttr), B(fv:IpAttr), B(fv:MacAttr), and B(fv:VmAttr).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Christian Kolrep (@Christian-Kolrep)
+- Akini Ross (@akinross)
+"""
+
+EXAMPLES = r"""
+- name: Add a new vmtag useg attribute in default block statement
+ cisco.aci.aci_epg_useg_attribute_simple_statement:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: anstest
+ ap: anstest
+ epg: anstest
+ name: vmtagprod
+ type: vmtag
+ category: Environment
+ operator: equals
+ value: Production
+ state: present
+ delegate_to: localhost
+
+- name: Add a new vmtag useg attribute in nested block statement
+ cisco.aci.aci_epg_useg_attribute_simple_statement:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: anstest
+ ap: anstest
+ epg: anstest
+ name: vmtagprod
+ parent_block_statements:
+ - block_a
+ - block_b
+ type: vmtag
+ category: Environment
+ operator: equals
+ value: Production
+ state: present
+ delegate_to: localhost
+
+- name: Query a specific vmtag useg attribute in default block statement
+ cisco.aci.aci_epg_useg_attribute_simple_statement:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: anstest
+ ap: anstest
+ epg: anstest
+ name: vmtagprod
+ type: vmtag
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all vmtag useg attributes
+ cisco.aci.aci_epg_useg_attribute_simple_statement:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ type: vmtag
+ delegate_to: localhost
+ register: query_result
+
+- name: Remove an existing vmtag useg attribute from default block statement
+ cisco.aci.aci_epg_useg_attribute_simple_statement:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: anstest
+ ap: anstest
+ epg: anstest
+ name: vmtagprod
+ type: vmtag
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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
+from ansible_collections.cisco.aci.plugins.module_utils.constants import USEG_ATTRIBUTE_MAPPING, OPERATOR_MAPPING
+
+
+def main():
+ argument_spec = aci_argument_spec()
+ argument_spec.update(aci_annotation_spec())
+ argument_spec.update(
+ ap=dict(type="str", aliases=["app_profile", "app_profile_name"]), # Not required for querying all objects
+ epg=dict(type="str", aliases=["epg_name"]), # Not required for querying all objects
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ tenant=dict(type="str", aliases=["tenant_name"]), # Not required for querying all objects
+ parent_block_statements=dict(type="list", elements="str", aliases=["parent_blocks", "blocks"]),
+ name=dict(type="str", aliases=["useg_attribute_name"]),
+ type=dict(type="str", required=True, choices=list(USEG_ATTRIBUTE_MAPPING.keys()), aliases=["useg_attribute_type"]),
+ operator=dict(type="str", choices=list(OPERATOR_MAPPING.keys())),
+ category=dict(type="str", aliases=["custom_attribute"]),
+ value=dict(type="str"),
+ use_subnet=dict(type="bool"),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["ap", "epg", "tenant", "name"]],
+ ["state", "present", ["ap", "epg", "tenant", "name"]],
+ ],
+ )
+
+ aci = ACIModule(module)
+
+ ap = module.params.get("ap")
+ epg = module.params.get("epg")
+ state = module.params.get("state")
+ tenant = module.params.get("tenant")
+ blocks = module.params.get("parent_block_statements")
+ name = module.params.get("name")
+ attribute_type = module.params.get("type")
+ value = module.params.get("value")
+ operator = module.params.get("operator")
+ category = module.params.get("category")
+ use_subnet = aci.boolean(module.params.get("use_subnet"))
+
+ # Excluding below classes from the module:
+ # fvProtoAttr:
+ # Was used in AVS, but it is not longer in use.
+ # fvUsegBDCont:
+ # Was part of a feature that allowed uSeg attributes to be applied at VRF (instead of BD) level.
+ # It has been since deprecated and we no longer allow setting the scope at fvCtrn to scope-vrf.
+ # This type of functionality has been replaced by the ESG feature.
+ attribute_class = USEG_ATTRIBUTE_MAPPING[attribute_type]["attribute_class"]
+ attribute_rn = USEG_ATTRIBUTE_MAPPING[attribute_type]["rn_format"].format(name)
+ attribute_type = USEG_ATTRIBUTE_MAPPING[attribute_type]["attribute_type"]
+
+ if blocks:
+ if len(blocks) > 3:
+ module.fail_json(msg="{0} block statements are provided but the maximum amount of parent_block_statements is 3".format(len(blocks)))
+ parent_blocks_class = "fvSCrtrn"
+ parent_blocks_rn = "crtrn/crtrn-{0}".format("/crtrn-".join(blocks))
+ parent_blocks_name = blocks[-1]
+ else:
+ parent_blocks_class = "fvCrtrn"
+ parent_blocks_rn = "crtrn"
+ parent_blocks_name = "default"
+
+ 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="fvAp",
+ aci_rn="ap-{0}".format(ap),
+ module_object=ap,
+ target_filter={"name": ap},
+ ),
+ subclass_2=dict(
+ aci_class="fvAEPg",
+ aci_rn="epg-{0}".format(epg),
+ module_object=epg,
+ target_filter={"name": epg},
+ ),
+ subclass_3=dict(
+ aci_class=parent_blocks_class,
+ aci_rn=parent_blocks_rn,
+ module_object=parent_blocks_name,
+ target_filter={"name": parent_blocks_name},
+ ),
+ subclass_4=dict(
+ aci_class=attribute_class,
+ aci_rn=attribute_rn,
+ module_object=name,
+ target_filter={"name": name},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ class_config = dict(name=name)
+
+ if attribute_class == "fvVmAttr":
+ class_config.update(type=attribute_type)
+ class_config.update(operator=OPERATOR_MAPPING.get(operator))
+ class_config.update(value=value)
+ if attribute_type == "tag":
+ class_config.update(category=category)
+ elif attribute_type == "custom-label":
+ class_config.update(labelName=category)
+
+ elif attribute_class == "fvIpAttr":
+ class_config.update(usefvSubnet=use_subnet)
+ class_config.update(ip=value)
+
+ elif attribute_class == "fvMacAttr":
+ class_config.update(mac=value.upper())
+
+ elif attribute_class == "fvDnsAttr":
+ class_config.update(filter=value)
+
+ elif attribute_class == "fvIdGroupAttr":
+ class_config.update(selector=value)
+
+ aci.payload(aci_class=attribute_class, class_config=class_config)
+
+ aci.get_diff(aci_class=attribute_class)
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_esg_ip_subnet_selector.py b/ansible_collections/cisco/aci/plugins/modules/aci_esg_ip_subnet_selector.py
index 368f9e6dc..b8632ec6a 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_esg_ip_subnet_selector.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_esg_ip_subnet_selector.py
@@ -14,7 +14,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_esg_ip_subnet_selector
-short_description: Manage ESG IP Subnet selector(fv:EPSelector)
+short_description: Manage ESG IP Subnet selector (fv:EPSelector)
description:
- Manage Endpoint Security Groups (ESG) IP Subnet selector on Cisco ACI fabrics.
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_fabric_external_connection_profile.py b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_external_connection_profile.py
new file mode 100644
index 000000000..efea05338
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_external_connection_profile.py
@@ -0,0 +1,311 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright: (c) 2024, Samita Bhattacharjee (@samitab) <samitab.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": "certified"}
+
+DOCUMENTATION = r"""
+---
+module: aci_fabric_external_connection_profile
+short_description: Manage Fabric External Connection Profiles (fv:FabricExtConnP).
+description:
+- Manage Fabric External Connection Profiles (Intrasite/Intersite profiles) on Cisco ACI fabrics.
+options:
+ description:
+ description:
+ - Specifies a description of the profile definition.
+ type: str
+ aliases: [ descr ]
+ fabric_id:
+ description:
+ - The fabric identifier of the Fabric External Connection Profile.
+ type: int
+ aliases: [ id, fabric ]
+ name:
+ description:
+ - The name of the Fabric External Connection Profile.
+ type: str
+ aliases: [ profile_name ]
+ community:
+ description:
+ - Global EVPN Route Target of the Fabric External Connection Profile.
+ - eg. extended:as2-nn4:5:16
+ type: str
+ aliases: [ rt, route_target ]
+ site_id:
+ description:
+ - The site identifier of the Fabric External Connection Profile.
+ type: int
+ aliases: [ sid, site, s_id ]
+ peering_type:
+ description:
+ - The BGP EVPN Peering Type. Use either C(automatic_with_full_mesh) or C(automatic_with_rr).
+ type: str
+ choices: [ automatic_with_full_mesh, automatic_with_rr ]
+ aliases: [ p_type, peer, peer_t ]
+ peering_password:
+ description:
+ - The BGP EVPN Peering Password. Used for setting automatic peering sessions.
+ type: str
+ aliases: [ peer_password, peer_pwd ]
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+seealso:
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(fv:FabricExtConnP).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Samita Bhattacharjee (@samitab)
+"""
+
+EXAMPLES = r"""
+- name: Add a new Fabric External Connection Profile
+ cisco.aci.aci_fabric_external_connection_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ fabric_id: 1
+ name: ansible_fabric_ext_conn_profile
+ description: Fabric External Connection Profile
+ community: extended:as2-nn4:5:16
+ site_id: 1
+ peering_type: automatic_with_rr
+ peering_password: SomeSecretPeeringPassword
+ state: present
+ delegate_to: localhost
+
+- name: Query a Fabric External Connection Profile
+ cisco.aci.aci_fabric_external_connection_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ fabric_id: 1
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all Fabric External Connection Profiles
+ cisco.aci.aci_fabric_external_connection_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Remove a Fabric External Connection Profile
+ cisco.aci.aci_fabric_external_connection_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ fabric_id: 1
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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(
+ description=dict(type="str", aliases=["descr"]),
+ fabric_id=dict(type="int", aliases=["id", "fabric"]),
+ name=dict(type="str", aliases=["profile_name"]),
+ community=dict(type="str", aliases=["rt", "route_target"]),
+ site_id=dict(type="int", aliases=["sid", "site", "s_id"]),
+ peering_type=dict(type="str", aliases=["p_type", "peer", "peer_t"], choices=["automatic_with_full_mesh", "automatic_with_rr"]),
+ peering_password=dict(type="str", aliases=["peer_password", "peer_pwd"], no_log=True),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["fabric_id"]],
+ ["state", "present", ["fabric_id"]],
+ ],
+ )
+
+ aci = ACIModule(module)
+
+ description = module.params.get("description")
+ fabric_id = module.params.get("fabric_id")
+ name = module.params.get("name")
+ community = module.params.get("community")
+ peering_type = module.params.get("peering_type")
+ peering_password = module.params.get("peering_password")
+ site_id = module.params.get("site_id")
+ state = module.params.get("state")
+
+ aci.construct_url(
+ root_class=dict(
+ aci_class="fvFabricExtConnP",
+ aci_rn="tn-infra/fabricExtConnP-{0}".format(fabric_id),
+ module_object=fabric_id,
+ target_filter={"id": fabric_id},
+ ),
+ child_classes=["fvPeeringP"],
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ child_configs = None
+ if peering_type is not None or peering_password is not None:
+ peering_p = {"fvPeeringP": {"attributes": {}}}
+ if peering_type is not None:
+ peering_p["fvPeeringP"]["attributes"]["type"] = peering_type
+ if peering_password is not None:
+ peering_p["fvPeeringP"]["attributes"]["password"] = peering_password
+ child_configs = [peering_p]
+
+ aci.payload(
+ aci_class="fvFabricExtConnP",
+ class_config=dict(
+ descr=description,
+ id=fabric_id,
+ name=name,
+ rt=community,
+ siteId=site_id,
+ ),
+ child_configs=child_configs,
+ )
+
+ aci.get_diff(aci_class="fvFabricExtConnP")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_fabric_external_routing_profile.py b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_external_routing_profile.py
new file mode 100644
index 000000000..539705def
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_external_routing_profile.py
@@ -0,0 +1,315 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright: (c) 2024, Samita Bhattacharjee (@samitab) <samitab.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": "certified"}
+
+DOCUMENTATION = r"""
+---
+module: aci_fabric_external_routing_profile
+short_description: Manage Fabric External Routing Profiles (l3ext:FabricExtRoutingP)
+description:
+- Manage Fabric External Routing Profiles on Cisco ACI fabrics.
+options:
+ name:
+ description:
+ - The name of the Fabric External Routing Profile.
+ type: str
+ aliases: [ routing_profile, profile ]
+ fabric_id:
+ description:
+ - The Fabric ID associated with the Fabric External Routing Profile.
+ type: int
+ aliases: [ fabric, fid]
+ description:
+ description:
+ - The description of the Fabric External Routing Profile.
+ type: str
+ aliases: [ descr ]
+ subnets:
+ description:
+ - The list of external subnet IP addresses.
+ - Duplicate subnet IP addresses are not valid and would be ignored.
+ type: list
+ elements: str
+ aliases: [ ip_addresses, ips ]
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+notes:
+- This module requires an existing I(fabric_external_connection_profile).
+ The module M(cisco.aci.aci_fabric_external_connection_profile) can be used for this.
+seealso:
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(l3ext:FabricExtRoutingP).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Samita Bhattacharjee (@samitab)
+"""
+
+# TODO EXAMPLES
+EXAMPLES = r"""
+- name: Add an External Routing Profile
+ cisco.aci.aci_fabric_external_routing_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ fabric_id: "1"
+ description: "Fabric external routing profile"
+ name: "ansible_fabric_ext_routing_profile"
+ subnets:
+ - 1.2.3.4/24
+ - 5.6.7.8/24
+ state: present
+ delegate_to: localhost
+
+- name: Query an External Routing Profile
+ cisco.aci.aci_fabric_external_routing_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ fabric_id: 1
+ name: ansible_fabric_ext_routing_profile
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all External Routing Profiles
+ cisco.aci.aci_fabric_external_routing_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Remove an External Routing Profile
+ cisco.aci.aci_fabric_external_routing_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ fabric_id: 1
+ name: ansible_fabric_ext_routing_profile
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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(
+ name=dict(type="str", aliases=["routing_profile", "profile"]),
+ fabric_id=dict(type="int", aliases=["fabric", "fid"]),
+ description=dict(type="str", aliases=["descr"]),
+ subnets=dict(type="list", elements="str", aliases=["ip_addresses", "ips"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["fabric_id", "name"]],
+ ["state", "present", ["fabric_id", "name"]],
+ ],
+ )
+
+ aci = ACIModule(module)
+
+ name = module.params.get("name")
+ fabric_id = module.params.get("fabric_id")
+ description = module.params.get("description")
+ subnets = module.params.get("subnets")
+ state = module.params.get("state")
+
+ # Remove duplicate subnets
+ if isinstance(subnets, list):
+ subnets = list(dict.fromkeys(subnets))
+
+ aci.construct_url(
+ root_class=dict(
+ aci_class="fvFabricExtConnP",
+ aci_rn="tn-infra/fabricExtConnP-{0}".format(fabric_id),
+ module_object=fabric_id,
+ target_filter={"id": fabric_id},
+ ),
+ subclass_1=dict(
+ aci_class="l3extFabricExtRoutingP",
+ aci_rn="fabricExtRoutingP-{0}".format(name),
+ module_object=name,
+ target_filter={"name": name},
+ ),
+ child_classes=["l3extSubnet"],
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ child_configs = []
+
+ # Validate if existing and remove subnet objects when the config does not match the provided config.
+ if isinstance(aci.existing, list) and len(aci.existing) > 0:
+ subnets = [] if subnets is None else subnets
+ for child in aci.existing[0].get("l3extFabricExtRoutingP", {}).get("children", {}):
+ if child.get("l3extSubnet") and child.get("l3extSubnet").get("attributes").get("ip") not in subnets:
+ child_configs.append(
+ {
+ "l3extSubnet": {
+ "attributes": {
+ "ip": child.get("l3extSubnet").get("attributes").get("ip"),
+ "status": "deleted",
+ }
+ }
+ }
+ )
+
+ if subnets is not None:
+ for subnet in subnets:
+ child_configs.append({"l3extSubnet": {"attributes": {"ip": subnet}}})
+
+ aci.payload(
+ aci_class="l3extFabricExtRoutingP",
+ class_config=dict(
+ name=name,
+ descr=description,
+ ),
+ child_configs=child_configs,
+ )
+
+ aci.get_diff(aci_class="l3extFabricExtRoutingP")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_fabric_interface_policy_group.py b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_interface_policy_group.py
index 4048187db..a6a62b3da 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_fabric_interface_policy_group.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_interface_policy_group.py
@@ -13,7 +13,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_fabric_interface_policy_group
-short_description: Manage Fabric Interface Policy Groups (fabric:LePortPGrp, fabric:SpPortPGrp)
+short_description: Manage Fabric Interface Policy Groups (fabric:LePortPGrp and fabric:SpPortPGrp)
description:
- Manage Fabric Interface Policy Groups on Cisco ACI fabrics.
options:
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_fabric_leaf_profile.py b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_leaf_profile.py
index 09c87a387..590fbd7ba 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_fabric_leaf_profile.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_leaf_profile.py
@@ -12,7 +12,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_fabric_leaf_profile
-short_description: Manage fabric leaf profiles (fabric:LeafP).
+short_description: Manage fabric leaf profiles (fabric:LeafP)
description:
- Manage fabric leaf switch profiles in an ACI fabric.
options:
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_fabric_management_access.py b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_management_access.py
new file mode 100644
index 000000000..493de3947
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_management_access.py
@@ -0,0 +1,700 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2024, Akini Ross (@akinross) <akinross@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": "certified"}
+
+DOCUMENTATION = r"""
+---
+module: aci_fabric_management_access
+short_description: Manage Fabric Management Access (comm:Pol)
+description:
+- Manage Fabric Management Access on Cisco ACI fabrics.
+options:
+ name:
+ description:
+ - The name of the Fabric Management Access policy.
+ type: str
+ aliases: [ fabric_management_access_policy_name ]
+ description:
+ description:
+ - The description of the Fabric Management Access policy.
+ type: str
+ aliases: [ descr ]
+ name_alias:
+ description:
+ - The name alias of the Fabric Management Access policy.
+ - This relates to the nameAlias property in ACI.
+ type: str
+ http:
+ description:
+ - Parameters for HTTP configuration (comm:Http).
+ type: dict
+ suboptions:
+ admin_state:
+ description:
+ - The admin state of the HTTP connection.
+ - The APIC defaults to C(disabled) when unset during creation.
+ type: str
+ choices: [ enabled, disabled ]
+ port:
+ description:
+ - The port for the HTTP connection.
+ - The APIC defaults to C(80) when unset during creation.
+ type: int
+ redirect:
+ description:
+ - The state of the HTTP to HTTPS redirect service.
+ - The APIC defaults to C(disabled) when unset during creation.
+ type: str
+ choices: [ enabled, disabled, tested ]
+ allow_origins:
+ description:
+ - The allowed origins for the HTTP connection.
+ - 'Example format: http://127.0.0.1:8000'
+ type: str
+ allow_credentials:
+ description:
+ - The state of the allow credential for the HTTP connection.
+ - The APIC defaults to C(disabled) when unset during creation.
+ type: str
+ choices: [ enabled, disabled ]
+ throttle:
+ description:
+ - The state of the request throttle for the HTTP connection.
+ - The APIC defaults to C(disabled) when unset during creation.
+ type: str
+ choices: [ enabled, disabled ]
+ throttle_rate:
+ description:
+ - The rate of the request throttle.
+ - The APIC defaults to C(10000) when unset during creation.
+ type: int
+ throttle_unit:
+ description:
+ - The unit of the request throttle rate.
+ - The APIC defaults to C(requests_per_second) when unset during creation.
+ type: str
+ choices: [ requests_per_second, requests_per_minute ]
+ https:
+ description:
+ - Parameters for HTTPS configuration (comm:Https).
+ type: dict
+ suboptions:
+ admin_state:
+ description:
+ - The admin state of the HTTPS connection.
+ - The APIC defaults to C(enabled) when unset during creation.
+ type: str
+ choices: [ enabled, disabled ]
+ port:
+ description:
+ - The port for the HTTPS connection.
+ - The APIC defaults to C(443) when unset during creation.
+ type: int
+ allow_origins:
+ description:
+ - The allowed origins for the HTTPS connection.
+ - 'Example format: http://127.0.0.1:8000'
+ type: str
+ allow_credentials:
+ description:
+ - The state of the allow credential for the HTTPS connection.
+ - The APIC defaults to C(disabled) when unset during creation.
+ type: str
+ choices: [ enabled, disabled ]
+ ssl:
+ description:
+ - The SSL protocol(s) for the HTTPS connection.
+ - The APIC defaults to C(tls_v1.1) and C(tls_v1.2) set when unset during creation.
+ type: list
+ elements: str
+ choices: [ tls_v1.0, tls_v1.1, tls_v1.2, tls_v1.3 ]
+ aliases: [ ssl_protocols ]
+ dh_param:
+ description:
+ - The Diffie-Hellman parameter for the HTTPS connection.
+ - The APIC defaults to C(none) when unset during creation.
+ type: str
+ choices: [ '1024', '2048', '4096', none ]
+ throttle:
+ description:
+ - The state of the request throttle for the HTTPS connection.
+ - The APIC defaults to C(disabled) when unset during creation.
+ type: str
+ choices: [ enabled, disabled ]
+ throttle_rate:
+ description:
+ - The rate of the request throttle.
+ - The APIC defaults to C(10000) when unset during creation.
+ type: int
+ throttle_unit:
+ description:
+ - The unit of the request throttle rate.
+ - The APIC defaults to C(requests_per_second) when unset during creation.
+ type: str
+ choices: [ requests_per_second, requests_per_minute ]
+ admin_key_ring:
+ description:
+ - The admin key ring for the HTTPS connection.
+ - The APIC defaults to C(default) when unset during creation.
+ type: str
+ client_certificate_trustpoint:
+ description:
+ - The client certificate trustpoint for the HTTPS connection.
+ type: str
+ aliases: [ trustpoint ]
+ client_certificate_authentication_state:
+ description:
+ - The client certificate authentication state for the HTTPS connection.
+ - The APIC defaults to C(disabled) when unset during creation.
+ - The C(enabled) state requires a C(client_certificate_trustpoint) to be set.
+ type: str
+ choices: [ enabled, disabled ]
+ aliases: [ client_certificate_auth_state, auth_state, authentication_state ]
+ telnet:
+ description:
+ - Parameters for telnet configuration (comm:Telnet).
+ type: dict
+ suboptions:
+ admin_state:
+ description:
+ - The admin state of the telnet connection.
+ - The APIC defaults to C(disabled) when unset during creation.
+ type: str
+ choices: [ enabled, disabled ]
+ port:
+ description:
+ - The port for the telnet connection.
+ - The APIC defaults to C(23) when unset during creation.
+ type: int
+ ssh:
+ description:
+ - Parameters for SSH configuration (comm:Ssh).
+ type: dict
+ suboptions:
+ admin_state:
+ description:
+ - The admin state of the SSH connection.
+ - The APIC defaults to C(enabled) when unset during creation.
+ type: str
+ choices: [ enabled, disabled ]
+ password_auth_state:
+ description:
+ - The password authentication state of the SSH connection.
+ - The APIC defaults to C(enabled) when unset during creation.
+ type: str
+ choices: [ enabled, disabled ]
+ port:
+ description:
+ - The port for the SSH connection.
+ - The APIC defaults to C(22) when unset during creation.
+ type: int
+ ciphers:
+ description:
+ - The ciphers of the SSH connection.
+ - The APIC defaults to all options set when unset during creation.
+ type: list
+ elements: str
+ choices: [ aes128_ctr, aes192_ctr, aes256_ctr, aes128_gcm, aes256_gcm, chacha20 ]
+ kex:
+ description:
+ - The KEX algorithms of the SSH connection.
+ - The APIC defaults to all options set when unset during creation.
+ type: list
+ elements: str
+ choices: [ dh_sha1, dh_sha256, dh_sha512, curve_sha256, curve_sha256_libssh, ecdh_256, ecdh_384, ecdh_521 ]
+ macs:
+ description:
+ - The MACs of the SSH connection.
+ - The APIC defaults to all options set when unset during creation.
+ type: list
+ elements: str
+ choices: [ sha1, sha2_256, sha2_512, sha2_256_etm, sha2_512_etm ]
+ ssh_web:
+ description:
+ - Parameters for SSH access via WEB configuration (comm:Shellinabox).
+ type: dict
+ suboptions:
+ admin_state:
+ description:
+ - The admin state of the SSH access via WEB connection.
+ - The APIC defaults to C(disabled) when unset during creation.
+ type: str
+ choices: [ enabled, disabled ]
+ state:
+ description:
+ - Use C(present) for updating configuration.
+ - Use C(query) for showing current configuration.
+ type: str
+ choices: [ absent, present, query ]
+ default: present
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+seealso:
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(comm:Pol).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Akini Ross (@akinross)
+"""
+
+EXAMPLES = r"""
+- name: Create a Fabric Management Access policy
+ cisco.aci.aci_fabric_management_access:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ name: fabric_management_access_policy_1
+ description: "This is a example Fabric Management Access policy."
+ state: present
+ delegate_to: localhost
+
+- name: Create a Fabric Management Access policy with telnet enabled
+ cisco.aci.aci_fabric_management_access:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ name: fabric_management_access_policy_1
+ description: "This is a example Fabric Management Access policy."
+ telnet:
+ admin_state: enabled
+ state: present
+ delegate_to: localhost
+
+- name: Create a Fabric Management Access policy with SSH access via WEB enabled
+ cisco.aci.aci_fabric_management_access:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ name: fabric_management_access_policy_1
+ description: "This is a example Fabric Management Access policy."
+ ssh_web:
+ admin_state: enabled
+ state: present
+ delegate_to: localhost
+
+- name: Create a Fabric Management Access policy with SSH enabled and ciphers set
+ cisco.aci.aci_fabric_management_access:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ name: fabric_management_access_policy_1
+ description: "This is a example Fabric Management Access policy."
+ ssh:
+ admin_state: enabled
+ ciphers:
+ - aes128_ctr
+ - aes192_ctr
+ - aes256_ctr
+ state: present
+ delegate_to: localhost
+
+- name: Create a Fabric Management Access policy with HTTP enabled
+ cisco.aci.aci_fabric_management_access:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ name: fabric_management_access_policy_1
+ description: "This is a example Fabric Management Access policy."
+ http:
+ admin_state: enabled
+ allow_origins: http://127.0.0.1:8000
+ throttle: enabled
+ throttle_rate: 7500
+ throttle_unit: requests_per_minute
+ state: present
+ delegate_to: localhost
+
+- name: Create a Fabric Management Access policy with HTTPS enabled
+ cisco.aci.aci_fabric_management_access:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ name: fabric_management_access_policy_1
+ description: "This is a example Fabric Management Access policy."
+ https:
+ admin_state: enabled
+ port: 445
+ allow_origins: http://127.0.0.1:8000
+ allow_credentials: enabled
+ ssl:
+ - tls_v1.2
+ dh_param: 4096
+ throttle: enabled
+ throttle_rate: 7500
+ throttle_unit: requests_per_minute
+ admin_key_ring: default
+ client_certificate_trustpoint: ansible_trustpoint
+ client_certificate_authentication_state: enabled
+ state: present
+ delegate_to: localhost
+
+- name: Query a Fabric Management Access policy
+ cisco.aci.aci_fabric_management_access:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ name: fabric_management_access_policy_1
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all Fabric Management Access policies
+ cisco.aci.aci_fabric_management_access:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Delete a Fabric Management Access policy
+ cisco.aci.aci_fabric_management_access:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ name: fabric_management_access_policy_1
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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
+from ansible_collections.cisco.aci.plugins.module_utils.constants import THROTTLE_UNIT, SSH_CIPHERS, KEX_ALGORITHMS, SSH_MACS, HTTP_TLS_MAPPING
+
+
+def main():
+ argument_spec = aci_argument_spec()
+ argument_spec.update(aci_annotation_spec())
+ argument_spec.update(aci_owner_spec())
+ argument_spec.update(
+ name=dict(type="str", aliases=["fabric_management_access_policy_name"]), # Not required for querying all objects
+ description=dict(type="str", aliases=["descr"]),
+ name_alias=dict(type="str"),
+ http=dict(
+ type="dict",
+ options=dict(
+ admin_state=dict(type="str", choices=["enabled", "disabled"]),
+ port=dict(type="int"),
+ redirect=dict(type="str", choices=["enabled", "disabled", "tested"]),
+ allow_origins=dict(type="str"),
+ allow_credentials=dict(type="str", choices=["enabled", "disabled"]),
+ throttle=dict(type="str", choices=["enabled", "disabled"]),
+ throttle_rate=dict(type="int"),
+ throttle_unit=dict(type="str", choices=["requests_per_second", "requests_per_minute"]),
+ ),
+ ),
+ https=dict(
+ type="dict",
+ options=dict(
+ admin_state=dict(type="str", choices=["enabled", "disabled"]),
+ port=dict(type="int"),
+ allow_origins=dict(type="str"),
+ allow_credentials=dict(type="str", choices=["enabled", "disabled"]),
+ ssl=dict(
+ type="list",
+ elements="str",
+ choices=list(HTTP_TLS_MAPPING.keys()),
+ aliases=["ssl_protocols"],
+ ),
+ dh_param=dict(type="str", choices=["1024", "2048", "4096", "none"]),
+ throttle=dict(type="str", choices=["enabled", "disabled"]),
+ throttle_rate=dict(type="int"),
+ throttle_unit=dict(type="str", choices=["requests_per_second", "requests_per_minute"]),
+ admin_key_ring=dict(type="str", no_log=False),
+ client_certificate_trustpoint=dict(type="str", aliases=["trustpoint"]),
+ client_certificate_authentication_state=dict(
+ type="str",
+ choices=["enabled", "disabled"],
+ aliases=["client_certificate_auth_state", "auth_state", "authentication_state"],
+ ),
+ ),
+ ),
+ telnet=dict(
+ type="dict",
+ options=dict(
+ admin_state=dict(type="str", choices=["enabled", "disabled"]),
+ port=dict(type="int"),
+ ),
+ ),
+ ssh=dict(
+ type="dict",
+ options=dict(
+ admin_state=dict(type="str", choices=["enabled", "disabled"]),
+ password_auth_state=dict(type="str", choices=["enabled", "disabled"]),
+ port=dict(type="int"),
+ ciphers=dict(type="list", elements="str", choices=list(SSH_CIPHERS.keys())),
+ kex=dict(type="list", elements="str", choices=list(KEX_ALGORITHMS.keys())),
+ macs=dict(type="list", elements="str", choices=list(SSH_MACS.keys())),
+ ),
+ ),
+ ssh_web=dict(
+ type="dict",
+ options=dict(
+ admin_state=dict(type="str", choices=["enabled", "disabled"]),
+ ),
+ ),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "present", ["name"]],
+ ["state", "absent", ["name"]],
+ ],
+ )
+
+ aci = ACIModule(module)
+ aci_class = "commPol"
+ aci_child_classes = ["commSsh", "commHttp", "commHttps", "commTelnet", "commShellinabox"]
+
+ name = module.params.get("name")
+ description = module.params.get("description")
+ name_alias = module.params.get("name_alias")
+ http = module.params.get("http")
+ https = module.params.get("https")
+ telnet = module.params.get("telnet")
+ ssh = module.params.get("ssh")
+ ssh_web = module.params.get("ssh_web")
+ state = module.params.get("state")
+
+ aci.construct_url(
+ root_class=dict(
+ aci_class=aci_class,
+ aci_rn="fabric/comm-{0}".format(name),
+ module_object=name,
+ target_filter={"name": name},
+ ),
+ child_classes=aci_child_classes,
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ child_configs = []
+
+ if ssh:
+ child_configs.append(
+ dict(
+ commSsh=dict(
+ attributes=dict(
+ adminSt=ssh.get("admin_state"),
+ passwordAuth=ssh.get("password_auth_state"),
+ port=ssh.get("port"),
+ sshCiphers=",".join(sorted(SSH_CIPHERS.get(v) for v in set(ssh.get("ciphers")))) if ssh.get("ciphers") else None,
+ kexAlgos=",".join(sorted(KEX_ALGORITHMS.get(v) for v in set(ssh.get("kex")))) if ssh.get("kex") else None,
+ sshMacs=",".join(sorted(SSH_MACS.get(v) for v in set(ssh.get("macs")))) if ssh.get("macs") else None,
+ )
+ )
+ )
+ )
+
+ if http:
+ child_configs.append(
+ dict(
+ commHttp=dict(
+ attributes=dict(
+ adminSt=http.get("admin_state"),
+ port=http.get("port"),
+ redirectSt=http.get("redirect"),
+ accessControlAllowOrigins=http.get("allow_origins"),
+ accessControlAllowCredential=http.get("allow_credentials"),
+ globalThrottleSt=http.get("throttle"),
+ globalThrottleRate=http.get("throttle_rate"),
+ globalThrottleUnit=THROTTLE_UNIT.get(http.get("throttle_unit")),
+ )
+ )
+ )
+ )
+
+ if https:
+ https_config = dict(
+ commHttps=dict(
+ attributes=dict(
+ adminSt=https.get("admin_state"),
+ port=https.get("port"),
+ accessControlAllowOrigins=https.get("allow_origins"),
+ accessControlAllowCredential=https.get("allow_credentials"),
+ sslProtocols=",".join(sorted(HTTP_TLS_MAPPING.get(v) for v in set(https.get("ssl")))) if https.get("ssl") else None,
+ dhParam=https.get("dh_param"),
+ globalThrottleSt=https.get("throttle"),
+ globalThrottleRate=https.get("throttle_rate"),
+ globalThrottleUnit=THROTTLE_UNIT.get(https.get("throttle_unit")),
+ clientCertAuthState=https.get("client_certificate_authentication_state"),
+ ),
+ children=[],
+ )
+ )
+
+ if https.get("admin_key_ring"):
+ https_config["commHttps"]["children"].append(dict(commRsKeyRing=dict(attributes=dict(tnPkiKeyRingName=https.get("admin_key_ring")))))
+
+ if https.get("client_certificate_trustpoint"):
+ https_config["commHttps"]["children"].append(
+ dict(commRsClientCertCA=dict(attributes=dict(tDn="uni/userext/pkiext/tp-{0}".format(https.get("client_certificate_trustpoint")))))
+ )
+
+ child_configs.append(https_config)
+
+ if telnet:
+ child_configs.append(
+ dict(
+ commTelnet=dict(
+ attributes=dict(
+ adminSt=telnet.get("admin_state"),
+ port=telnet.get("port"),
+ )
+ )
+ )
+ )
+
+ if ssh_web:
+ child_configs.append(
+ dict(
+ commShellinabox=dict(
+ attributes=dict(
+ adminSt=ssh_web.get("admin_state"),
+ )
+ )
+ )
+ )
+
+ aci.payload(
+ aci_class=aci_class,
+ class_config=dict(
+ name=name,
+ descr=description,
+ nameAlias=name_alias,
+ ),
+ child_configs=child_configs,
+ )
+
+ aci.get_diff(aci_class=aci_class)
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_fabric_management_access_https_cipher.py b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_management_access_https_cipher.py
new file mode 100644
index 000000000..96952f263
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_management_access_https_cipher.py
@@ -0,0 +1,282 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2024, Akini Ross (@akinross) <akinross@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": "certified"}
+
+DOCUMENTATION = r"""
+---
+module: aci_fabric_management_access_https_cipher
+short_description: Manage Fabric Management Access HTTPS SSL Cipher Configuration (comm:Cipher)
+description:
+- Manage Fabric Management Access HTTPS SSL Cipher Configuration on Cisco ACI fabrics.
+options:
+ fabric_management_access_policy_name:
+ description:
+ - The name of the Fabric Management Access policy.
+ type: str
+ aliases: [ name ]
+ id:
+ description:
+ - The ID of the SSL Cipher Configuration.
+ type: str
+ cipher_state:
+ description:
+ - The state of the SSL Cipher Configuration.
+ type: str
+ choices: [ enabled, disabled ]
+ name_alias:
+ description:
+ - The name alias of the Fabric Management Access HTTPS SSL Cipher Configuration.
+ - This relates to the nameAlias property in ACI.
+ type: str
+ state:
+ description:
+ - Use C(present) for updating configuration.
+ - Use C(query) for showing current configuration.
+ type: str
+ choices: [ absent, present, query ]
+ default: present
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+notes:
+- The C(fabric_management_access_policy_name) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_fabric_management_access) module can be used for this.
+seealso:
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(comm:Cipher).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Akini Ross (@akinross)
+"""
+
+EXAMPLES = r"""
+- name: Create a Fabric Management Access HTTPS SSL Cipher
+ cisco.aci.aci_fabric_management_access_https_cipher:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ fabric_management_access_policy_name: fabric_management_access_policy_1
+ id: DHE-RSA-AES128-SHA
+ cipher_state: enabled
+ state: present
+ delegate_to: localhost
+
+- name: Query a Fabric Management Access HTTPS SSL Cipher
+ cisco.aci.aci_fabric_management_access_https_cipher:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ fabric_management_access_policy_name: fabric_management_access_policy_1
+ id: DHE-RSA-AES128-SHA
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all Fabric Management Access policies
+ cisco.aci.aci_fabric_management_access_https_cipher:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Delete a Fabric Management Access HTTPS SSL Cipher
+ cisco.aci.aci_fabric_management_access_https_cipher:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ fabric_management_access_policy_name: fabric_management_access_policy_1
+ id: DHE-RSA-AES128-SHA
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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(
+ fabric_management_access_policy_name=dict(type="str", aliases=["name"]), # Not required for querying all objects
+ id=dict(type="str"),
+ cipher_state=dict(type="str", choices=["enabled", "disabled"]),
+ name_alias=dict(type="str"),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "present", ["fabric_management_access_policy_name", "id", "cipher_state"]],
+ ["state", "absent", ["fabric_management_access_policy_name", "id"]],
+ ],
+ )
+
+ aci = ACIModule(module)
+ aci_class = "commCipher"
+
+ fabric_management_access_policy_name = module.params.get("fabric_management_access_policy_name")
+ id_value = module.params.get("id")
+ cipher_state = module.params.get("cipher_state")
+ name_alias = module.params.get("name_alias")
+ state = module.params.get("state")
+
+ aci.construct_url(
+ root_class=dict(
+ aci_class=aci_class,
+ aci_rn="fabric/comm-{0}".format(fabric_management_access_policy_name),
+ module_object=fabric_management_access_policy_name,
+ target_filter={"name": fabric_management_access_policy_name},
+ ),
+ subclass_1=dict(
+ aci_class=aci_class,
+ aci_rn="https/cph-{0}".format(id_value),
+ module_object=id_value,
+ target_filter={"id": id_value},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class=aci_class,
+ class_config=dict(
+ id=id_value,
+ state=cipher_state,
+ nameAlias=name_alias,
+ ),
+ )
+
+ aci.get_diff(aci_class=aci_class)
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_fabric_pod.py b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_pod.py
new file mode 100644
index 000000000..b9adc1d27
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_pod.py
@@ -0,0 +1,292 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Samita Bhattacharjee (@samitab) <samitab@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": "certified"}
+
+DOCUMENTATION = r"""
+---
+module: aci_fabric_pod
+short_description: Manage Fabric Pod Setup Policy (fabric:SetupP)
+description:
+- Manage Fabric Pod Setup Policy on Cisco ACI fabrics.
+options:
+ pod_id:
+ description:
+ - The Pod ID for the Fabric Pod Setup Policy.
+ - Accepted value range between C(1) and C(254).
+ type: int
+ aliases: [ pod, id ]
+ pod_type:
+ description:
+ - The type of the Pod. Use C(physical) or C(virtual).
+ - The APIC defaults to C(physical) when unset during creation.
+ type: str
+ choices: [ physical, virtual ]
+ aliases: [ type ]
+ tep_pool:
+ description:
+ - The TEP address pool for the Fabric Pod Setup Policy.
+ - Must be valid IPv4 and include the subnet mask.
+ - Example 192.168.1.0/24
+ type: str
+ aliases: [ tep, pool ]
+ description:
+ description:
+ - The description for the Fabric Pod Setup Policy.
+ 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
+
+seealso:
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(fabric:SetupP).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Samita Bhattacharjee (@samitab)
+"""
+
+EXAMPLES = r"""
+- name: Add a fabric pod setup policy
+ cisco.aci.aci_fabric_pod:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ pod_id: 1
+ tep_pool: 10.0.0.0/16
+ state: present
+ delegate_to: localhost
+
+- name: Query the fabric pod setup policy
+ cisco.aci.aci_fabric_pod:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ pod_id: 1
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all fabric pod setup policies
+ cisco.aci.aci_fabric_pod:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Remove a fabric pod setup policy
+ cisco.aci.aci_fabric_pod:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ pod_id: 1
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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(
+ description=dict(type="str", aliases=["descr"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ name_alias=dict(type="str"),
+ pod_id=dict(type="int", aliases=["pod", "id"]),
+ pod_type=dict(type="str", choices=["physical", "virtual"], aliases=["type"]),
+ tep_pool=dict(type="str", aliases=["tep", "pool"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["pod_id"]],
+ ["state", "present", ["pod_id"]],
+ ],
+ )
+
+ aci = ACIModule(module)
+
+ name_alias = module.params.get("name_alias")
+ pod_id = module.params.get("pod_id")
+ pod_type = module.params.get("pod_type")
+ tep_pool = module.params.get("tep_pool")
+ description = module.params.get("description")
+ state = module.params.get("state")
+
+ if pod_id is not None and int(pod_id) not in range(1, 254):
+ aci.fail_json(msg="Pod ID: {0} is invalid; it must be in the range of 1 to 254.".format(pod_id))
+
+ aci.construct_url(
+ root_class=dict(
+ aci_class="fabricSetupP",
+ aci_rn="controller/setuppol/setupp-{0}".format(pod_id),
+ module_object=pod_id,
+ target_filter={"podId": pod_id},
+ ),
+ child_classes=["fabricExtRoutablePodSubnet", "fabricExtSetupP"],
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class="fabricSetupP",
+ class_config=dict(
+ podId=pod_id,
+ podType=pod_type,
+ tepPool=tep_pool,
+ descr=description,
+ nameAlias=name_alias,
+ ),
+ )
+
+ aci.get_diff(aci_class="fabricSetupP")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_fabric_pod_connectivity_profile.py b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_pod_connectivity_profile.py
new file mode 100644
index 000000000..ed601a358
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_pod_connectivity_profile.py
@@ -0,0 +1,336 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright: (c) 2024, Samita Bhattacharjee (@samitab) <samitab.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": "certified"}
+
+DOCUMENTATION = r"""
+---
+module: aci_fabric_pod_connectivity_profile
+short_description: Manage Fabric External Pod Connectivity Profiles (fv:PodConnP)
+description:
+- Manage Fabric External Pod Connectivity Profiles on Cisco ACI fabrics.
+options:
+ pod_id:
+ description:
+ - The Pod ID associated with the Pod Connectivity Profile.
+ type: int
+ aliases: [ pod, pid ]
+ fabric_id:
+ description:
+ - The Fabric ID associated with the Pod Connectivity Profile.
+ type: int
+ aliases: [ fabric, fid ]
+ virtual_pod_id:
+ description:
+ - The Pod ID in the main fabric to which this I(pod_id) is associated. This property is valid only if this pod is a virtual pod.
+ type: int
+ aliases: [ vpod, vpod_id ]
+ description:
+ description:
+ - The description of the Pod Connectivity Profile.
+ type: str
+ aliases: [ descr ]
+ data_plane_tep:
+ description:
+ - The Data Plane TEP IPv4 address and prefix.
+ - eg. 10.1.1.1/32
+ type: str
+ aliases: [ dp_tep ]
+ unicast_tep:
+ description:
+ - The Unicast TEP IPv4 address and prefix.
+ - eg. 10.1.1.2/32
+ type: str
+ aliases: [ u_tep ]
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+notes:
+- This module requires an existing I(fabric_external_connection_profile).
+ The module M(cisco.aci.aci_fabric_external_connection_profile) can be used for this.
+seealso:
+- module: cisco.aci.aci_fabric_external_connection_profile
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(fv:PodConnP).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Samita Bhattacharjee (@samitab)
+"""
+
+EXAMPLES = r"""
+- name: Add a Pod Connectivity Profile
+ cisco.aci.aci_fabric_pod_connectivity_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ fabric_id: 1
+ pod_id: 1
+ description: First pod connectivity profile
+ data_plane_tep: 10.1.1.1/32
+ unicast_tep: 10.1.1.2/32
+ state: present
+ delegate_to: localhost
+
+- name: Query a Pod Connectivity Profile
+ cisco.aci.aci_fabric_pod_connectivity_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ fabric_id: 1
+ pod_id: 1
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all Pod Connectivity Profiles
+ cisco.aci.aci_fabric_pod_connectivity_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Remove a Pod Connectivity Profile
+ cisco.aci.aci_fabric_pod_connectivity_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ fabric_id: 1
+ pod_id: 1
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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(
+ pod_id=dict(type="int", aliases=["pod", "pid"]),
+ fabric_id=dict(type="int", aliases=["fabric", "fid"]),
+ virtual_pod_id=dict(type="int", aliases=["vpod", "vpod_id"]),
+ description=dict(type="str", aliases=["descr"]),
+ data_plane_tep=dict(type="str", aliases=["dp_tep"]),
+ unicast_tep=dict(type="str", aliases=["u_tep"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["fabric_id", "pod_id"]],
+ ["state", "present", ["fabric_id", "pod_id"]],
+ ],
+ )
+
+ aci = ACIModule(module)
+
+ pod_id = module.params.get("pod_id")
+ fabric_id = module.params.get("fabric_id")
+ virtual_pod_id = module.params.get("virtual_pod_id")
+ description = module.params.get("description")
+ data_plane_tep = module.params.get("data_plane_tep")
+ unicast_tep = module.params.get("unicast_tep")
+ state = module.params.get("state")
+
+ aci.construct_url(
+ root_class=dict(
+ aci_class="fvFabricExtConnP",
+ aci_rn="tn-infra/fabricExtConnP-{0}".format(fabric_id),
+ module_object=fabric_id,
+ target_filter={"id": fabric_id},
+ ),
+ subclass_1=dict(
+ aci_class="fvPodConnP",
+ aci_rn="podConnP-{0}".format(pod_id),
+ module_object=pod_id,
+ target_filter={"id": pod_id},
+ ),
+ child_classes=["fvIp", "fvExtRoutableUcastConnP"],
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ child_configs = []
+
+ # Validate if existing and remove child objects when the config does not match the provided config.
+ if isinstance(aci.existing, list) and len(aci.existing) > 0:
+ for child in aci.existing[0].get("fvPodConnP", {}).get("children", {}):
+ if child.get("fvExtRoutableUcastConnP") and child.get("fvExtRoutableUcastConnP").get("attributes").get("addr") != unicast_tep:
+ child_configs.append(
+ {
+ "fvExtRoutableUcastConnP": {
+ "attributes": {
+ "addr": child.get("fvExtRoutableUcastConnP").get("attributes").get("addr"),
+ "status": "deleted",
+ }
+ }
+ }
+ )
+ if child.get("fvIp") and child.get("fvIp").get("attributes").get("addr") != data_plane_tep:
+ child_configs.append(
+ {
+ "fvIp": {
+ "attributes": {
+ "addr": child.get("fvIp").get("attributes").get("addr"),
+ "status": "deleted",
+ }
+ }
+ }
+ )
+
+ if unicast_tep is not None:
+ child_configs.append({"fvExtRoutableUcastConnP": {"attributes": {"addr": unicast_tep}}})
+ if data_plane_tep is not None:
+ child_configs.append({"fvIp": {"attributes": {"addr": data_plane_tep}}})
+
+ aci.payload(
+ aci_class="fvPodConnP",
+ class_config=dict(
+ id=pod_id,
+ assocIntersitePodId=virtual_pod_id,
+ descr=description,
+ ),
+ child_configs=child_configs,
+ )
+
+ aci.get_diff(aci_class="fvPodConnP")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_fabric_pod_external_tep.py b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_pod_external_tep.py
new file mode 100644
index 000000000..511a5aa93
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_pod_external_tep.py
@@ -0,0 +1,321 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Samita Bhattacharjee (@samitab) <samitab@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": "certified"}
+
+DOCUMENTATION = r"""
+---
+module: aci_fabric_pod_external_tep
+short_description: Manage Fabric Pod External TEP (fabric:ExtRoutablePodSubnet)
+description:
+- Manage Fabric Pod External TEP Subnets.
+options:
+ pod_id:
+ description:
+ - The Pod ID for the External TEP.
+ type: int
+ aliases: [ pod ]
+ description:
+ description:
+ - The description for the External TEP.
+ type: str
+ aliases: [ descr ]
+ name_alias:
+ description:
+ - The alias for the current object. This relates to the nameAlias field in ACI.
+ type: str
+ external_tep_pool:
+ description:
+ - The subnet IP address pool for the External TEP.
+ - Must be valid IPv4 and include the subnet mask.
+ - Example 192.168.1.0/24
+ type: str
+ aliases: [ ip, ip_address, tep_pool, pool ]
+ reserve_address_count:
+ description:
+ - Indicates the number of IP addresses that are reserved from the start of the subnet.
+ type: int
+ aliases: [ address_count ]
+ status:
+ description:
+ - State of the External TEP C(active) or C(inactive).
+ - An External TEP can only be deleted when the state is inactive.
+ - The APIC defaults to C(active) when unset during creation.
+ type: str
+ choices: [ active, inactive ]
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+notes:
+- The C(Fabric Pod Setup Policy) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_fabric_pod) module can be used for this.
+seealso:
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(fabric:ExtRoutablePodSubnet).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Samita Bhattacharjee (@samitab)
+"""
+
+EXAMPLES = r"""
+- name: Add an External TEP to a fabric pod setup policy
+ cisco.aci.aci_fabric_pod_external_tep:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ pod_id: 2
+ external_tep_pool: 10.6.1.0/24
+ reserve_address_count: 5
+ status: active
+ state: present
+ delegate_to: localhost
+
+- name: Change an External TEP state on a fabric pod setup policy to inactive
+ cisco.aci.aci_fabric_pod_external_tep:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ pod_id: 2
+ external_tep_pool: 10.6.1.0/24
+ status: inactive
+ state: present
+ delegate_to: localhost
+
+- name: Query the External TEP on a fabric pod setup policy
+ cisco.aci.aci_fabric_pod_external_tep:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ pod_id: 2
+ external_tep_pool: 10.6.1.0/24
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query External TEPs on all fabric pod setup policies
+ cisco.aci.aci_fabric_pod_external_tep:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Delete an External TEP on a fabric pod setup policy
+ cisco.aci.aci_fabric_pod_external_tep:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ pod_id: 2
+ external_tep_pool: 10.6.1.0/24
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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(
+ description=dict(type="str", aliases=["descr"]),
+ name_alias=dict(type="str"),
+ pod_id=dict(type="int", aliases=["pod"]),
+ external_tep_pool=dict(type="str", aliases=["ip", "ip_address", "tep_pool", "pool"]),
+ reserve_address_count=dict(type="int", aliases=["address_count"]),
+ status=dict(type="str", choices=["active", "inactive"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["pod_id", "external_tep_pool"]],
+ ["state", "present", ["pod_id", "external_tep_pool"]],
+ ],
+ )
+
+ aci = ACIModule(module)
+
+ pod_id = module.params.get("pod_id")
+ descr = module.params.get("descr")
+ name_alias = module.params.get("name_alias")
+ external_tep_pool = module.params.get("external_tep_pool")
+ reserve_address_count = module.params.get("reserve_address_count")
+ status = module.params.get("status")
+ state = module.params.get("state")
+
+ if pod_id is not None and int(pod_id) not in range(1, 254):
+ aci.fail_json(msg="Pod ID: {0} is invalid; it must be in the range of 1 to 254.".format(pod_id))
+
+ aci.construct_url(
+ root_class=dict(
+ aci_class="fabricSetupP",
+ aci_rn="controller/setuppol/setupp-{0}".format(pod_id),
+ module_object=pod_id,
+ target_filter={"podId": pod_id},
+ ),
+ subclass_1=dict(
+ aci_class="fabricExtRoutablePodSubnet",
+ aci_rn="extrtpodsubnet-[{0}]".format(external_tep_pool),
+ module_object=external_tep_pool,
+ target_filter={"pool": external_tep_pool},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class="fabricExtRoutablePodSubnet",
+ class_config=dict(
+ descr=descr,
+ nameAlias=name_alias,
+ pool=external_tep_pool,
+ reserveAddressCount=reserve_address_count,
+ state=status,
+ ),
+ )
+
+ aci.get_diff(aci_class="fabricExtRoutablePodSubnet")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_fabric_pod_profile.py b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_pod_profile.py
new file mode 100644
index 000000000..e77114848
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_pod_profile.py
@@ -0,0 +1,267 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Samita Bhattacharjee (@samitab) <samitab@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": "certified"}
+
+DOCUMENTATION = r"""
+---
+module: aci_fabric_pod_profile
+short_description: Manage Fabric Pod Profile (fabric:PodP)
+description:
+- Manage Fabric Pod Profile on Cisco ACI fabrics.
+options:
+ name:
+ description:
+ - The name of the Pod Profile.
+ type: str
+ aliases: [ profile, pod_profile ]
+ description:
+ description:
+ - The description for the Fabric Pod Profile.
+ 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
+
+seealso:
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(fabric:PodP).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Samita Bhattacharjee (@samitab)
+"""
+
+EXAMPLES = r"""
+- name: Add a new pod profile
+ cisco.aci.aci_fabric_pod_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ name: ans_pod_profile
+ state: present
+ delegate_to: localhost
+
+- name: Query a pod profile
+ cisco.aci.aci_fabric_pod_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ name: ans_pod_profile
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all pod profiles
+ cisco.aci.aci_fabric_pod_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Remove a pod profile
+ cisco.aci.aci_fabric_pod_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ name: ans_pod_profile
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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(
+ description=dict(type="str", aliases=["descr"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ name_alias=dict(type="str"),
+ name=dict(type="str", aliases=["profile", "pod_profile"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["name"]],
+ ["state", "present", ["name"]],
+ ],
+ )
+
+ aci = ACIModule(module)
+
+ name_alias = module.params.get("name_alias")
+ name = module.params.get("name")
+ description = module.params.get("description")
+ state = module.params.get("state")
+
+ aci.construct_url(
+ root_class=dict(
+ aci_class="fabricPodP",
+ aci_rn="fabric/podprof-{0}".format(name),
+ module_object=name,
+ target_filter={"name": name},
+ ),
+ child_classes=["fabricPodS"],
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class="fabricPodP",
+ class_config=dict(
+ name=name,
+ descr=description,
+ nameAlias=name_alias,
+ ),
+ )
+
+ aci.get_diff(aci_class="fabricPodP")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_fabric_pod_remote_pool.py b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_pod_remote_pool.py
new file mode 100644
index 000000000..189a0273d
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_pod_remote_pool.py
@@ -0,0 +1,294 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Samita Bhattacharjee (@samitab) <samitab@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": "certified"}
+
+DOCUMENTATION = r"""
+---
+module: aci_fabric_pod_remote_pool
+short_description: Manage Fabric Pod Remote Pool (fabric:ExtSetupP)
+description:
+- Manage Remote Pools on Fabric Pod Subnets.
+options:
+ pod_id:
+ description:
+ - The Pod ID for the Remote Pool.
+ type: int
+ aliases: [ pod ]
+ description:
+ description:
+ - The description for the Remote Pool.
+ type: str
+ aliases: [desc]
+ remote_id:
+ description:
+ - The Identifier for the Remote Pool.
+ type: int
+ aliases: [ id ]
+ name_alias:
+ description:
+ - The alias for the current object. This relates to the nameAlias field in ACI.
+ type: str
+ remote_pool:
+ description:
+ - The subnet IP address pool for the Remote Pool.
+ - Must be valid IPv4 and include the subnet mask.
+ - Example 192.168.1.0/24
+ type: str
+ aliases: [ pool ]
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+notes:
+- The C(Fabric Pod Setup Policy) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_fabric_pod) module can be used for this.
+seealso:
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(fabric:ExtSetupP).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Samita Bhattacharjee (@samitab)
+"""
+
+EXAMPLES = r"""
+- name: Add a Remote Pool to a fabric pod setup policy
+ cisco.aci.aci_fabric_pod_remote_pool:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ pod_id: 2
+ remote_id: 1
+ remote_pool: 10.6.2.0/24
+ state: present
+ delegate_to: localhost
+
+- name: Query the Remote Pool on a fabric pod setup policy
+ cisco.aci.aci_fabric_pod_remote_pool:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ pod_id: 2
+ remote_id: 1
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query Remote Pools on all fabric pod setup policies
+ cisco.aci.aci_fabric_pod_remote_pool:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Delete a Remote Pool from a fabric pod setup policy
+ cisco.aci.aci_fabric_pod_external_tep:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ pod_id: 2
+ remote_id: 1
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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(
+ pod_id=dict(type="int", aliases=["pod"]),
+ description=dict(type="str", aliases=["desc"]),
+ remote_id=dict(type="int", aliases=["id"]),
+ name_alias=dict(type="str"),
+ remote_pool=dict(type="str", aliases=["pool"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["pod_id", "remote_id"]],
+ ["state", "present", ["pod_id", "remote_id"]],
+ ],
+ )
+
+ aci = ACIModule(module)
+
+ pod_id = module.params.get("pod_id")
+ description = module.params.get("description")
+ remote_id = module.params.get("remote_id")
+ name_alias = module.params.get("name_alias")
+ remote_pool = module.params.get("remote_pool")
+ state = module.params.get("state")
+
+ if pod_id is not None and int(pod_id) not in range(1, 254):
+ aci.fail_json(msg="Pod ID: {0} is invalid; it must be in the range of 1 to 254.".format(pod_id))
+
+ aci.construct_url(
+ root_class=dict(
+ aci_class="fabricSetupP",
+ aci_rn="controller/setuppol/setupp-{0}".format(pod_id),
+ module_object=pod_id,
+ target_filter={"podId": pod_id},
+ ),
+ subclass_1=dict(
+ aci_class="fabricExtSetupP",
+ aci_rn="extsetupp-{0}".format(remote_id),
+ module_object=remote_id,
+ target_filter={"extPoolId": remote_id},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class="fabricExtSetupP",
+ class_config=dict(
+ descr=description,
+ extPoolId=remote_id,
+ nameAlias=name_alias,
+ tepPool=remote_pool,
+ ),
+ )
+
+ aci.get_diff(aci_class="fabricExtSetupP")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_fabric_pod_selector.py b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_pod_selector.py
index 6c95f32df..28d95eae0 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_fabric_pod_selector.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_pod_selector.py
@@ -67,6 +67,7 @@ extends_documentation_fragment:
notes:
- The C(pod_profile) must exist before using this module in your playbook.
+- The M(cisco.aci.aci_fabric_pod_profile) module can be used to create the C(pod_profile).
seealso:
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(fabric:PodS).
@@ -76,9 +77,6 @@ author:
- Akini Ross (@akinross)
"""
-# TODO add to notes section when cisco.aci.aci_pod_profile is implemented:
-# The M(cisco.aci.aci_pod_profile) module can be used for this.
-
EXAMPLES = r"""
- name: Add a new pod selector with type all
cisco.aci.aci_fabric_pod_selector:
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_fabric_spine_profile.py b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_spine_profile.py
index 364b613ff..af80ee415 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_fabric_spine_profile.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_spine_profile.py
@@ -12,7 +12,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_fabric_spine_profile
-short_description: Manage fabric spine profiles (fabric:SpineP).
+short_description: Manage fabric spine profiles (fabric:SpineP)
description:
- Manage fabric spine switch profiles in an ACI fabric.
options:
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_fabric_spine_switch_assoc.py b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_spine_switch_assoc.py
index ce0a00ce8..5884cd1e1 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_fabric_spine_switch_assoc.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_spine_switch_assoc.py
@@ -12,7 +12,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_fabric_spine_switch_assoc
-short_description: Manage spine switch bindings to profiles and policy groups (fabric:SpineS and fabric:RsSpNodePGrp).
+short_description: Manage spine switch bindings to profiles and policy groups (fabric:SpineS and fabric:RsSpNodePGrp)
description:
- Manage fabric spine switch associations (fabric:SpineS) to an existing fabric
spine profile (fabric:SpineP) in an ACI fabric, and bind them to a
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_fabric_switch_block.py b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_switch_block.py
index 57bd59874..ded3b56ec 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_fabric_switch_block.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_switch_block.py
@@ -12,7 +12,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_fabric_switch_block
-short_description: Manage switch blocks (fabric:NodeBlk).
+short_description: Manage switch blocks (fabric:NodeBlk)
description:
- Manage fabric node blocks within switch associations (fabric:SpineS and
fabric:LeafS) contained within fabric switch profiles (fabric:SpineP and fabric:LeafP)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_fabric_switch_policy_group.py b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_switch_policy_group.py
index 1d766a34e..a3ba0a033 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_fabric_switch_policy_group.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_switch_policy_group.py
@@ -13,72 +13,72 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_fabric_switch_policy_group
-short_description: Manage Fabric Switch Policy Group objects.
+short_description: Manage Fabric Switch Policy Group objects (fabric:LeNodePGrp and fabric:SpNodePGrp)
description:
-- Manage Fabric Switch Policy Group (fabricLeNodePGrp and fabricSpNodePGrp) configuration on Cisco ACI fabrics.
+- Manage Fabric Switch Policy Group configuration on Cisco ACI fabrics.
options:
name:
description:
- - The name of the Leaf Policy Group.
+ - The name of the Fabric Switch Policy Group.
type: str
aliases: [ 'policy_group', 'policy_group_name' ]
description:
description:
- - Description for the Leaf Policy Group.
+ - Description for the Fabric Switch Policy Group.
type: str
switch_type:
description:
- - Whether this is a leaf or spine policy group
+ - Whether this is a leaf or spine Fabric Switch Policy Group.
type: str
choices: [ leaf, spine ]
required: true
monitoring_policy:
description:
- - Monitoring Policy to attach to this Policy Group
+ - Monitoring Policy to attach to this Fabric Switch Policy Group.
type: str
aliases: [ 'monitoring', 'fabricRsMonInstFabricPol' ]
tech_support_export_policy:
description:
- - Tech Support Export Policy to attach to this Policy Group
+ - Tech Support Export Policy to attach to this Fabric Switch Policy Group.
type: str
aliases: [ 'tech_support', 'tech_support_export', 'fabricRsNodeTechSupP']
core_export_policy:
description:
- - Core Export Policy to attach to this Policy Group
+ - Core Export Policy to attach to this Fabric Switch Policy Group.
type: str
aliases: [ 'core', 'core_export', 'fabricRsNodeCoreP' ]
inventory_policy:
description:
- - Inventory Policy to attach to this Policy Group
+ - Inventory Policy to attach to this Fabric Switch Policy Group.
type: str
aliases: [ 'inventory', 'fabricRsCallhomeInvPol' ]
power_redundancy_policy:
description:
- - Power Redundancy Policy to atttach to this Policy Group
+ - Power Redundancy Policy to atttach to this Fabric Switch Policy Group.
type: str
aliases: [ 'power_redundancy', 'fabricRsPsuInstPol' ]
twamp_server_policy:
description:
- - TWAMP Server Policy to attach to this Policy Group
+ - TWAMP Server Policy to attach to this Fabric Switch Policy Group.
type: str
aliases: [ 'twamp_server', 'fabricRsTwampServerPol' ]
twamp_responder_policy:
description:
- - TWAMP Responder Policy to attach to this Policy Group
+ - TWAMP Responder Policy to attach to this Fabric Switch Policy Group.
type: str
aliases: [ 'twamp_responder', 'fabricRsTwampResponderPol' ]
node_control_policy:
description:
- - Node Control Policy to attach to this Policy Group
+ - Node Control Policy to attach to this Fabric Switch Policy Group.
type: str
aliases: [ 'node_control', 'fabricRsNodeCtrl' ]
analytics_cluster:
description:
- - Name of the analytics cluster. Requires analytics_name to be present
+ - Name of the analytics cluster. Requires analytics_name to be present.
type: str
analytics_name:
description:
- - Name of the analytics policy. Requires analytics_cluster to be present
+ - Name of the analytics policy. Requires analytics_cluster to be present.
type: str
state:
description:
@@ -93,7 +93,7 @@ extends_documentation_fragment:
seealso:
- name: APIC Management Information Model reference
- description: More information about the internal APIC classes B(fabricLeNodePGrp and fabricSpNodePGrp).
+ description: More information about the internal APIC classes B(fabric:LeNodePGrp) and B(fabric:SpNodePGrp).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Tim Cragg (@timcragg)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_fabric_wide_settings.py b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_wide_settings.py
index 1bc7c28eb..2f8a879a9 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_fabric_wide_settings.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_fabric_wide_settings.py
@@ -235,7 +235,7 @@ url:
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
-from ansible_collections.cisco.aci.plugins.module_utils.constants import TLS_MAPPING
+from ansible_collections.cisco.aci.plugins.module_utils.constants import OPFLEX_TLS_MAPPING
def main():
@@ -251,7 +251,7 @@ def main():
leaf_opflex_client_auth=dict(type="bool"),
spine_ssl_opflex=dict(type="bool"),
leaf_ssl_opflex=dict(type="bool"),
- opflex_ssl_versions=dict(type="list", choices=list(TLS_MAPPING.keys()), elements="str"),
+ opflex_ssl_versions=dict(type="list", choices=list(OPFLEX_TLS_MAPPING.keys()), elements="str"),
reallocate_gipo=dict(type="bool"),
restrict_infra_vlan_traffic=dict(type="bool"),
state=dict(type="str", default="present", choices=["present", "query"]),
@@ -300,7 +300,7 @@ def main():
restrictInfraVLANTraffic=restrict_infra_vlan_traffic,
)
if opflex_ssl_versions is not None:
- class_config["opflexpSslProtocols"] = ",".join([TLS_MAPPING.get(tls) for tls in sorted(opflex_ssl_versions)])
+ class_config["opflexpSslProtocols"] = ",".join([OPFLEX_TLS_MAPPING.get(tls) for tls in sorted(opflex_ssl_versions)])
aci.payload(
aci_class="infraSetPol",
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_igmp_interface_policy.py b/ansible_collections/cisco/aci/plugins/modules/aci_igmp_interface_policy.py
index 7f537871a..78369df89 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_igmp_interface_policy.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_igmp_interface_policy.py
@@ -294,8 +294,8 @@ def main():
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
- ["state", "present", ["name"]],
- ["state", "absent", ["name"]],
+ ["state", "present", ["name", "tenant"]],
+ ["state", "absent", ["name", "tenant"]],
],
required_together=[
["allow_v3_asm", "fast_leave", "report_link_local_groups"],
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_interface_blacklist.py b/ansible_collections/cisco/aci/plugins/modules/aci_interface_blacklist.py
index 61d5ef44d..aeba32988 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_interface_blacklist.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_interface_blacklist.py
@@ -12,7 +12,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_interface_blacklist
-short_description: Enabling or Disabling physical interfaces.
+short_description: Enabling or Disabling physical interfaces (fabric:RsOosPath)
description:
- Enables or Disables physical interfaces on Cisco ACI fabrics.
options:
@@ -49,6 +49,10 @@ extends_documentation_fragment:
- cisco.aci.aci
- cisco.aci.annotation
+seealso:
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(fabric:RsOosPath).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Akini Ross (@akinross)
"""
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_interface_description.py b/ansible_collections/cisco/aci/plugins/modules/aci_interface_description.py
index c4a204c89..387acd54a 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_interface_description.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_interface_description.py
@@ -12,7 +12,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_interface_description
-short_description: Setting and removing description on physical interfaces.
+short_description: Setting and removing description on physical interfaces (infra:HPathS, infra:RsHPathAtt, infra:SHPathS, and infra:RsSHPathAtt)
description:
- Setting and removing description on physical interfaces on Cisco ACI fabrics.
options:
@@ -59,6 +59,10 @@ extends_documentation_fragment:
- cisco.aci.annotation
- cisco.aci.owner
+seealso:
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC classes B(infra:HPathS), B(infra:RsHPathAtt), B(infra:SHPathS), and B(infra:RsSHPathAtt).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Akini Ross (@akinross)
"""
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_bfd.py b/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_bfd.py
new file mode 100644
index 000000000..ec651f360
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_bfd.py
@@ -0,0 +1,318 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Anvitha Jain (@anvjain) <anvjain@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_interface_policy_bfd
+short_description: Manage BFD Interface policies (bfd:IfPol)
+description:
+- Manage BFD Interface policy configuration on Cisco ACI fabrics
+- Only available in APIC version 5.2 or later
+options:
+ tenant:
+ description:
+ - Name of an existing tenant
+ type: str
+ name:
+ description:
+ - Name of the BFD Interface policy
+ type: str
+ aliases: [ bfd_interface_policy ]
+ description:
+ description:
+ - Description of the BFD Interface policy
+ type: str
+ admin_state:
+ description:
+ - Admin state of the BFD Interface policy
+ - APIC sets the default value to enabled
+ type: str
+ choices: [ enabled, disabled ]
+ detection_multiplier:
+ description:
+ - Detection multiplier of the BFD Interface policy
+ - APIC sets the default value to 3
+ - Allowed range is 1-50
+ type: int
+ min_transmit_interval:
+ description:
+ - Minimum transmit (Tx) interval of the BFD Interface policy
+ - APIC sets the default value to 50
+ - Allowed range is 250-999
+ type: int
+ min_receive_interval:
+ description:
+ - Minimum receive (Rx) interval of the BFD Interface policy
+ - APIC sets the default value to 50
+ - Allowed range is 250-999
+ type: int
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+
+notes:
+- The C(tenant) must exist before using this module in your playbook
+ The M(cisco.aci.aci_tenant) modules can be used for this
+seealso:
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(bfd:IfPol)
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+- module: cisco.aci.aci_tenant
+author:
+- Anvitha Jain (@anvjain)
+"""
+
+EXAMPLES = r"""
+- name: Add a new BFD Interface policy
+ cisco.aci.aci_interface_policy_bfd:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: ansible_tenant
+ name: ansible_bfd_interface_policy
+ description: Ansible BFD Interface Policy
+ state: present
+ delegate_to: localhost
+
+- name: Remove a BFD Interface policy
+ cisco.aci.aci_interface_policy_bfd:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: ansible_tenant
+ name: ansible_bfd_interface_policy
+ state: absent
+ delegate_to: localhost
+
+- name: Query a BFD Interface policy
+ cisco.aci.aci_interface_policy_bfd:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: ansible_tenant
+ name: ansible_bfd_interface_policy
+ state: query
+ delegate_to: localhost
+
+- name: Query all BFD Interface policies in a specific tenant
+ cisco.aci.aci_interface_policy_bfd:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: ansible_tenant
+ state: query
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+ 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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class "/></imdata>'
+ 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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+ 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
+
+
+def main():
+ argument_spec = aci_argument_spec()
+ argument_spec.update(aci_annotation_spec())
+ argument_spec.update(
+ name=dict(type="str", aliases=["bfd_interface_policy"]),
+ description=dict(type="str"),
+ admin_state=dict(type="str", choices=["enabled", "disabled"]),
+ detection_multiplier=dict(type="int"),
+ min_transmit_interval=dict(type="int"),
+ min_receive_interval=dict(type="int"),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ tenant=dict(type="str"),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["name", "tenant"]],
+ ["state", "present", ["name", "tenant"]],
+ ],
+ )
+
+ name = module.params.get("name")
+ description = module.params.get("description")
+ state = module.params.get("state")
+ tenant = module.params.get("tenant")
+ admin_state = module.params.get("admin_state")
+ detection_multiplier = module.params.get("detection_multiplier")
+ min_transmit_interval = module.params.get("min_transmit_interval")
+ min_receive_interval = module.params.get("min_receive_interval")
+
+ 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="bfdIfPol",
+ aci_rn="bfdIfPol-{0}".format(name),
+ module_object=name,
+ target_filter={"name": name},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ class_config = dict(
+ name=name,
+ descr=description,
+ adminSt=admin_state,
+ )
+
+ if detection_multiplier and detection_multiplier not in range(1, 50):
+ module.fail_json(msg='The "detection_multiplier" must be a value between 1 and 50')
+ else:
+ class_config["detectMult"] = detection_multiplier
+ if min_transmit_interval and min_transmit_interval not in range(50, 999):
+ module.fail_json(msg='The "min_transmit_interval" must be a value between 50 and 999')
+ else:
+ class_config["minTxIntvl"] = min_transmit_interval
+ if min_receive_interval and min_receive_interval not in range(50, 999):
+ module.fail_json(msg='The "min_receive_interval" must be a value between 50 and 999')
+ else:
+ class_config["minRxIntvl"] = min_receive_interval
+
+ aci.payload(
+ aci_class="bfdIfPol",
+ class_config=class_config,
+ )
+
+ aci.get_diff(aci_class="bfdIfPol")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_bfd_multihop.py b/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_bfd_multihop.py
new file mode 100644
index 000000000..31cc9321c
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_bfd_multihop.py
@@ -0,0 +1,318 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Anvitha Jain (@anvjain) <anvjain@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_interface_policy_bfd_multihop
+short_description: Manage BFD Multihop Interface policies (bfd:MhIfPol)
+description:
+- Manage BFD Multihop Interface policy configuration on Cisco ACI fabrics
+- Only available in APIC version 5.2 or later
+options:
+ tenant:
+ description:
+ - Name of an existing tenant
+ type: str
+ name:
+ description:
+ - Name of the BFD Multihop Interface policy
+ type: str
+ aliases: [ bfd_multihop_interface_policy ]
+ description:
+ description:
+ - Description of the BFD Multihop Interface policy
+ type: str
+ admin_state:
+ description:
+ - Admin state of the BFD Multihop Interface policy
+ - APIC sets the default value to enabled.
+ type: str
+ choices: [ enabled, disabled ]
+ detection_multiplier:
+ description:
+ - Detection multiplier of the BFD Multihop Interface policy
+ - APIC sets the default value to 3.
+ - Allowed range is 1-50.
+ type: int
+ min_transmit_interval:
+ description:
+ - Minimum transmit (Tx) interval of the BFD Multihop Interface policy
+ - APIC sets the default value to 250
+ - Allowed range is 250-999
+ type: int
+ min_receive_interval:
+ description:
+ - Minimum receive (Rx) interval of the BFD Multihop Interface policy
+ - APIC sets the default value to 250
+ - Allowed range is 250-999
+ type: int
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+
+notes:
+- The C(tenant) must exist before using this module in your playbook
+ The M(cisco.aci.aci_tenant) modules can be used for this
+seealso:
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(bfd:MhIfPol)
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+- module: cisco.aci.aci_tenant
+author:
+- Anvitha Jain (@anvjain)
+"""
+
+EXAMPLES = r"""
+- name: Add a new BFD Multihop Interface policy
+ cisco.aci.aci_interface_policy_bfd_multihop:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: ansible_tenant
+ name: ansible_bfd_multihop_interface_policy
+ description: Ansible BFD Multihop Interface Policy
+ state: present
+ delegate_to: localhost
+
+- name: Remove a BFD Multihop Interface policy
+ cisco.aci.aci_interface_policy_bfd_multihop:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: ansible_tenant
+ name: ansible_bfd_multihop_interface_policy
+ state: absent
+ delegate_to: localhost
+
+- name: Query a BFD Multihop Interface policy
+ cisco.aci.aci_interface_policy_bfd_multihop:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: ansible_tenant
+ name: ansible_bfd_multihop_interface_policy
+ state: query
+ delegate_to: localhost
+
+- name: Query all BFD Multihop Interface policies in a specific tenant
+ cisco.aci.aci_interface_policy_bfd_multihop:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: ansible_tenant
+ state: query
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+ 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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class "/></imdata>'
+ 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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+ 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
+
+
+def main():
+ argument_spec = aci_argument_spec()
+ argument_spec.update(aci_annotation_spec())
+ argument_spec.update(
+ name=dict(type="str", aliases=["bfd_multihop_interface_policy"]),
+ description=dict(type="str"),
+ admin_state=dict(type="str", choices=["enabled", "disabled"]),
+ detection_multiplier=dict(type="int"),
+ min_transmit_interval=dict(type="int"),
+ min_receive_interval=dict(type="int"),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ tenant=dict(type="str"),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["name", "tenant"]],
+ ["state", "present", ["name", "tenant"]],
+ ],
+ )
+
+ name = module.params.get("name")
+ description = module.params.get("description")
+ state = module.params.get("state")
+ tenant = module.params.get("tenant")
+ admin_state = module.params.get("admin_state")
+ detection_multiplier = module.params.get("detection_multiplier")
+ min_transmit_interval = module.params.get("min_transmit_interval")
+ min_receive_interval = module.params.get("min_receive_interval")
+
+ 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="bfdMhIfPol",
+ aci_rn="bfdMhIfPol-{0}".format(name),
+ module_object=name,
+ target_filter={"name": name},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ class_config = dict(
+ name=name,
+ descr=description,
+ adminSt=admin_state,
+ )
+
+ if detection_multiplier and detection_multiplier not in range(1, 50):
+ module.fail_json(msg='The "detection_multiplier" must be a value between 1 and 50')
+ else:
+ class_config["detectMult"] = detection_multiplier
+ if min_transmit_interval and min_transmit_interval not in range(250, 999):
+ module.fail_json(msg='The "min_transmit_interval" must be a value between 250 and 999')
+ else:
+ class_config["minTxIntvl"] = min_transmit_interval
+ if min_receive_interval and min_receive_interval not in range(250, 999):
+ module.fail_json(msg='The "min_receive_interval" must be a value between 250 and 999')
+ else:
+ class_config["minRxIntvl"] = min_receive_interval
+
+ aci.payload(
+ aci_class="bfdMhIfPol",
+ class_config=class_config,
+ )
+
+ aci.get_diff(aci_class="bfdMhIfPol")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_eigrp.py b/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_eigrp.py
new file mode 100644
index 000000000..7e0e64d53
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_eigrp.py
@@ -0,0 +1,371 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2022, Lukas Holub (@lukasholub)
+# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@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": "certified"}
+
+DOCUMENTATION = r"""
+---
+module: aci_interface_policy_eigrp
+short_description: Manage EIGRP interface policies (eigrp:IfPol)
+description:
+- Manage EIGRP interface policies for Tenants on Cisco ACI fabrics.
+options:
+ tenant:
+ description:
+ - The name of an existing Tenant.
+ type: str
+ aliases: [ tenant_name ]
+ eigrp:
+ description:
+ - The EIGRP interface policy name.
+ - Note that you cannot change this name after the object has been created.
+ type: str
+ aliases: [ eigrp_interface, name ]
+ bandwidth:
+ description:
+ - The EIGRP bandwidth in kbps, overrides the bandwidth configured on an interface.
+ - This is used to influence path selection.
+ - Accepted values range between C(0) and C(2560000000).
+ - The APIC defaults to C(0) when unset during creation.
+ type: int
+ control_state:
+ description:
+ - The interface policy control state.
+ - 'This is a list of one or more of the following controls:'
+ - C(bfd) -- Enable Bidirectional Forwarding Detection.
+ - C(nexthop_self) -- Nexthop Self.
+ - C(split_horizon) -- Split Horizon.
+ - C(passive) -- The interface does not participate in the EIGRP protocol and
+ will not establish adjacencies or send routing updates.
+ - The APIC defaults to C([split_horizon, nexthop_self]) when unset during creation.
+ type: list
+ elements: str
+ choices: [ bfd, nexthop_self, passive, split_horizon ]
+ delay:
+ description:
+ - The EIGRP throughput delay, overrides the delay configured on an interface.
+ - This is used to influence path selection.
+ - The APIC defaults to C(0) when unset during creation.
+ type: int
+ delay_unit:
+ description:
+ - The EIGRP delay units, Wide metrics can use picoseconds accuracy for delay.
+ - The APIC defaults to C(tens_of_microseconds) when unset during creation.
+ type: str
+ choices: [ picoseconds, tens_of_microseconds ]
+ hello_interval:
+ description:
+ - The time interval in seconds between hello packets that EIGRP sends on the interface.
+ - The smaller the hello interval, the faster topological changes will be detected, but more routing traffic will ensue.
+ - Accepted values range between C(1) and C(65535).
+ - The APIC defaults to C(5) when unset during creation.
+ type: int
+ hold_interval:
+ description:
+ - The time period of time in seconds before declaring that the neighbor is down.
+ - Accepted values range between C(1) and C(65535).
+ - The APIC defaults to C(15) when unset during creation.
+ type: int
+ description:
+ description:
+ - The description of the EIGRP interface policy.
+ 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) used must exist before using this module in your playbook.
+- The M(cisco.aci.aci_tenant) module 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(eigrp:IfPol).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Gaspard Micol (@gmicol)
+- Lukas Holub (@lukasholub)
+"""
+
+EXAMPLES = r"""
+- name: Create an EIGRP interface policy
+ cisco.aci.aci_interface_policy_eigrp:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: production
+ eigrp: eigrp1
+ bandwidth: 10000
+ control_state: [split-horizon, nh-self]
+ delay: 10
+ delay_unit: tens_of_micro
+ hello_interval: 5
+ hold_interval: 15
+ state: present
+ delegate_to: localhost
+
+- name: Delete EIGRRP interface policy
+ cisco.aci.aci_interface_policy_eigrp:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: production
+ eigrp: eigrp1
+ state: present
+ delegate_to: localhost
+
+- name: Query an EIGRRP interface policy
+ cisco.aci.aci_interface_policy_eigrp:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: production
+ eigrp: eigrp1
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all EIGRP interface policies in tenant production
+ cisco.aci.aci_interface_policy_eigrp:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: production
+ state: query
+ delegate_to: localhost
+ register: query_result
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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
+from ansible_collections.cisco.aci.plugins.module_utils.constants import (
+ MATCH_EIGRP_INTERFACE_POLICY_DELAY_UNIT_MAPPING,
+ MATCH_EIGRP_INTERFACE_POLICY_CONTROL_STATE_MAPPING,
+)
+
+
+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
+ eigrp=dict(type="str", aliases=["eigrp_interface", "name"]), # Not required for querying all objects
+ description=dict(type="str", aliases=["descr"]),
+ bandwidth=dict(type="int"),
+ control_state=dict(type="list", elements="str", choices=["bfd", "nexthop_self", "passive", "split_horizon"]),
+ delay=dict(type="int"),
+ delay_unit=dict(type="str", choices=["picoseconds", "tens_of_microseconds"]),
+ hello_interval=dict(type="int"),
+ hold_interval=dict(type="int"),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ name_alias=dict(type="str"),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["eigrp", "tenant"]],
+ ["state", "present", ["eigrp", "tenant"]],
+ ],
+ )
+
+ aci = ACIModule(module)
+
+ tenant = module.params.get("tenant")
+ eigrp = module.params.get("eigrp")
+ delay = module.params.get("delay")
+ delay_unit = MATCH_EIGRP_INTERFACE_POLICY_DELAY_UNIT_MAPPING.get(module.params.get("delay_unit"))
+ description = module.params.get("description")
+ name_alias = module.params.get("name_alias")
+ state = module.params.get("state")
+
+ bandwidth = module.params.get("bandwidth")
+ if bandwidth is not None and bandwidth not in range(2560000001):
+ module.fail_json(msg="Parameter 'bandwidth' is only valid in range between 0 and 2560000000.")
+
+ hello_interval = module.params.get("hello_interval")
+ if hello_interval is not None and hello_interval not in range(1, 65536):
+ module.fail_json(msg="Parameter 'hello_interval' is only valid in range between 1 and 65535.")
+
+ hold_interval = module.params.get("hold_interval")
+ if hold_interval is not None and hold_interval not in range(1, 65536):
+ module.fail_json(msg="Parameter 'hold_interval' is only valid in range between 1 and 65535.")
+
+ if module.params.get("control_state"):
+ control_state = ",".join([MATCH_EIGRP_INTERFACE_POLICY_CONTROL_STATE_MAPPING.get(v) for v in module.params.get("control_state")])
+ else:
+ control_state = None
+
+ 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="eigrpIfPol",
+ aci_rn="eigrpIfPol-{0}".format(eigrp),
+ module_object=eigrp,
+ target_filter={"name": eigrp},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class="eigrpIfPol",
+ class_config=dict(
+ name=eigrp,
+ descr=description,
+ bw=bandwidth,
+ ctrl=control_state,
+ delay=delay,
+ delayUnit=delay_unit,
+ helloIntvl=hello_interval,
+ holdIntvl=hold_interval,
+ nameAlias=name_alias,
+ ),
+ )
+
+ aci.get_diff(aci_class="eigrpIfPol")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_hsrp.py b/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_hsrp.py
new file mode 100644
index 000000000..c94b5af42
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_hsrp.py
@@ -0,0 +1,310 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Shreyas Srish (@shrsr) <ssrish@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": "certified"}
+
+DOCUMENTATION = r"""
+---
+module: aci_interface_policy_hsrp
+short_description: Manage HSRP interface policies (hsrp:IfPol)
+description:
+- Manage HSRP interface policies on Cisco ACI fabrics.
+options:
+ tenant:
+ description:
+ - The name of the Tenant the HSRP interface policy should belong to.
+ type: str
+ aliases: [ tenant_name ]
+ hsrp:
+ description:
+ - The HSRP interface policy name.
+ type: str
+ aliases: [ hsrp_interface, name ]
+ description:
+ description:
+ - The description of the HSRP interface.
+ type: str
+ aliases: [ descr ]
+ controls:
+ description:
+ - The interface policy controls.
+ type: list
+ elements: str
+ choices: [ bfd, bia ]
+ delay:
+ description:
+ - The administrative port delay of HSRP interface policy.
+ - This is only valid in range between 1 and 10000.
+ type: int
+ reload_delay:
+ description:
+ - The option for reload delay of HSRP interface policy.
+ - This is only valid in range between 1 and 10000.
+ type: int
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+notes:
+- The C(tenant) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant) can be used for this.
+seealso:
+- module: aci_tenant
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(hsrp:IfPol).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Shreyas Srish (@shrsr)
+"""
+
+EXAMPLES = r"""
+- name: Add a HSRP interface policy
+ cisco.aci.aci_interface_policy_hsrp:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: production
+ hsrp: hsrp1
+ controls: bfd
+ delay: 50
+ reload_delay: 100
+ state: present
+ delegate_to: localhost
+
+- name: Delete a HSRP interface policy
+ cisco.aci.aci_interface_policy_hsrp:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: production
+ hsrp: hsrp1
+ state: absent
+ delegate_to: localhost
+
+- name: Query a HSRP interface policy
+ cisco.aci.aci_interface_policy_hsrp:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: production
+ hsrp: hsrp1
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all HSRP interface policies in tenant production
+ cisco.aci.aci_interface_policy_hsrp:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: production
+ state: query
+ delegate_to: localhost
+ register: query_result
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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
+ hsrp=dict(type="str", aliases=["hsrp_interface", "name"]), # Not required for querying all objects
+ description=dict(type="str", aliases=["descr"]),
+ controls=dict(type="list", elements="str", choices=["bfd", "bia"]),
+ reload_delay=dict(type="int"),
+ delay=dict(type="int"),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["tenant", "hsrp"]],
+ ["state", "present", ["tenant", "hsrp"]],
+ ],
+ )
+
+ aci = ACIModule(module)
+
+ tenant = module.params.get("tenant")
+ hsrp = module.params.get("hsrp")
+ description = module.params.get("description")
+ controls = ",".join(module.params.get("controls")) if module.params.get("controls") else None
+
+ reload_delay = module.params.get("reload_delay")
+ if reload_delay is not None and reload_delay not in range(1, 10000):
+ module.fail_json(msg="Parameter 'reload_delay' is only valid in range between 1 and 10000.")
+
+ delay = module.params.get("delay")
+ if delay is not None and delay not in range(1, 10000):
+ module.fail_json(msg="Parameter 'delay' is only valid in range between 1 and 10000.")
+
+ state = module.params.get("state")
+
+ 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="hsrpIfPol",
+ aci_rn="hsrpIfPol-{0}".format(hsrp),
+ module_object=hsrp,
+ target_filter={"name": hsrp},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class="hsrpIfPol",
+ class_config=dict(
+ name=hsrp,
+ descr=description,
+ ctrl=controls,
+ reloadDelay=reload_delay,
+ delay=delay,
+ ),
+ )
+
+ aci.get_diff(aci_class="hsrpIfPol")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_leaf_fc_policy_group.py b/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_leaf_fc_policy_group.py
index 6c3436459..b77eb16fe 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_leaf_fc_policy_group.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_leaf_fc_policy_group.py
@@ -13,7 +13,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_interface_policy_leaf_fc_policy_group
-short_description: Manage Fibre Channel (FC) interface policy groups (infra:FcAccBndlGrp, infra:FcAccPortGrp)
+short_description: Manage Fibre Channel (FC) interface policy groups (infra:FcAccBndlGrp and infra:FcAccPortGrp)
description:
- Manage Fibre Channel (FC) interface policy groups on Cisco ACI fabrics.
options:
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_leaf_policy_group.py b/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_leaf_policy_group.py
index da2e90adf..d106df250 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_leaf_policy_group.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_leaf_policy_group.py
@@ -14,7 +14,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_interface_policy_leaf_policy_group
-short_description: Manage fabric interface policy leaf policy groups (infra:AccBndlGrp, infra:AccPortGrp)
+short_description: Manage fabric interface policy leaf policy groups (infra:AccBndlGrp and infra:AccPortGrp)
description:
- Manage fabric interface policy leaf policy groups on Cisco ACI fabrics.
options:
@@ -624,34 +624,6 @@ def main():
),
),
),
- dict(
- infraRsLinkFlapPol=dict(
- attributes=dict(
- tnFabricLinkFlapPolName=link_flap_policy,
- ),
- ),
- ),
- dict(
- infraRsQosLlfcIfPol=dict(
- attributes=dict(
- tnQosLlfcIfPolName=link_level_flow_control,
- ),
- ),
- ),
- dict(
- infraRsMacsecIfPol=dict(
- attributes=dict(
- tnMacsecIfPolName=mac_sec_interface_policy,
- ),
- ),
- ),
- dict(
- infraRsCoppIfPol=dict(
- attributes=dict(
- tnCoppIfPolName=copp_policy,
- ),
- ),
- ),
]
child_classes = [
@@ -671,10 +643,6 @@ def main():
"infraRsQosSdIfPol",
"infraRsStormctrlIfPol",
"infraRsStpIfPol",
- "infraRsLinkFlapPol",
- "infraRsQosLlfcIfPol",
- "infraRsMacsecIfPol",
- "infraRsCoppIfPol",
]
# Add infraRsattEntP binding only when aep is defined
@@ -728,6 +696,7 @@ def main():
)
)
child_classes.append("infraRsOpticsIfPol")
+
if dwdm is not None:
child_configs.append(
dict(
@@ -739,6 +708,7 @@ def main():
)
)
child_classes.append("infraRsDwdmIfPol")
+
if port_authentication is not None:
child_configs.append(
dict(
@@ -750,6 +720,7 @@ def main():
)
)
child_classes.append("infraRsL2PortAuthPol")
+
if poe_interface_policy is not None:
child_configs.append(
dict(
@@ -762,6 +733,54 @@ def main():
)
child_classes.append("infraRsPoeIfPol")
+ if link_flap_policy is not None:
+ child_configs.append(
+ dict(
+ infraRsLinkFlapPol=dict(
+ attributes=dict(
+ tnFabricLinkFlapPolName=link_flap_policy,
+ ),
+ ),
+ ),
+ )
+ child_classes.append("infraRsLinkFlapPol")
+
+ if link_level_flow_control is not None:
+ child_configs.append(
+ dict(
+ infraRsQosLlfcIfPol=dict(
+ attributes=dict(
+ tnQosLlfcIfPolName=link_level_flow_control,
+ ),
+ ),
+ ),
+ )
+ child_classes.append("infraRsQosLlfcIfPol")
+
+ if mac_sec_interface_policy is not None:
+ child_configs.append(
+ dict(
+ infraRsMacsecIfPol=dict(
+ attributes=dict(
+ tnMacsecIfPolName=mac_sec_interface_policy,
+ ),
+ ),
+ ),
+ )
+ child_classes.append("infraRsMacsecIfPol")
+
+ if copp_policy is not None:
+ child_configs.append(
+ dict(
+ infraRsCoppIfPol=dict(
+ attributes=dict(
+ tnCoppIfPolName=copp_policy,
+ ),
+ ),
+ ),
+ )
+ child_classes.append("infraRsCoppIfPol")
+
aci.construct_url(
root_class=dict(
aci_class=aci_class_name,
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_link_level.py b/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_link_level.py
index 5c0120d4d..1980721cc 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_link_level.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_link_level.py
@@ -36,9 +36,10 @@ options:
speed:
description:
- Determines the interface policy administrative port speed.
+ - The C(auto) option is only supported in APIC version 5.2 or later.
- The APIC defaults to C(inherit) when unset during creation.
type: str
- choices: [ 100M, 1G, 10G, 25G, 40G, 50G, 100G, 200G, 400G, inherit ]
+ choices: [ 100M, 1G, 10G, 25G, 40G, 50G, 100G, 200G, 400G, auto, inherit ]
default: inherit
link_debounce_interval:
description:
@@ -231,7 +232,7 @@ def main():
link_level_policy=dict(type="str", aliases=["name"]),
description=dict(type="str", aliases=["descr"]),
auto_negotiation=dict(type="bool", default="true"),
- speed=dict(type="str", default="inherit", choices=["100M", "1G", "10G", "25G", "40G", "50G", "100G", "200G", "400G", "inherit"]),
+ speed=dict(type="str", default="inherit", choices=["100M", "1G", "10G", "25G", "40G", "50G", "100G", "200G", "400G", "auto", "inherit"]),
link_debounce_interval=dict(type="int", default="100"),
forwarding_error_correction=dict(
type="str", default="inherit", choices=["inherit", "kp-fec", "cl91-rs-fec", "cl74-fc-fec", "disable-fec", "ieee-rs-fec", "cons16-rs-fec"]
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_pim.py b/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_pim.py
new file mode 100644
index 000000000..ad47fb836
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_pim.py
@@ -0,0 +1,444 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@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": "certified"}
+
+DOCUMENTATION = r"""
+---
+module: aci_interface_policy_pim
+short_description: Manage Protocol-Independent Multicast (PIM) interface policies (pim:IfPol)
+description:
+- Manage Protocol Independent Multicast interface policies for Tenants on Cisco ACI fabrics.
+options:
+ tenant:
+ description:
+ - The name of an existing Tenant.
+ type: str
+ aliases: [ tenant_name ]
+ pim:
+ description:
+ - The PIM interface policy name.
+ - The name cannot be changed after the object has been created.
+ type: str
+ aliases: [ pim_interface_policy, name ]
+ authentication_key:
+ description:
+ - The authentication key.
+ type: str
+ aliases: [ auth_key ]
+ authentication_type:
+ description:
+ - The authentication type.
+ type: str
+ choices: [ none, md5_hmac ]
+ aliases: [ auth_type ]
+ control_state:
+ description:
+ - The PIM interface policy control state.
+ - 'This is a list of one or more of the following controls:'
+ - C(multicast_domain_boundary) -- Boundary of Multicast domain.
+ - C(strict_rfc_compliant) -- Only listen to PIM protocol packets.
+ - C(passive) -- Do not send/receive PIM protocol packets.
+ type: list
+ elements: str
+ choices: [ multicast_domain_boundary, strict_rfc_compliant, passive ]
+ designated_router_delay:
+ description:
+ - The PIM designated router delay.
+ - Accepted values range between C(1) and C(65535).
+ - The APIC defaults to C(3) when unset during creation.
+ type: int
+ aliases: [ delay ]
+ designated_router_priority:
+ description:
+ - The PIM designated router priority.
+ - Accepted values range between C(1) and C(4294967295).
+ - The APIC defaults to C(1) when unset during creation.
+ type: int
+ aliases: [ prio ]
+ hello_interval:
+ description:
+ - The time interval in seconds between hello packets that PIM sends on the interface.
+ - The smaller the hello interval, the faster topological changes will be detected, but more routing traffic will ensue.
+ - Accepted values range between C(1) and C(18724286).
+ - The APIC defaults to C(30000) when unset during creation.
+ type: int
+ join_prune_interval:
+ description:
+ - The join prune interval in seconds.
+ - Accepted values range between C(60) and C(65520).
+ - The APIC defaults to C(60) when unset during creation.
+ type: int
+ aliases: [ jp_interval ]
+ inbound_join_prune_filter_policy:
+ description:
+ - The interface-level inbound join/prune filter policy.
+ - The M(cisco.aci.aci_pim_route_map_policy) can be used for this.
+ - To delete it, pass an empty string.
+ type: str
+ aliases: [ inbound_filter ]
+ outbound_join_prune_filter_policy:
+ description:
+ - The interface-level outbound join/prune filter policy.
+ - The M(cisco.aci.aci_pim_route_map_policy) can be used for this.
+ - To delete it, pass an empty string.
+ type: str
+ aliases: [ outbound_filter ]
+ neighbor_filter_policy:
+ description:
+ - The Interface-level neighbor filter policy.
+ - The M(cisco.aci.aci_pim_route_map_policy) can be used for this.
+ - To delete it, pass an empty string.
+ type: str
+ aliases: [ neighbor_filter ]
+ description:
+ description:
+ - The description of the PIM interface policy.
+ 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) used must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant) module can be used for this.
+seealso:
+- module: cisco.aci.aci_tenant
+- module: cisco.aci.aci_pim_route_map_policy
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(pim:IfPol).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Gaspard Micol (@gmicol)
+"""
+
+EXAMPLES = r"""
+- name: Create a PIM interface policy
+ cisco.aci.aci_interface_policy_pim:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: production
+ pim: my_pim_policy
+ control_state: [multicast_domain_boundary, strict_rfc_compliant]
+ designated_router_delay: 10
+ designated_router_priority: tens_of_micro
+ hello_interval: 5
+ join_prune_interval: 15
+ inbound_join_prune_filter_policy: my_pim_route_map_policy_1
+ outbound_join_prune_filter_policy: my_pim_route_map_policy_2
+ neighbor_filter_policy: my_pim_route_map_policy_3
+ state: present
+ delegate_to: localhost
+
+- name: Query a PIM interface policy
+ cisco.aci.aci_interface_policy_pim:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: production
+ pim: my_pim_policy
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all PIM interface policies in tenant production
+ cisco.aci.aci_interface_policy_pim:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: production
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Delete a PIM interface policy
+ cisco.aci.aci_interface_policy_pim:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: production
+ pim: my_pim_policy
+ state: present
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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
+from ansible_collections.cisco.aci.plugins.module_utils.constants import (
+ MATCH_PIM_INTERFACE_POLICY_CONTROL_STATE_MAPPING,
+ MATCH_PIM_INTERFACE_POLICY_AUTHENTICATION_TYPE_MAPPING,
+)
+
+
+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
+ pim=dict(type="str", aliases=["pim_interface_policy", "name"]), # Not required for querying all objects
+ description=dict(type="str", aliases=["descr"]),
+ authentication_key=dict(type="str", aliases=["auth_key"], no_log=True),
+ authentication_type=dict(type="str", choices=["none", "md5_hmac"], aliases=["auth_type"]),
+ control_state=dict(type="list", elements="str", choices=["multicast_domain_boundary", "strict_rfc_compliant", "passive"]),
+ designated_router_delay=dict(type="int", aliases=["delay"]),
+ designated_router_priority=dict(type="int", aliases=["prio"]),
+ hello_interval=dict(type="int"),
+ join_prune_interval=dict(type="int", aliases=["jp_interval"]),
+ inbound_join_prune_filter_policy=dict(type="str", aliases=["inbound_filter"]),
+ outbound_join_prune_filter_policy=dict(type="str", aliases=["outbound_filter"]),
+ neighbor_filter_policy=dict(type="str", aliases=["neighbor_filter"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ name_alias=dict(type="str"),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["pim", "tenant"]],
+ ["state", "present", ["pim", "tenant"]],
+ ],
+ )
+
+ aci = ACIModule(module)
+
+ tenant = module.params.get("tenant")
+ pim = module.params.get("pim")
+ authentication_key = module.params.get("authentication_key")
+ authentication_type = MATCH_PIM_INTERFACE_POLICY_AUTHENTICATION_TYPE_MAPPING.get(module.params.get("authentication_type"))
+ description = module.params.get("description")
+ name_alias = module.params.get("name_alias")
+ state = module.params.get("state")
+
+ designated_router_delay = module.params.get("designated_router_delay")
+ if designated_router_delay is not None and designated_router_delay not in range(1, 65536):
+ module.fail_json(msg="Parameter 'designated_router_delay' is only valid in range between 1 and 65535.")
+
+ designated_router_priority = module.params.get("designated_router_priority")
+ if designated_router_priority is not None and designated_router_priority not in range(1, 4294967296):
+ module.fail_json(msg="Parameter 'designated_router_priority' is only valid in range between 1 and 4294967295.")
+
+ hello_interval = module.params.get("hello_interval")
+ if hello_interval is not None and hello_interval not in range(1, 18724287):
+ module.fail_json(msg="Parameter 'hello_interval' is only valid in range between 1 and 18724286.")
+
+ join_prune_interval = module.params.get("join_prune_interval")
+ if join_prune_interval is not None and join_prune_interval not in range(60, 65521):
+ module.fail_json(msg="Parameter 'join_prune_interval' is only valid in range between 60 and 65520.")
+
+ if module.params.get("control_state"):
+ control_state = ",".join([MATCH_PIM_INTERFACE_POLICY_CONTROL_STATE_MAPPING.get(v) for v in module.params.get("control_state")])
+ else:
+ control_state = None
+
+ child_classes = dict(
+ pimJPInbFilterPol=module.params.get("inbound_join_prune_filter_policy"),
+ pimJPOutbFilterPol=module.params.get("outbound_join_prune_filter_policy"),
+ pimNbrFilterPol=module.params.get("neighbor_filter_policy"),
+ )
+
+ 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="pimIfPol",
+ aci_rn="pimifpol-{0}".format(pim),
+ module_object=pim,
+ target_filter={"name": pim},
+ ),
+ child_classes=list(child_classes.keys()),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ child_configs = []
+ for class_name, class_input in child_classes.items():
+ if class_input is not None:
+ if class_input == "" and isinstance(aci.existing, list) and len(aci.existing) > 0:
+ for child in aci.existing[0].get("pimIfPol", {}).get("children", {}):
+ if child.get(class_name):
+ child_configs.append(dict([(class_name, dict(attributes=dict(status="deleted")))]))
+ elif class_input != "":
+ child_configs.append(
+ dict(
+ [
+ (
+ class_name,
+ dict(
+ attributes=dict(),
+ children=[
+ dict(
+ rtdmcRsFilterToRtMapPol=dict(
+ attributes=dict(
+ tDn="uni/tn-{0}/rtmap-{1}".format(tenant, class_input),
+ ),
+ )
+ )
+ ],
+ ),
+ )
+ ]
+ )
+ )
+
+ aci.payload(
+ aci_class="pimIfPol",
+ class_config=dict(
+ name=pim,
+ descr=description,
+ authKey=authentication_key,
+ authT=authentication_type,
+ ctrl=control_state,
+ drDelay=designated_router_delay,
+ drPrio=designated_router_priority,
+ helloItvl=hello_interval,
+ jpInterval=join_prune_interval,
+ nameAlias=name_alias,
+ ),
+ child_configs=child_configs,
+ )
+
+ aci.get_diff(aci_class="pimIfPol")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_storm_control.py b/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_storm_control.py
new file mode 100644
index 000000000..19b67070d
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_interface_policy_storm_control.py
@@ -0,0 +1,434 @@
+#!/usr/bin/python
+
+# Copyright: (c) 2023, Eric Girard <@netgirard>
+# Copyright: (c) 2024, Gaspard Micol (@gmicol) <gmicol@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": "certified"}
+
+DOCUMENTATION = r"""
+---
+module: aci_interface_policy_storm_control
+short_description: Manage Storm Control interface policies (stormctrl:IfPol)
+description:
+- Manage Storm Control interface policies on Cisco ACI fabrics.
+options:
+ storm_control_policy:
+ description:
+ - The Storm Control interface policy name.
+ type: str
+ aliases: [ storm_control, storm_control_name, name ]
+ description:
+ description:
+ - The description for the Storm interface policy name.
+ 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
+ storm_control_action:
+ description:
+ - The storm control action to take when triggered.
+ type: str
+ choices: [drop, shutdown]
+ storm_control_soak_action:
+ description:
+ - The number of instances before triggering shutdown.
+ type: int
+ all_types_configuration:
+ description:
+ - The rates configuration for all packets type.
+ type: dict
+ aliases: [ all_types ]
+ suboptions:
+ rate:
+ description:
+ - The rate for all packet types.
+ type: str
+ burst_rate:
+ description:
+ - The burst rate of all packet types.
+ type: str
+ rate_type:
+ description:
+ - The type of rate of all packet types.
+ - Choice between percentage of the bandiwth C(percentage) or packet per second C(pps)
+ type: str
+ choices: [ percentage, pps ]
+ required: true
+ broadcast_configuration:
+ description:
+ - The rates configuration of broadcast packets.
+ type: dict
+ aliases: [ broadcast ]
+ suboptions:
+ rate:
+ description:
+ - The rate for broadcast packets.
+ type: str
+ burst_rate:
+ description:
+ - The burst rate of broadcast packets.
+ type: str
+ rate_type:
+ description:
+ - The type of rate of all packet types.
+ - Choice between percentage of the bandiwth C(percentage) or packet per second C(pps)
+ type: str
+ choices: [ percentage, pps ]
+ required: true
+ multicast_configuration:
+ description:
+ - The rates configuration of multicast packets.
+ type: dict
+ aliases: [ multicast ]
+ suboptions:
+ rate:
+ description:
+ - The rate for multicast packets.
+ type: str
+ burst_rate:
+ description:
+ - The burst rate of multicast packets.
+ type: str
+ rate_type:
+ description:
+ - The type of rate of all packet types.
+ - Choice between percentage of the bandiwth C(percentage) or packet per second C(pps)
+ type: str
+ choices: [ percentage, pps ]
+ required: true
+ unicast_configuration:
+ description:
+ - The rates configuration of unicast packets.
+ type: dict
+ aliases: [ unicast ]
+ suboptions:
+ rate:
+ description:
+ - The rate for unicast packets.
+ type: str
+ burst_rate:
+ description:
+ - The burst rate of unicast packets.
+ type: str
+ rate_type:
+ description:
+ - The type of rate of all packet types.
+ - Choice between percentage of the bandiwth C(percentage) or packet per second C(pps)
+ type: str
+ choices: [ percentage, pps ]
+ required: true
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+seealso:
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(stormctrl:IfPol).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Eric Girard (@netgirard)
+- Gaspard Micol (@gmicol)
+"""
+
+EXAMPLES = r"""
+- name: Add a new Storm Control Interface Policy
+ cisco.aci.aci_interface_policy_storm_control:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ storm_control_policy: my_storm_control_policy
+ description: My Storm Control Policy
+ all_types_configuration:
+ rate: 80
+ burst_rate: 100
+ rate_type: percentage
+ storm_control_action: shutdown
+ storm_control_soak_action: 5
+ state: present
+ delegate_to: localhost
+
+- name: Query a Storm Control Interface Policy
+ cisco.aci.aci_interface_policy_storm_control:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ storm_control_policy: my_storm_control_policy
+ state: query
+ delegate_to: localhost
+
+- name: Query all Storm Control Interface Policies
+ cisco.aci.aci_interface_policy_storm_control:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+
+- name: Delete a Storm Control Interface Policy
+ cisco.aci.aci_interface_policy_storm_control:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ storm_control_policy: my_storm_control_policy
+ state: absent
+ delegate_to: localhost
+"""
+
+RETURN = r"""
+current:
+ description: The existing configuration from the APIC after the module has finished
+ returned: success
+ type: list
+ sample:
+ [
+ {
+ "cdpIfPol": {
+ "attributes": {
+ "adminSt": "disabled",
+ "annotation": "",
+ "descr": "Ansible Created CDP Test Policy",
+ "dn": "uni/infra/cdpIfP-Ansible_CDP_Test_Policy",
+ "name": "Ansible_CDP_Test_Policy",
+ "nameAlias": "",
+ "ownerKey": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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,
+ storm_control_policy_rate_spec,
+)
+
+
+def get_rates_configuration(module, configuration, percentage, pps, burst_percentage, burst_pps):
+ if configuration is None:
+ return {}
+ rate = configuration.get("rate")
+ burst_rate = configuration.get("burst_rate")
+ rate_type = configuration.get("rate_type")
+
+ if rate_type == "percentage":
+ for rate_name, rate_value in dict(rate=rate, burst_rate=burst_rate).items():
+ if rate_value is None or not (0 <= float(rate_value) <= 100):
+ module.fail_json(
+ msg="If argument rate_type is percentage, the {0} needs to be a value between 0 and 100 inclusive, got {1}".format(
+ rate_name,
+ rate_value,
+ )
+ )
+ return {
+ percentage: "{0:.6f}".format(float(rate)),
+ pps: "unspecified",
+ burst_percentage: "{0:.6f}".format(float(burst_rate)),
+ burst_pps: "unspecified",
+ }
+ elif rate_type == "pps":
+ return {pps: rate, burst_pps: burst_rate}
+
+
+def main():
+ argument_spec = aci_argument_spec()
+ argument_spec.update(aci_annotation_spec())
+ argument_spec.update(aci_owner_spec())
+ argument_spec.update(
+ storm_control_policy=dict(
+ type="str", required=False, aliases=["name", "storm_control", "storm_control_name"]
+ ), # Not required for querying all objects
+ description=dict(type="str", aliases=["descr"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ name_alias=dict(type="str"),
+ all_types_configuration=dict(type="dict", options=storm_control_policy_rate_spec(), aliases=["all_types"]),
+ broadcast_configuration=dict(type="dict", options=storm_control_policy_rate_spec(), aliases=["broadcast"]),
+ multicast_configuration=dict(type="dict", options=storm_control_policy_rate_spec(), aliases=["multicast"]),
+ unicast_configuration=dict(type="dict", options=storm_control_policy_rate_spec(), aliases=["unicast"]),
+ storm_control_action=dict(type="str", choices=["drop", "shutdown"]),
+ storm_control_soak_action=dict(type="int"),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["storm_control_policy"]],
+ ["state", "present", ["storm_control_policy"]],
+ ],
+ mutually_exclusive=[
+ ("all_types_configuration", "broadcast_configuration"),
+ ("all_types_configuration", "multicast_configuration"),
+ ("all_types_configuration", "unicast_configuration"),
+ ],
+ )
+
+ aci = ACIModule(module)
+
+ storm_control_policy = module.params.get("storm_control_policy")
+ description = module.params.get("description")
+ state = module.params.get("state")
+ name_alias = module.params.get("name_alias")
+ storm_control_action = module.params.get("storm_control_action")
+ storm_control_soak_action = module.params.get("storm_control_soak_action")
+ all_types_configuration = module.params.get("all_types_configuration")
+ broadcast_configuration = module.params.get("broadcast_configuration")
+ multicast_configuration = module.params.get("multicast_configuration")
+ unicast_configuration = module.params.get("unicast_configuration")
+
+ rates_input = {}
+
+ if all_types_configuration is not None:
+ rates_input.update(get_rates_configuration(module, all_types_configuration, "rate", "ratePps", "burstRate", "burstPps"))
+ storm_control_types = "Invalid"
+ elif any([broadcast_configuration, multicast_configuration, unicast_configuration]):
+ rates_input.update(get_rates_configuration(module, broadcast_configuration, "bcRate", "bcRatePps", "bcBurstRate", "bcBurstPps"))
+ rates_input.update(get_rates_configuration(module, multicast_configuration, "mcRate", "mcRatePps", "mcBurstRate", "mcBurstPps"))
+ rates_input.update(get_rates_configuration(module, unicast_configuration, "uucRate", "uucRatePps", "uucBurstRate", "uucBurstPps"))
+ storm_control_types = "Valid"
+
+ aci.construct_url(
+ root_class=dict(
+ aci_class="infraInfra",
+ aci_rn="infra",
+ ),
+ subclass_1=dict(
+ aci_class="stormctrlIfPol",
+ aci_rn="stormctrlifp-{0}".format(storm_control_policy),
+ module_object=storm_control_policy,
+ target_filter={"name": storm_control_policy},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ class_config = dict(
+ name=storm_control_policy,
+ descr=description,
+ nameAlias=name_alias,
+ isUcMcBcStormPktCfgValid=storm_control_types,
+ stormCtrlAction=storm_control_action,
+ stormCtrlSoakInstCount=storm_control_soak_action,
+ )
+ class_config.update(rates_input)
+ aci.payload(
+ aci_class="stormctrlIfPol",
+ class_config=class_config,
+ )
+
+ aci.get_diff(aci_class="stormctrlIfPol")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_key_policy.py b/ansible_collections/cisco/aci/plugins/modules/aci_key_policy.py
new file mode 100644
index 000000000..27ebe292a
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_key_policy.py
@@ -0,0 +1,325 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@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_key_policy
+short_description: Manage Key Policy (fv:KeyPol)
+description:
+- Manage Key Policies for KeyChain Policies on Cisco ACI fabrics.
+options:
+ tenant:
+ description:
+ - The name of an existing tenant.
+ type: str
+ aliases: [ tenant_name ]
+ keychain_policy:
+ description:
+ - The name of an existing keychain policy.
+ type: str
+ aliases: [ keychain_policy_name ]
+ id:
+ description:
+ - The object identifier.
+ type: int
+ start_time:
+ description:
+ - The start time of the key policy.
+ - The APIC defaults to C(now) when unset during creation.
+ - The format is YYYY-MM-DD HH:MM:SS
+ type: str
+ end_time:
+ description:
+ - The end time of the key policy.
+ - The APIC defaults to C(infinite) when unset during creation.
+ - The format is YYYY-MM-DD HH:MM:SS
+ type: str
+ pre_shared_key:
+ description:
+ - The pre-shared authentifcation key.
+ - When using I(pre_shared_key) this module will always show as C(changed) as the module cannot know what the currently configured key is.
+ type: str
+ description:
+ description:
+ - The description for the keychain policy.
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+notes:
+- The C(tenant) and C(keychain_policy) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant) and M(cisco.aci.aci_keychain_policy) can be used for this.
+seealso:
+- module: cisco.aci.aci_tenant
+- module: cisco.aci.aci_keychain_policy
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC classes
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Gaspard Micol (@gmicol)
+"""
+
+EXAMPLES = r"""
+- name: Add a new key policy
+ cisco.aci.aci_key_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ keychain_policy: my_keychain_policy
+ id: 1
+ start_time: now
+ end_time: infinite
+ pre_shared_key: my_password
+ state: present
+ delegate_to: localhost
+
+- name: Delete an key policy
+ cisco.aci.aci_key_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ keychain_policy: my_keychain_policy
+ id: 1
+ state: absent
+ delegate_to: localhost
+
+- name: Query an key policy
+ cisco.aci.aci_key_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ keychain_policy: my_keychain_policy
+ id: 1
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all key policies in my_keychain_policy
+ cisco.aci.aci_key_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ keychain_policy: my_keychain_policy
+ state: query
+ delegate_to: localhost
+ register: query_result
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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"]),
+ keychain_policy=dict(type="str", aliases=["keychain_policy_name"], no_log=False),
+ id=dict(type="int"),
+ start_time=dict(type="str"),
+ end_time=dict(type="str"),
+ pre_shared_key=dict(type="str", no_log=True),
+ description=dict(type="str", aliases=["descr"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["tenant", "keychain_policy", "id"]],
+ ["state", "present", ["tenant", "keychain_policy", "id"]],
+ ],
+ )
+
+ tenant = module.params.get("tenant")
+ keychain_policy = module.params.get("keychain_policy")
+ id = module.params.get("id")
+ start_time = module.params.get("start_time")
+ end_time = module.params.get("end_time")
+ pre_shared_key = module.params.get("pre_shared_key")
+ description = module.params.get("description")
+ state = module.params.get("state")
+
+ 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="fvKeyChainPol",
+ aci_rn="keychainp-{0}".format(keychain_policy),
+ module_object=keychain_policy,
+ target_filter={"name": keychain_policy},
+ ),
+ subclass_2=dict(
+ aci_class="fvKeyPol",
+ aci_rn="keyp-{0}".format(id),
+ module_object=id,
+ target_filter={"id": id},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ class_config = dict(
+ id=id,
+ startTime=start_time,
+ endTime=end_time,
+ descr=description,
+ )
+ if pre_shared_key is not None:
+ class_config.update(preSharedKey=pre_shared_key)
+
+ aci.payload(
+ aci_class="fvKeyPol",
+ class_config=class_config,
+ )
+
+ aci.get_diff(aci_class="fvKeyPol")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_keychain_policy.py b/ansible_collections/cisco/aci/plugins/modules/aci_keychain_policy.py
new file mode 100644
index 000000000..a9776cf59
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_keychain_policy.py
@@ -0,0 +1,276 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@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_keychain_policy
+short_description: Manage KeyChain Policy (fv:KeyChainPol)
+description:
+- Manage KeyChain Policies for tenants on Cisco ACI fabrics.
+options:
+ tenant:
+ description:
+ - The name of an existing tenant.
+ type: str
+ aliases: [ tenant_name ]
+ keychain_policy:
+ description:
+ - The name of the keychain policy.
+ type: str
+ aliases: [ keychain_policy_name, name ]
+ description:
+ description:
+ - The description for the keychain policy.
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+notes:
+- The C(tenant) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant) can be used for this.
+seealso:
+- module: cisco.aci.aci_tenant
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC classes
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Gaspard Micol (@gmicol)
+"""
+
+EXAMPLES = r"""
+- name: Add a new keychain policy
+ cisco.aci.aci_keychain_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ keychain_policy: my_keychain_policy
+ state: present
+ delegate_to: localhost
+
+- name: Delete an keychain policy
+ cisco.aci.aci_keychain_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ keychain_policy: my_keychain_policy
+ state: absent
+ delegate_to: localhost
+
+- name: Query an keychain policy
+ cisco.aci.aci_keychain_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ keychain_policy: my_keychain_policy
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query an keychain policy in my_tenant
+ cisco.aci.aci_keychain_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ state: query
+ delegate_to: localhost
+ register: query_result
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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"]),
+ keychain_policy=dict(type="str", aliases=["keychain_policy_name", "name"], no_log=False),
+ description=dict(type="str", aliases=["descr"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["tenant", "keychain_policy"]],
+ ["state", "present", ["tenant", "keychain_policy"]],
+ ],
+ )
+
+ tenant = module.params.get("tenant")
+ description = module.params.get("description")
+ keychain_policy = module.params.get("keychain_policy")
+ state = module.params.get("state")
+
+ 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="fvKeyChainPol",
+ aci_rn="keychainp-{0}".format(keychain_policy),
+ module_object=keychain_policy,
+ target_filter={"name": keychain_policy},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class="fvKeyChainPol",
+ class_config=dict(
+ name=keychain_policy,
+ descr=description,
+ ),
+ )
+
+ aci.get_diff(aci_class="fvKeyChainPol")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l2out.py b/ansible_collections/cisco/aci/plugins/modules/aci_l2out.py
index 974c3c8e9..fdba63ef5 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_l2out.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l2out.py
@@ -14,7 +14,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_l2out
-short_description: Manage Layer2 Out (L2Out) objects.
+short_description: Manage Layer2 Out (L2Out) objects (l2ext:Out)
description:
- Manage Layer2 Out configuration on Cisco ACI fabrics.
options:
@@ -64,7 +64,7 @@ notes:
The M(cisco.aci.aci_tenant) modules can be used for this.
seealso:
- name: APIC Management Information Model reference
- description: More information about the internal APIC class B(fvTenant).
+ description: More information about the internal APIC class B(l2ext:Out).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Sudhakar Shet Kudtarkar (@kudtarkar1)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l2out_extepg.py b/ansible_collections/cisco/aci/plugins/modules/aci_l2out_extepg.py
index 3df19e9da..d633a7aae 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_l2out_extepg.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l2out_extepg.py
@@ -15,9 +15,9 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_l2out_extepg
-short_description: Manage External Network Instance (L2Out External EPG) objects (l2extInstP).
+short_description: Manage External Network Instance (L2Out External EPG) objects (l2ext:InstP).
description:
-- Manage External Network Instance (L2Out External EPG) objects (l2extInstP) on ACI fabrics.
+- Manage External Network Instance (L2Out External EPG) objects on ACI fabrics.
options:
tenant:
description:
@@ -63,7 +63,7 @@ notes:
The M(cisco.aci.aci_tenant) and M(cisco.aci.aci_l2out) modules can be used for this.
seealso:
- name: APIC Management Information Model reference
- description: More information about the internal APIC class B(fvtenant) and B(l2extOut).
+ description: More information about the internal APIC class B(l2ext:InstP).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Sudhakar Shet Kudtarkar (@kudtarkar1)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l2out_extepg_to_contract.py b/ansible_collections/cisco/aci/plugins/modules/aci_l2out_extepg_to_contract.py
index 205be3795..0ed57326f 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_l2out_extepg_to_contract.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l2out_extepg_to_contract.py
@@ -15,7 +15,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_l2out_extepg_to_contract
-short_description: Bind Contracts to L2 External End Point Groups (EPGs)
+short_description: Bind Contracts to L2 External End Point Groups (EPGs) (fv:RsCons and fv:RsProv)
description:
- Bind Contracts to L2 External End Point Groups (EPGs) on ACI fabrics.
options:
@@ -69,7 +69,7 @@ notes:
The M(cisco.aci.aci_tenant), M(cisco.aci.aci_l2out) and M(cisco.aci.aci_l2out_extepg) modules can be used for this.
seealso:
- name: APIC Management Information Model reference
- description: More information about the internal APIC class B(fvtenant), B(l2extInstP) and B(l2extOut).
+ description: More information about the internal APIC classes B((fv:RsCons) B(fv:RsProv).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Sudhakar Shet Kudtarkar (@kudtarkar1)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l2out_logical_interface_path.py b/ansible_collections/cisco/aci/plugins/modules/aci_l2out_logical_interface_path.py
index 6be588bcd..0d8130139 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_l2out_logical_interface_path.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l2out_logical_interface_path.py
@@ -12,7 +12,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_l2out_logical_interface_path
-short_description: Manage Layer 2 Outside (L2Out) logical interface path (l2extRsPathL2OutAtt)
+short_description: Manage Layer 2 Outside (L2Out) logical interface path (l2ext:RsPathL2OutAtt)
description:
- Manage interface path entry of L2 outside node (BD extension) on Cisco ACI fabrics.
options:
@@ -79,7 +79,7 @@ seealso:
- module: aci_l2out_logical_interface_profile
- module: aci_l2out_extepg
- name: APIC Management Information Model reference
- description: More information about the internal APIC classes
+ description: More information about the internal APIC class B(l2ext:RsPathL2OutAtt).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Oleksandr Kreshchenko (@alexkross)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l2out_logical_interface_profile.py b/ansible_collections/cisco/aci/plugins/modules/aci_l2out_logical_interface_profile.py
index 93e8fd195..c1d0b3d61 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_l2out_logical_interface_profile.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l2out_logical_interface_profile.py
@@ -55,7 +55,7 @@ seealso:
- module: aci_l2out_logical_interface_path
- module: aci_l2out_extepg
- name: APIC Management Information Model reference
- description: More information about the internal APIC classes
+ description: More information about the internal APIC class B(l2ext:LIfP).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Oleksandr Kreshchenko (@alexkross)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l2out_logical_node_profile.py b/ansible_collections/cisco/aci/plugins/modules/aci_l2out_logical_node_profile.py
index 12a1aa6f5..6fa04db01 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_l2out_logical_node_profile.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l2out_logical_node_profile.py
@@ -49,7 +49,7 @@ seealso:
- module: aci_l2out_logical_interface_path
- module: aci_l2out_extepg
- name: APIC Management Information Model reference
- description: More information about the internal APIC classes
+ description: More information about the internal APIC class B(l2ext:LNodeP).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Oleksandr Kreshchenko (@alexkross)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l3out.py b/ansible_collections/cisco/aci/plugins/modules/aci_l3out.py
index 56f158b3d..73d51fc63 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_l3out.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l3out.py
@@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@cisco.com>
+# Copyright: (c) 2023, Akini Ross (@akinross) <akinross@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
@@ -34,6 +35,7 @@ options:
vrf:
description:
- Name of the VRF being associated with the L3Out.
+ - SR-MPLS Infra L3out requires the VRF to be 'overlay-1'.
type: str
aliases: [ vrf_name ]
domain:
@@ -60,6 +62,8 @@ options:
description:
- Indicate whether MPLS (Multi-Protocol Label Switching) is enabled or not.
- The APIC defaults to C(no) when unset during creation.
+ - SR-MPLS is only supported in APIC v5.0 and above.
+ - The child classes C(mplsExtP), C(mplsRsLabelPol) and C(l3extProvLbl) will be displayed in output only when C(yes).
type: str
choices: [ "no", "yes" ]
l3protocol:
@@ -70,6 +74,7 @@ options:
- First example, to add BGP protocol to an l3out with OSPF protocol, the user must enter C([ bgp, ospf ]) even though "ospf" was provided before.
- Second example, to change the protocol from OSPF to EIGRP, the user must simply enter C([ eigrp ]) and the previous OSPF protocol will be deleted.
- To remove all existing protocols, the user must enter C([ static ]).
+ - SR-MPLS Infra L3out requires the l3protocol to be 'bgp'.
type: list
elements: str
choices: [ bgp, eigrp, ospf, pim, static ]
@@ -165,6 +170,7 @@ seealso:
author:
- Rostyslav Davydenko (@rost-d)
- Gaspard Micol (@gmicol)
+- Akini Ross (@akinross)
"""
EXAMPLES = r"""
@@ -444,39 +450,17 @@ def main():
dict(l3extRsL3DomAtt=dict(attributes=dict(tDn="uni/l3dom-{0}".format(domain)))),
dict(l3extRsEctx=dict(attributes=dict(tnFvCtxName=vrf))),
]
- if l3protocol is not None:
- l3protocol_child_configs = dict(
- bgp=dict(bgpExtP=dict(attributes=dict(status="deleted"))),
- eigrp=dict(eigrpExtP=dict(attributes=dict(status="deleted"))),
- ospf=dict(ospfExtP=dict(attributes=dict(status="deleted"))),
- pim=dict(pimExtP=dict(attributes=dict(status="deleted"))),
+
+ if tenant == "infra" and mpls == "yes":
+ if l3protocol != ["bgp"] and state == "present":
+ module.fail_json(msg="The l3protocol parameter must be 'bgp' when tenant is 'infra' and mpls is 'yes'")
+ if vrf != "overlay-1" and state == "present":
+ module.fail_json(msg="The vrf parameter must be 'overlay-1' when tenant is 'infra' and mpls is 'yes'")
+ child_classes += ["mplsExtP", "mplsRsLabelPol", "l3extProvLbl"]
+ child_configs.append(
+ dict(mplsExtP=dict(attributes=dict(), children=[dict(mplsRsLabelPol=dict(attributes=dict(tDn="uni/tn-infra/mplslabelpol-default")))]))
)
- for protocol in l3protocol:
- if protocol == "bgp":
- l3protocol_child_configs["bgp"] = dict(bgpExtP=dict(attributes=dict(descr="")))
- elif protocol == "eigrp":
- l3protocol_child_configs["eigrp"] = dict(eigrpExtP=dict(attributes=dict(asn=asn)))
- elif protocol == "ospf":
- if isinstance(ospf, dict):
- ospf["area_ctrl"] = ",".join(ospf.get("area_ctrl"))
- l3protocol_child_configs["ospf"] = dict(
- ospfExtP=dict(
- attributes=dict(
- areaCost=ospf.get("area_cost"),
- areaCtrl=ospf.get("area_ctrl"),
- areaId=ospf.get("area_id"),
- areaType=ospf.get("area_type"),
- descr=ospf.get("description"),
- multipodInternal=ospf.get("multipod_internal"),
- nameAlias=ospf.get("name_alias"),
- )
- )
- )
- else:
- l3protocol_child_configs["ospf"] = dict(ospfExtP=dict(attributes=dict(descr="")))
- elif protocol == "pim":
- l3protocol_child_configs["pim"] = dict(pimExtP=dict(attributes=dict(descr="")))
- child_configs.extend(list(l3protocol_child_configs.values()))
+ child_configs.append(dict(l3extProvLbl=dict(attributes=dict(name=l3out))))
aci.construct_url(
root_class=dict(
@@ -497,6 +481,46 @@ def main():
aci.get_existing()
if state == "present":
+ if l3protocol is not None:
+ if isinstance(aci.existing, list) and len(aci.existing) > 0:
+ for child in aci.existing[0].get("l3extOut", {}).get("children", {}):
+ if child.get("bgpExtP") and "bgp" not in l3protocol:
+ child_configs.append(dict(bgpExtP=dict(attributes=dict(status="deleted"))))
+ if child.get("eigrpExtP") and "eigrp" not in l3protocol:
+ child_configs.append(dict(eigrpExtP=dict(attributes=dict(status="deleted"))))
+ if child.get("ospfExtP") and "ospf" not in l3protocol:
+ child_configs.append(dict(ospfExtP=dict(attributes=dict(status="deleted"))))
+ if child.get("pimExtP") and "pim" not in l3protocol:
+ child_configs.append(dict(pimExtP=dict(attributes=dict(status="deleted"))))
+
+ for protocol in l3protocol:
+ if protocol == "bgp":
+ child_configs.append(dict(bgpExtP=dict(attributes=dict(descr=""))))
+ elif protocol == "eigrp":
+ child_configs.append(dict(eigrpExtP=dict(attributes=dict(asn=asn))))
+ elif protocol == "ospf":
+ if isinstance(ospf, dict):
+ ospf["area_ctrl"] = ",".join(ospf.get("area_ctrl"))
+ child_configs.append(
+ dict(
+ ospfExtP=dict(
+ attributes=dict(
+ areaCost=ospf.get("area_cost"),
+ areaCtrl=ospf.get("area_ctrl"),
+ areaId=ospf.get("area_id"),
+ areaType=ospf.get("area_type"),
+ descr=ospf.get("description"),
+ multipodInternal=ospf.get("multipod_internal"),
+ nameAlias=ospf.get("name_alias"),
+ )
+ )
+ )
+ )
+ else:
+ child_configs.append(dict(ospfExtP=dict(attributes=dict(descr=""))))
+ elif protocol == "pim":
+ child_configs.append(dict(pimExtP=dict(attributes=dict(descr=""))))
+
aci.payload(
aci_class="l3extOut",
class_config=dict(
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_bfd_interface_profile.py b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_bfd_interface_profile.py
new file mode 100644
index 000000000..193ff0c1d
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_bfd_interface_profile.py
@@ -0,0 +1,367 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Anvitha Jain (@anvjain) <anvjain@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_l3out_bfd_interface_profile
+short_description: Manage L3Out BFD Interface profiles (bfd:IfP)
+description:
+- Manage L3Out BFD Interface profile configuration on Cisco ACI fabrics
+- Only available in APIC version 5.2 or later and for non-cloud APICs
+options:
+ tenant:
+ description:
+ - Name of an existing tenant
+ type: str
+ aliases: [ tenant_name ]
+ l3out:
+ description:
+ - Name of an existing L3Out
+ type: str
+ aliases: [ l3out_name ]
+ l3out_logical_node_profile:
+ description:
+ - Name of an existing L3Out Logical Node profile
+ type: str
+ aliases: [ logical_node_profile, logical_node_profile_name ]
+ l3out_logical_interface_profile:
+ description:
+ - Name of an existing L3Out Logical Interface profile
+ type: str
+ aliases: [ logical_interface_profile, logical_interface_profile_name ]
+ name:
+ description:
+ - Name of the L3Out BFD Interface profile object
+ type: str
+ aliases: [ bfd_multihop_interface_profile ]
+ name_alias:
+ description:
+ - Name Alias of the L3Out BFD Interface profile object
+ type: str
+ description:
+ description:
+ - Description of the L3Out BFD Interface profile object
+ type: str
+ aliases: [ descr ]
+ authentication_type:
+ description:
+ - Authentication Type of the L3Out BFD Interface profile object
+ - APIC sets the default value to none
+ type: str
+ choices: [ none, sha1 ]
+ key:
+ description:
+ - Authentication Key of the L3Out BFD Interface profile object
+ type: str
+ key_id:
+ description:
+ - Authentication Key ID of the L3Out BFD Interface profile object
+ - APIC sets the default value to 3
+ - Allowed range is 1-255
+ type: int
+ bfd_interface_policy:
+ description:
+ - The name of the Interface policy
+ type: str
+ aliases: [ interface_policy, interface_policy_name ]
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+
+notes:
+- The C(tenant), c(l3out), C(l3out_logical_node_profile) and C(l3out_logical_interface_profile) must exist before using this module in your playbook
+ The M(cisco.aci.aci_tenant) modules can be used for this
+seealso:
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(bfd:IfP)
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+- module: cisco.aci.aci_tenant
+- module: cisco.aci.aci_l3out
+- module: cisco.aci.aci_l3out_logical_node_profile
+- module: cisco.aci.aci_l3out_logical_interface_profile
+- module: cisco.aci.aci_interface_policy_bfd
+author:
+- Anvitha Jain (@anvjain)
+"""
+
+EXAMPLES = r"""
+- name: Add a new L3Out BFD Interface Profile
+ cisco.aci.aci_l3out_bfd_interface_profile:
+ username: admin
+ password: SomeSecretPassword
+ tenant: ansible_tenant
+ l3out: ansible_l3out
+ l3out_logical_node_profile: ansible_node_profile
+ l3out_logical_interface_profile: ansible_interface_profile
+ state: present
+ delegate_to: localhost
+
+- name: Query a new L3Out BFD Interface Profile
+ cisco.aci.aci_l3out_bfd_interface_profile:
+ username: admin
+ password: SomeSecretPassword
+ tenant: ansible_tenant
+ l3out: ansible_l3out
+ l3out_logical_node_profile: ansible_node_profile
+ l3out_logical_interface_profile: ansible_interface_profile
+ state: query
+ delegate_to: localhost
+
+- name: Query all L3Out BFD Interface Profile
+ cisco.aci.aci_l3out_bfd_interface_profile:
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+
+- name: Delete L3Out BFD Interface Profile
+ cisco.aci.aci_l3out_bfd_interface_profile:
+ username: admin
+ password: SomeSecretPassword
+ tenant: ansible_tenant
+ l3out: ansible_l3out
+ l3out_logical_node_profile: ansible_node_profile
+ l3out_logical_interface_profile: ansible_interface_profile
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+ 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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class "/></imdata>'
+ 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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+ 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
+
+
+def main():
+ argument_spec = aci_argument_spec()
+ argument_spec.update(aci_annotation_spec())
+ argument_spec.update(
+ tenant=dict(type="str", aliases=["tenant_name"]),
+ l3out=dict(type="str", aliases=["l3out_name"]),
+ l3out_logical_node_profile=dict(type="str", aliases=["logical_node_profile_name", "logical_node_profile"]),
+ l3out_logical_interface_profile=dict(type="str", aliases=["logical_interface_profile_name", "logical_interface_profile"]),
+ name=dict(type="str", aliases=["bfd_multihop_interface_profile"]),
+ name_alias=dict(type="str"),
+ description=dict(type="str", aliases=["descr"]),
+ authentication_type=dict(type="str", choices=["none", "sha1"]),
+ key=dict(type="str", no_log=True),
+ key_id=dict(type="int"),
+ bfd_interface_policy=dict(type="str", aliases=["interface_policy", "interface_policy_name"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["tenant", "l3out", "l3out_logical_node_profile", "l3out_logical_interface_profile"]],
+ ["state", "present", ["tenant", "l3out", "l3out_logical_node_profile", "l3out_logical_interface_profile", "bfd_interface_policy"]],
+ ["authentication_type", "sha1", ["key"]],
+ ],
+ )
+
+ tenant = module.params.get("tenant")
+ l3out = module.params.get("l3out")
+ l3out_logical_node_profile = module.params.get("l3out_logical_node_profile")
+ l3out_logical_interface_profile = module.params.get("l3out_logical_interface_profile")
+ name = module.params.get("name")
+ name_alias = module.params.get("name_alias")
+ description = module.params.get("description")
+ authentication_type = module.params.get("authentication_type")
+ key = module.params.get("key")
+ key_id = module.params.get("key_id")
+ bfd_interface_policy = module.params.get("bfd_interface_policy")
+ state = module.params.get("state")
+
+ 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="l3extOut",
+ aci_rn="out-{0}".format(l3out),
+ module_object=l3out,
+ target_filter={"name": l3out},
+ ),
+ subclass_2=dict(
+ aci_class="l3extLNodeP",
+ aci_rn="lnodep-{0}".format(l3out_logical_node_profile),
+ module_object=l3out_logical_node_profile,
+ target_filter={"name": l3out_logical_node_profile},
+ ),
+ subclass_3=dict(
+ aci_class="l3extLIfP",
+ aci_rn="lifp-{0}".format(l3out_logical_interface_profile),
+ module_object=l3out_logical_interface_profile,
+ target_filter={"name": l3out_logical_interface_profile},
+ ),
+ subclass_4=dict(
+ aci_class="bfdIfP",
+ aci_rn="bfdIfP",
+ module_object="bfdIfP",
+ target_filter={"name": name},
+ ),
+ child_classes=["bfdRsIfPol"],
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ child_configs = []
+ class_config = dict(
+ name=name,
+ nameAlias=name_alias,
+ descr=description,
+ key=key,
+ type=authentication_type,
+ )
+
+ if key_id and key_id not in range(1, 255):
+ module.fail_json(msg='The "key_id" must be a value between 1 and 255')
+ else:
+ class_config["keyId"] = key_id
+
+ if bfd_interface_policy is not None:
+ child_configs.append(dict(bfdRsIfPol=dict(attributes=dict(tnBfdIfPolName=bfd_interface_policy))))
+
+ aci.payload(
+ aci_class="bfdIfP",
+ class_config=class_config,
+ child_configs=child_configs,
+ )
+
+ aci.get_diff(aci_class="bfdIfP")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_bfd_multihop_interface_profile.py b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_bfd_multihop_interface_profile.py
new file mode 100644
index 000000000..f7dd66c3e
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_bfd_multihop_interface_profile.py
@@ -0,0 +1,366 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Anvitha Jain (@anvjain) <anvjain@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_l3out_bfd_multihop_interface_profile
+short_description: Manage BFD Multihop Interface profiles (bfd:MhIfP)
+description:
+- Manage BFD Multihop Interface profile configuration on Cisco ACI fabrics
+- Only available in APIC version 5.2 or later and for non-cloud APICs
+options:
+ tenant:
+ description:
+ - Name of an existing tenant
+ type: str
+ aliases: [ tenant_name ]
+ l3out:
+ description:
+ - Name of an existing L3Out
+ type: str
+ aliases: [ l3out_name ]
+ l3out_logical_node_profile:
+ description:
+ - Name of an existing L3Out Logical Node profile
+ type: str
+ aliases: [ logical_node_profile, logical_node_profile_name ]
+ l3out_logical_interface_profile:
+ description:
+ - Name of an existing L3Out Logical Interface profile
+ type: str
+ aliases: [ logical_interface_profile, logical_interface_profile_name ]
+ name:
+ description:
+ - Name of the BFD Multihop Interface Profile object
+ type: str
+ aliases: [ bfd_multihop_interface_profile ]
+ name_alias:
+ description:
+ - Name Alias of the BFD Multihop Interface Profile object
+ type: str
+ description:
+ description:
+ - Description of the BFD Multihop Interface Profile object
+ type: str
+ aliases: [ descr ]
+ authentication_type:
+ description:
+ - Authentication Type of the BFD Multihop Interface Profile object
+ - APIC sets the default value to none.
+ type: str
+ choices: [ none, sha1 ]
+ key:
+ description:
+ - Authentication Key of the BFD Multihop Interface Profile object
+ type: str
+ key_id:
+ description:
+ - Authentication Key ID of the BFD Multihop Interface Profile object
+ - APIC sets the default value to 3
+ - Allowed range is 1-255
+ type: int
+ bfd_multihop_interface_policy:
+ description:
+ - The name of the BFD Multihop Interface policy
+ type: str
+ aliases: [ multihop_interface_policy, multihop_interface_policy_name ]
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+
+notes:
+- The C(tenant), c(l3out), C(l3out_logical_node_profile) and C(l3out_logical_interface_profile) must exist before using this module in your playbook
+ The M(cisco.aci.aci_tenant) modules can be used for this
+seealso:
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(bfd:MhIfP)
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+- module: cisco.aci.aci_tenant
+- module: cisco.aci.aci_l3out
+- module: cisco.aci.aci_l3out_logical_node_profile
+- module: cisco.aci.aci_l3out_logical_interface_profile
+- module: cisco.aci.aci_interface_policy_bfd_multihop
+author:
+- Anvitha Jain (@anvjain)
+"""
+
+EXAMPLES = r"""
+- name: Add a new L3Out BFD Multihop Interface Profile
+ cisco.aci.aci_l3out_bfd_multihop_interface_profile:
+ username: admin
+ password: SomeSecretPassword
+ tenant: ansible_tenant
+ l3out: ansible_l3out
+ l3out_logical_node_profile: ansible_node_profile
+ l3out_logical_interface_profile: ansible_interface_profile
+ state: present
+ delegate_to: localhost
+
+- name: Query a new L3Out BFD Multihop Interface Profile
+ cisco.aci.aci_l3out_bfd_multihop_interface_profile:
+ username: admin
+ password: SomeSecretPassword
+ tenant: ansible_tenant
+ l3out: ansible_l3out
+ l3out_logical_node_profile: ansible_node_profile
+ l3out_logical_interface_profile: ansible_interface_profile
+ state: query
+ delegate_to: localhost
+
+- name: Query all L3Out BFD Multihop Interface Profile
+ cisco.aci.aci_l3out_bfd_multihop_interface_profile:
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+
+- name: Delete L3Out BFD Multihop Interface Profile
+ cisco.aci.aci_l3out_bfd_multihop_interface_profile:
+ username: admin
+ password: SomeSecretPassword
+ tenant: ansible_tenant
+ l3out: ansible_l3out
+ l3out_logical_node_profile: ansible_node_profile
+ l3out_logical_interface_profile: ansible_interface_profile
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+ 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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class "/></imdata>'
+ 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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+ 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
+
+
+def main():
+ argument_spec = aci_argument_spec()
+ argument_spec.update(aci_annotation_spec())
+ argument_spec.update(
+ tenant=dict(type="str", aliases=["tenant_name"]),
+ l3out=dict(type="str", aliases=["l3out_name"]),
+ l3out_logical_node_profile=dict(type="str", aliases=["logical_node_profile_name", "logical_node_profile"]),
+ l3out_logical_interface_profile=dict(type="str", aliases=["logical_interface_profile_name", "logical_interface_profile"]),
+ name=dict(type="str", aliases=["bfd_multihop_interface_profile"]),
+ name_alias=dict(type="str"),
+ description=dict(type="str", aliases=["descr"]),
+ authentication_type=dict(type="str", choices=["none", "sha1"]),
+ key=dict(type="str", no_log=True),
+ key_id=dict(type="int"),
+ bfd_multihop_interface_policy=dict(type="str", aliases=["multihop_interface_policy", "multihop_interface_policy_name"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["tenant", "l3out", "l3out_logical_node_profile", "l3out_logical_interface_profile"]],
+ ["state", "present", ["tenant", "l3out", "l3out_logical_node_profile", "l3out_logical_interface_profile", "bfd_multihop_interface_policy"]],
+ ],
+ )
+
+ tenant = module.params.get("tenant")
+ l3out = module.params.get("l3out")
+ l3out_logical_node_profile = module.params.get("l3out_logical_node_profile")
+ l3out_logical_interface_profile = module.params.get("l3out_logical_interface_profile")
+ name = module.params.get("name")
+ name_alias = module.params.get("name_alias")
+ description = module.params.get("description")
+ authentication_type = module.params.get("authentication_type")
+ key = module.params.get("key")
+ key_id = module.params.get("key_id")
+ bfd_multihop_interface_policy = module.params.get("bfd_multihop_interface_policy")
+ state = module.params.get("state")
+
+ 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="l3extOut",
+ aci_rn="out-{0}".format(l3out),
+ module_object=l3out,
+ target_filter={"name": l3out},
+ ),
+ subclass_2=dict(
+ aci_class="l3extLNodeP",
+ aci_rn="lnodep-{0}".format(l3out_logical_node_profile),
+ module_object=l3out_logical_node_profile,
+ target_filter={"name": l3out_logical_node_profile},
+ ),
+ subclass_3=dict(
+ aci_class="l3extLIfP",
+ aci_rn="lifp-{0}".format(l3out_logical_interface_profile),
+ module_object=l3out_logical_interface_profile,
+ target_filter={"name": l3out_logical_interface_profile},
+ ),
+ subclass_4=dict(
+ aci_class="bfdMhIfP",
+ aci_rn="bfdMhIfP",
+ module_object="bfdMhIfP",
+ target_filter={"name": name},
+ ),
+ child_classes=["bfdRsMhIfPol"],
+ )
+
+ aci.get_existing()
+ aci.stdout = str(aci.get_existing())
+ if state == "present":
+ child_configs = []
+ class_config = dict(
+ name=name,
+ nameAlias=name_alias,
+ descr=description,
+ type=authentication_type,
+ key=key,
+ )
+
+ if key_id and key_id not in range(1, 255):
+ module.fail_json(msg='The "key_id" must be a value between 1 and 255')
+ else:
+ class_config["keyId"] = key_id
+
+ if bfd_multihop_interface_policy is not None:
+ child_configs.append(dict(bfdRsMhIfPol=dict(attributes=dict(tnBfdMhIfPolName=bfd_multihop_interface_policy))))
+
+ aci.payload(
+ aci_class="bfdMhIfP",
+ class_config=class_config,
+ child_configs=child_configs,
+ )
+
+ aci.get_diff(aci_class="bfdMhIfP")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_bgp_peer.py b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_bgp_peer.py
index 4719c42ca..79776fdb6 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_bgp_peer.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_bgp_peer.py
@@ -16,7 +16,7 @@ ANSIBLE_METADATA = {
DOCUMENTATION = r"""
---
module: aci_l3out_bgp_peer
-short_description: Manage Layer 3 Outside (L3Out) BGP Peers (bgp:PeerP)
+short_description: Manage Layer 3 Outside (L3Out) BGP Peers (bgp:PeerP and bgp:InfraPeerP)
description:
- Manage L3Out BGP Peers on Cisco ACI fabrics.
options:
@@ -68,7 +68,7 @@ options:
- BGP Controls
type: list
elements: str
- choices: [ send-com, send-ext-com, allow-self-as, as-override, dis-peer-as-check, nh-self ]
+ choices: [ send-com, send-ext-com, allow-self-as, as-override, dis-peer-as-check, nh-self, send-domain-path ]
peer_controls:
description:
- Peer Controls
@@ -143,6 +143,36 @@ options:
- The APIC defaults to 0 when unset during creation.
type: int
aliases: [ local_as_num ]
+ bgp_password:
+ description:
+ - Password for the BGP Peer.
+ type: str
+ description:
+ description:
+ - Description for the BGP Peer.
+ type: str
+ aliases: [ descr ]
+ transport_data_plane:
+ description:
+ - Transport Data Plane type.
+ type: str
+ choices: [ mpls, sr_mpls ]
+ bgp_peer_prefix_policy:
+ description:
+ - BGP Peer Prefix Policy.
+ - BGP Peer Prefix Policy is only allowed to be configured when I(bgp_infra_peer=true).
+ type: str
+ aliases: [ bgp_peer_prefix_policy_name ]
+ peer_type:
+ description:
+ - BGP Peer type.
+ type: str
+ choices: [ sr_mpls ]
+ bgp_infra_peer:
+ description:
+ - BGP Infra peer (bgp:InfraPeerP).
+ type: bool
+ aliases: [ infra ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
@@ -158,10 +188,11 @@ seealso:
- module: aci_l3out
- module: aci_l3out_logical_node_profile
- name: APIC Management Information Model reference
- description: More information about the internal APIC classes B(bgp:peerP)
+ description: More information about the internal APIC classes B(bgp:peerP) and B(bgp:InfraPeerP)
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Tim Cragg (@timcragg)
+- Akini Ross (@akinross)
"""
EXAMPLES = r"""
@@ -215,6 +246,28 @@ EXAMPLES = r"""
state: present
delegate_to: localhost
+- name: Create Infra BGP Peer with password
+ aci_l3out_bgp_peer: &infra_bgp_peer
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: infra
+ l3out: ansible_infra_l3out
+ node_profile: ansible_infra_l3out_node_profile
+ ttl: 2
+ bgp_infra_peer: true
+ bgp_password: ansible_test_password
+ peer_ip: 192.168.50.2
+ remote_asn: 65450
+ local_as_number: 65460
+ peer_type: sr_mpls
+ bgp_controls:
+ - send-domain-path
+ transport_data_plane: sr_mpls
+ bgp_peer_prefix_policy: ansible_peer_prefix_profile
+ state: present
+ delegate_to: localhost
+
- name: Shutdown a BGP peer
cisco.aci.aci_l3out_bgp_peer:
host: apic
@@ -266,6 +319,7 @@ EXAMPLES = r"""
direction: "export"
l3out: "anstest_l3out"
state: present
+ delegate_to: localhost
- name: Query a BGP peer
cisco.aci.aci_l3out_bgp_peer:
@@ -293,6 +347,15 @@ EXAMPLES = r"""
delegate_to: localhost
register: query_all
+- name: Query all BGP infra peer
+ cisco.aci.aci_l3out_bgp_peer:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ bgp_infra_peer: true
+ state: query
+ delegate_to: localhost
+ register: query_all
"""
RETURN = r"""
@@ -416,6 +479,7 @@ def main():
argument_spec.update(
tenant=dict(type="str", aliases=["tenant_name"]),
l3out=dict(type="str", aliases=["l3out_name"]),
+ description=dict(type="str", aliases=["descr"]),
node_profile=dict(type="str", aliases=["node_profile_name", "logical_node"]),
interface_profile=dict(type="str", aliases=["interface_profile_name", "logical_interface"]),
state=dict(type="str", default="present", choices=["absent", "present", "query"]),
@@ -434,6 +498,7 @@ def main():
"as-override",
"dis-peer-as-check",
"nh-self",
+ "send-domain-path",
],
),
peer_controls=dict(type="list", elements="str", choices=["bfd", "dis-conn-check"]),
@@ -454,6 +519,11 @@ def main():
),
local_as_number_config=dict(type="str", choices=["dual-as", "no-prepend", "none", "replace-as"], aliases=["local_as_num_config"]),
local_as_number=dict(type="int", aliases=["local_as_num"]),
+ bgp_password=dict(type="str", no_log=True),
+ transport_data_plane=dict(type="str", choices=["mpls", "sr_mpls"]),
+ bgp_peer_prefix_policy=dict(type="str", aliases=["bgp_peer_prefix_policy_name"]),
+ peer_type=dict(type="str", choices=["sr_mpls"]),
+ bgp_infra_peer=dict(type="bool", aliases=["infra"]),
)
module = AnsibleModule(
@@ -468,6 +538,7 @@ def main():
tenant = module.params.get("tenant")
l3out = module.params.get("l3out")
+ description = module.params.get("description")
node_profile = module.params.get("node_profile")
interface_profile = module.params.get("interface_profile")
state = module.params.get("state")
@@ -487,6 +558,11 @@ def main():
route_control_profiles = module.params.get("route_control_profiles")
local_as_number_config = module.params.get("local_as_number_config")
local_as_number = module.params.get("local_as_number")
+ bgp_password = module.params.get("bgp_password")
+ transport_data_plane = module.params.get("transport_data_plane")
+ peer_type = module.params.get("peer_type")
+ bgp_infra_peer = module.params.get("bgp_infra_peer")
+ bgp_peer_prefix_policy = module.params.get("bgp_peer_prefix_policy")
aci = ACIModule(module)
if node_id:
@@ -499,24 +575,23 @@ def main():
child_configs = []
child_classes = ["bgpRsPeerPfxPol", "bgpAsP", "bgpLocalAsnP"]
+ aci_class = "bgpInfraPeerP" if bgp_infra_peer else "bgpPeerP"
- if remote_asn:
- child_configs.append(
- dict(
- bgpAsP=dict(
- attributes=dict(asn=remote_asn),
- ),
- )
- )
+ if remote_asn is not None:
+ bgp_as_p = dict(bgpAsP=dict(attributes=dict(asn=remote_asn)))
+ if remote_asn == 0:
+ bgp_as_p["bgpAsP"]["attributes"]["status"] = "deleted"
+ child_configs.append(bgp_as_p)
- if local_as_number_config or local_as_number:
- child_configs.append(
- dict(
- bgpLocalAsnP=dict(
- attributes=dict(asnPropagate=local_as_number_config, localAsn=local_as_number),
- ),
- )
- )
+ if local_as_number_config is not None or local_as_number is not None:
+ bgp_local_asn_p = dict(bgpLocalAsnP=dict(attributes=dict(asnPropagate=local_as_number_config, localAsn=local_as_number)))
+ if local_as_number == 0:
+ bgp_local_asn_p["bgpLocalAsnP"]["attributes"]["status"] = "deleted"
+ child_configs.append(bgp_local_asn_p)
+
+ # BGP Peer Prefix Policy is ony configurable on Infra BGP Peer Profile
+ if bgp_peer_prefix_policy is not None:
+ child_configs.append(dict(bgpRsPeerPfxPol=dict(attributes=dict(tnBgpPeerPfxPolName=bgp_peer_prefix_policy))))
if route_control_profiles:
child_classes.append("bgpRsPeerToProfile")
@@ -541,8 +616,8 @@ def main():
)
bgp_peer_profile_dict = dict(
- aci_class="bgpPeerP",
- aci_rn="peerP-[{0}]".format(peer_ip),
+ aci_class=aci_class,
+ aci_rn="infraPeerP-[{0}]".format(peer_ip) if bgp_infra_peer else "peerP-{0}".format(peer_ip),
module_object=peer_ip,
target_filter={"addr": peer_ip},
)
@@ -594,32 +669,46 @@ def main():
aci.get_existing()
if state == "present":
- ctrl, peerCtrl, addrTCtrl, privateASctrl = None, None, None, None
+ ctrl, ctrl_ext, peerCtrl, addrTCtrl, privateASctrl = None, None, None, None, None
if bgp_controls:
+ if transport_data_plane == "mpls":
+ bgp_controls.append("segment-routing-disable")
+
+ if "send-domain-path" in bgp_controls:
+ ctrl_ext = "send-domain-path"
+ bgp_controls.remove("send-domain-path")
+
ctrl = ",".join(bgp_controls)
+
if peer_controls:
peerCtrl = ",".join(peer_controls)
if address_type_controls:
addrTCtrl = ",".join(address_type_controls)
if private_asn_controls:
privateASctrl = ",".join(private_asn_controls)
- aci.payload(
- aci_class="bgpPeerP",
- class_config=dict(
- addr=peer_ip,
- ctrl=ctrl,
- peerCtrl=peerCtrl,
- addrTCtrl=addrTCtrl,
- privateASctrl=privateASctrl,
- ttl=ttl,
- weight=weight,
- adminSt=admin_state,
- allowedSelfAsCnt=allow_self_as_count,
- ),
- child_configs=child_configs,
+
+ class_config = dict(
+ descr=description,
+ addr=peer_ip,
+ ctrl=ctrl,
+ ctrlExt=ctrl_ext,
+ peerCtrl=peerCtrl,
+ addrTCtrl=addrTCtrl,
+ privateASctrl=privateASctrl,
+ ttl=ttl,
+ weight=weight,
+ adminSt=admin_state,
+ allowedSelfAsCnt=allow_self_as_count,
+ peerT=peer_type.replace("_", "-") if peer_type else None,
)
- aci.get_diff(aci_class="bgpPeerP")
+ # Only add bgp_password if it is set to handle changed status properly because password is not part of existing config
+ if bgp_password:
+ class_config["password"] = bgp_password
+
+ aci.payload(aci_class=aci_class, class_config=class_config, child_configs=child_configs)
+
+ aci.get_diff(aci_class=aci_class)
aci.post_config()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_dhcp_relay_label.py b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_dhcp_relay_label.py
new file mode 100644
index 000000000..3b9885c23
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_dhcp_relay_label.py
@@ -0,0 +1,354 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@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_l3out_dhcp_relay_label
+short_description: Manage Layer 3 Outside (L3Out) DHCP Relay Label (dhcp:Lbl)
+description:
+- Manage DHCP Relay Labels for L3Out Logical Interface Profiles on Cisco ACI fabrics.
+- A DHCP Relay Label contains the name of an existing DHCP Relay Policy for the label,
+ the scope, and a DHCP Option Policy.
+options:
+ tenant:
+ description:
+ - The name of an existing tenant.
+ type: str
+ aliases: [ tenant_name ]
+ l3out:
+ description:
+ - The name of an existing L3Out.
+ type: str
+ aliases: [ l3out_name ]
+ node_profile:
+ description:
+ - The name of an existing node profile.
+ type: str
+ aliases: [ node_profile_name, logical_node ]
+ interface_profile:
+ description:
+ - The name of an existing interface profile.
+ type: str
+ aliases: [ interface_profile_name, logical_interface ]
+ dhcp_relay_label:
+ description:
+ - The name/label of an existing DHCP Relay Policy.
+ type: str
+ aliases: [ name, relay_policy ]
+ scope:
+ description:
+ - The scope is the owner of the relay server.
+ - The APIC defaults to C(infra) when unset during creation.
+ type: str
+ choices: [ infra, tenant ]
+ aliases: [ owner ]
+ dhcp_option_policy:
+ description:
+ - The name of an existing DHCP Option Policy to be associated with the DCHP Relay Policy.
+ - The DHCP option policy supplies DHCP clients with configuration parameters
+ such as domain, nameserver, and subnet router addresses.
+ - Passing an empty string will delete the current linked DHCP Option Policy.
+ However, this will associate the DHCP Relay Label to the default DHCP Option Policy
+ from the common Tenant.
+ type: str
+ aliases: [ dhcp_option_policy_name ]
+ description:
+ description:
+ - The description of the DHCP Relay Label.
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+notes:
+- The C(tenant), C(l3out), C(node_profile), C(interface_profile) and C(relay_policy) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant), M(cisco.aci.aci_l3out), M(cisco.aci.aci_l3out_logical_node_profile), M(cisco.aci.aci_l3out_logical_interface_profile)
+ and M(cisco.aci.aci_dhcp_relay) can be used for this.
+- If C(dhcp_option_policy) is used, it must exist before using this module in your playbook.
+ The M(cisco.aci.aci_dhcp_option_policy) can be used for this.
+seealso:
+- module: cisco.aci.aci_tenant
+- module: cisco.aci.aci_l3out
+- module: cisco.aci.aci_l3out_logical_node_profile
+- module: cisco.aci.aci_l3out_logical_interface_profile
+- module: cisco.aci.aci_dhcp_relay
+- module: cisco.aci.aci_dhcp_option_policy
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC classes
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Gaspard Micol (@gmicol)
+"""
+
+EXAMPLES = r"""
+- name: Add a new L3Out DHCP Relay Label
+ cisco.aci.aci_l3out_eigrp_interface_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ dhcp_relay_label: my_dhcp_relay_label
+ scope: tenant
+ dhcp_option_policy: my_dhcp_option_policy
+ state: present
+ delegate_to: localhost
+
+- name: Delete an L3Out DHCP Relay Label
+ cisco.aci.aci_l3out_eigrp_interface_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ dhcp_relay_label: my_dhcp_relay_label
+ state: absent
+ delegate_to: localhost
+
+- name: Query an L3Out DHCP Relay Label
+ cisco.aci.aci_l3out_eigrp_interface_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ dhcp_relay_label: my_dhcp_relay_label
+ state: query
+ delegate_to: localhost
+ register: query_result
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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"]),
+ l3out=dict(type="str", aliases=["l3out_name"]),
+ node_profile=dict(type="str", aliases=["node_profile_name", "logical_node"]),
+ interface_profile=dict(type="str", aliases=["interface_profile_name", "logical_interface"]),
+ dhcp_relay_label=dict(type="str", aliases=["name", "relay_policy"]),
+ scope=dict(type="str", choices=["infra", "tenant"], aliases=["owner"]),
+ dhcp_option_policy=dict(type="str", aliases=["dhcp_option_policy_name"]),
+ description=dict(type="str", aliases=["descr"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["tenant", "l3out", "node_profile", "interface_profile", "dhcp_relay_label"]],
+ ["state", "present", ["tenant", "l3out", "node_profile", "interface_profile", "dhcp_relay_label"]],
+ ],
+ )
+
+ tenant = module.params.get("tenant")
+ l3out = module.params.get("l3out")
+ node_profile = module.params.get("node_profile")
+ interface_profile = module.params.get("interface_profile")
+ dhcp_relay_label = module.params.get("dhcp_relay_label")
+ scope = module.params.get("scope")
+ dhcp_option_policy = module.params.get("dhcp_option_policy")
+ description = module.params.get("description")
+ state = module.params.get("state")
+
+ aci = ACIModule(module)
+
+ child_classes = ["dhcpRsDhcpOptionPol"]
+
+ 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="l3extOut",
+ aci_rn="out-{0}".format(l3out),
+ module_object=l3out,
+ target_filter={"name": l3out},
+ ),
+ subclass_2=dict(
+ aci_class="l3extLNodeP",
+ aci_rn="lnodep-{0}".format(node_profile),
+ module_object=node_profile,
+ target_filter={"name": node_profile},
+ ),
+ subclass_3=dict(
+ aci_class="l3extLIfP",
+ aci_rn="lifp-[{0}]".format(interface_profile),
+ module_object=interface_profile,
+ target_filter={"name": interface_profile},
+ ),
+ subclass_4=dict(
+ aci_class="dhcpLbl",
+ aci_rn="dhcplbl-[{0}]".format(dhcp_relay_label),
+ module_object=dhcp_relay_label,
+ target_filter={"name": dhcp_relay_label},
+ ),
+ child_classes=child_classes,
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ child_configs = [dict(dhcpRsDhcpOptionPol=dict(attributes=dict(tnDhcpOptionPolName=dhcp_option_policy)))]
+
+ aci.payload(
+ aci_class="dhcpLbl",
+ class_config=dict(
+ descr=description,
+ name=dhcp_relay_label,
+ owner=scope,
+ ),
+ child_configs=child_configs,
+ )
+
+ aci.get_diff(aci_class="dhcpLbl")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_eigrp_interface_profile.py b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_eigrp_interface_profile.py
new file mode 100644
index 000000000..d1359e500
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_eigrp_interface_profile.py
@@ -0,0 +1,392 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@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_l3out_eigrp_interface_profile
+short_description: Manage Layer 3 Outside (L3Out) EIGRP interface profile (eigrp:IfP)
+description:
+- Manage L3Out logical interface profile EIGRP policies on Cisco ACI fabrics.
+options:
+ tenant:
+ description:
+ - The name of an existing tenant.
+ type: str
+ aliases: [ tenant_name ]
+ l3out:
+ description:
+ - The name of an existing L3Out.
+ type: str
+ aliases: [ l3out_name ]
+ node_profile:
+ description:
+ - The name of the node profile.
+ type: str
+ aliases: [ node_profile_name, logical_node ]
+ interface_profile:
+ description:
+ - The name of an existing interface profile.
+ type: str
+ aliases: [ interface_profile_name, logical_interface ]
+ eigrp_policy:
+ description:
+ - The name of an existing EIGRP interface policy.
+ type: str
+ aliases: [ name, eigrp_policy_name ]
+ eigrp_keychain_policy:
+ description:
+ - The name of an existing EIGRP keychain policy.
+ - Pass an empty string to disable Authentification.
+ type: str
+ aliases: [ keychain_policy, keychain_policy_name ]
+ description:
+ description:
+ - The description of the EIGRP interface profile.
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+notes:
+- The C(tenant), C(l3out), C(node_profile), C(interface_profile) and C(eigrp_policy) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant), M(cisco.aci.aci_l3out), M(cisco.aci.aci_l3out_logical_node_profile), M(cisco.aci.aci_l3out_logical_interface_profile)
+ and M(cisco.aci.aci_interface_policy_eigrp) can be used for this.
+- if C(eigrp_keychain_policy) is used, it must exist before using this module in your playbook.
+ The M(cisco.aci.aci_keychain_policy) can be used for this.
+seealso:
+- module: cisco.aci.aci_tenant
+- module: cisco.aci.aci_l3out
+- module: cisco.aci.aci_l3out_logical_node_profile
+- module: cisco.aci.aci_l3out_logical_interface_profile
+- module: cisco.aci.aci_interface_policy_eigrp
+- module: cisco.aci.aci_keychain_policy
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC classes
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Gaspard Micol (@gmicol)
+"""
+
+EXAMPLES = r"""
+- name: Add a new interface profile EIGRP policy
+ cisco.aci.aci_l3out_eigrp_interface_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ eigrp_policy: my_eigrp_interface_policy
+ state: present
+ delegate_to: localhost
+
+- name: Add a new interface profile EIGRP policy with authentication
+ cisco.aci.aci_l3out_eigrp_interface_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ eigrp_policy: my_eigrp_interface_policy
+ eigrp_keychain_policy: my_keychain_policy
+ state: present
+ delegate_to: localhost
+
+- name: Disable authentification from an interface profile EIGRP policy
+ cisco.aci.aci_l3out_eigrp_interface_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ eigrp_policy: my_eigrp_interface_policy
+ eigrp_keychain_policy: ""
+ state: present
+ delegate_to: localhost
+
+- name: Delete an interface profile EIGRP policy
+ cisco.aci.aci_l3out_eigrp_interface_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ eigrp_policy: my_eigrp_interface_policy
+ state: absent
+ delegate_to: localhost
+
+- name: Query an interface profile EIGRP policy
+ cisco.aci.aci_l3out_eigrp_interface_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ eigrp_policy: my_eigrp_interface_policy
+ state: query
+ delegate_to: localhost
+ register: query_result
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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"]),
+ l3out=dict(type="str", aliases=["l3out_name"]),
+ node_profile=dict(type="str", aliases=["node_profile_name", "logical_node"]),
+ interface_profile=dict(type="str", aliases=["interface_profile_name", "logical_interface"]),
+ eigrp_policy=dict(type="str", aliases=["name", "eigrp_policy_name"]),
+ eigrp_keychain_policy=dict(type="str", aliases=["keychain_policy", "keychain_policy_name"], no_log=False),
+ description=dict(type="str", aliases=["descr"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["tenant", "l3out", "node_profile", "interface_profile"]],
+ ["state", "present", ["tenant", "l3out", "node_profile", "interface_profile", "eigrp_policy"]],
+ ],
+ )
+
+ tenant = module.params.get("tenant")
+ l3out = module.params.get("l3out")
+ node_profile = module.params.get("node_profile")
+ interface_profile = module.params.get("interface_profile")
+ eigrp_policy = module.params.get("eigrp_policy")
+ eigrp_keychain_policy = module.params.get("eigrp_keychain_policy")
+ description = module.params.get("description")
+ state = module.params.get("state")
+
+ aci = ACIModule(module)
+
+ child_classes = ["eigrpRsIfPol", "eigrpAuthIfP"]
+
+ 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="l3extOut",
+ aci_rn="out-{0}".format(l3out),
+ module_object=l3out,
+ target_filter={"name": l3out},
+ ),
+ subclass_2=dict(
+ aci_class="l3extLNodeP",
+ aci_rn="lnodep-{0}".format(node_profile),
+ module_object=node_profile,
+ target_filter={"name": node_profile},
+ ),
+ subclass_3=dict(
+ aci_class="l3extLIfP",
+ aci_rn="lifp-[{0}]".format(interface_profile),
+ module_object=interface_profile,
+ target_filter={"name": interface_profile},
+ ),
+ subclass_4=dict(
+ aci_class="eigrpIfP",
+ aci_rn="eigrpIfP",
+ module_object=interface_profile,
+ target_filter={"name": interface_profile},
+ ),
+ child_classes=child_classes,
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ child_configs = [dict(eigrpRsIfPol=dict(attributes=dict(tnEigrpIfPolName=eigrp_policy)))]
+
+ if eigrp_keychain_policy is not None:
+ if eigrp_keychain_policy == "" and isinstance(aci.existing, list) and len(aci.existing) > 0:
+ for child in aci.existing[0].get("eigrpIfP", {}).get("children", {}):
+ if child.get("eigrpAuthIfP"):
+ child_configs.append(
+ dict(
+ eigrpAuthIfP=dict(
+ attributes=dict(status="deleted"),
+ ),
+ )
+ )
+ elif eigrp_keychain_policy != "":
+ child_configs.append(
+ dict(
+ eigrpAuthIfP=dict(
+ attributes=dict(),
+ children=[
+ dict(
+ eigrpRsKeyChainPol=dict(
+ attributes=dict(
+ tnFvKeyChainPolName=eigrp_keychain_policy,
+ ),
+ )
+ )
+ ],
+ )
+ )
+ )
+
+ aci.payload(
+ aci_class="eigrpIfP",
+ class_config=dict(
+ descr=description,
+ ),
+ child_configs=child_configs,
+ )
+
+ aci.get_diff(aci_class="eigrpIfP")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_extepg.py b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_extepg.py
index acaa7ea9e..3180e6752 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_extepg.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_extepg.py
@@ -14,7 +14,7 @@ DOCUMENTATION = r"""
module: aci_l3out_extepg
short_description: Manage External Network Instance Profile (ExtEpg) objects (l3extInstP:instP)
description:
-- Manage External Network Instance Profile (ExtEpg) objects (l3extInstP:instP)
+- Manage External Network Instance Profile (ExtEpg) objects.
options:
tenant:
description:
@@ -104,7 +104,7 @@ seealso:
- module: cisco.aci.aci_domain
- module: cisco.aci.aci_vrf
- name: APIC Management Information Model reference
- description: More information about the internal APIC class B(l3ext:Out).
+ description: More information about the internal APIC class B(l3extInstP:instP).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Rostyslav Davydenko (@rost-d)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_extepg_to_contract.py b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_extepg_to_contract.py
index ba5df29c5..eb9f6da17 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_extepg_to_contract.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_extepg_to_contract.py
@@ -3,6 +3,7 @@
# Copyright: (c) 2020, Sudhakar Shet Kudtarkar (@kudtarkar1)
# Copyright: (c) 2020, Shreyas Srish <ssrish@cisco.com>
+# Copyright: (c) 2023, Akini Ross (@akinross) <akinross@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
@@ -14,7 +15,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_l3out_extepg_to_contract
-short_description: Bind Contracts to External End Point Groups (EPGs)
+short_description: Bind Contracts to External End Point Groups (EPGs) (fv:RsCons, fv:RsProv, fv:RsProtBy, fv:RsConsIf, and fv:RsIntraEpg)
description:
- Bind Contracts to External End Point Groups (EPGs) on ACI fabrics.
options:
@@ -26,32 +27,43 @@ options:
description:
- Name of the l3out.
type: str
- aliases: ['l3out_name']
+ aliases: [ l3out_name ]
extepg:
description:
- Name of the external end point group.
type: str
- aliases: ['extepg_name', 'external_epg']
+ aliases: [ extepg_name, external_epg]
contract:
description:
- - Name of the contract.
+ - The name of the contract or contract interface.
type: str
+ aliases: [ contract_name, contract_interface ]
contract_type:
description:
- - The type of contract.
+ - Determines the type of the Contract.
type: str
required: true
- choices: ['consumer', 'provider']
+ choices: [ consumer, provider, taboo, interface, intra_epg ]
priority:
description:
- - This has four levels of priority.
+ - QoS class.
+ - The APIC defaults to C(unspecified) when unset during creation.
type: str
- choices: ['level1', 'level2', 'level3', 'unspecified']
+ choices: [ level1, level2, level3, level4, level5, level6, unspecified ]
provider_match:
description:
- - This is configurable for provided contracts.
+ - The matching algorithm for Provided Contracts.
+ - The APIC defaults to C(at_least_one) when unset during creation.
+ type: str
+ choices: [ all, at_least_one, at_most_one, none ]
+ contract_label:
+ description:
+ - Contract label to match.
+ type: str
+ subject_label:
+ description:
+ - Subject label to match.
type: str
- choices: ['all', 'at_least_one', 'at_most_one', 'none']
state:
description:
- Use C(present) or C(absent) for adding or removing.
@@ -64,15 +76,16 @@ extends_documentation_fragment:
- cisco.aci.annotation
notes:
-- The C(tenant), C(l3out) and C(extepg) must exist before using this module in your playbook.
- The M(cisco.aci.aci_tenant), M(cisco.aci.aci_l3out) and M(cisco.aci.aci_l3out_extepg) modules can be used for this.
+- The C(tenant), C(l3out), C(extepg), and C(Contract) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant), M(cisco.aci.aci_l3out), M(cisco.aci.aci_l3out_extepg), and M(cisco.aci.aci_contract) modules can be used for this.
seealso:
- name: APIC Management Information Model reference
- description: More information about the internal APIC class B(fvtenant), B(l3extInstP) and B(l3extOut).
+ description: More information about the internal APIC class B(fv:RsCons), B(fv:RsProv), B(fv:RsProtBy, B(fv:RsConsIf, and B(fv:RsIntraEpg).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Sudhakar Shet Kudtarkar (@kudtarkar1)
- Shreyas Srish (@shrsr)
+- Akini Ross (@akinross)
"""
EXAMPLES = r"""
@@ -234,38 +247,23 @@ RETURN = r"""
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_CLASS_MAPPING = dict(
- consumer={
- "class": "fvRsCons",
- "rn": "rscons-",
- },
- provider={
- "class": "fvRsProv",
- "rn": "rsprov-",
- },
-)
-
-PROVIDER_MATCH_MAPPING = dict(
- all="All",
- at_least_one="AtleastOne",
- at_most_one="tmostOne",
- none="None",
-)
+from ansible_collections.cisco.aci.plugins.module_utils.constants import ACI_CLASS_MAPPING, CONTRACT_LABEL_MAPPING, PROVIDER_MATCH_MAPPING, SUBJ_LABEL_MAPPING
def main():
argument_spec = aci_argument_spec()
argument_spec.update(aci_annotation_spec())
argument_spec.update(
- contract_type=dict(type="str", required=True, choices=["consumer", "provider"]),
+ contract_type=dict(type="str", required=True, choices=["consumer", "provider", "taboo", "interface", "intra_epg"]),
l3out=dict(type="str", aliases=["l3out_name"]),
- contract=dict(type="str"),
- priority=dict(type="str", choices=["level1", "level2", "level3", "unspecified"]),
+ contract=dict(type="str", aliases=["contract_name", "contract_interface"]), # Not required for querying all objects
+ priority=dict(type="str", choices=["level1", "level2", "level3", "level4", "level5", "level6", "unspecified"]),
provider_match=dict(type="str", choices=["all", "at_least_one", "at_most_one", "none"]),
state=dict(type="str", default="present", choices=["absent", "present", "query"]),
tenant=dict(type="str"),
extepg=dict(type="str", aliases=["extepg_name", "external_epg"]),
+ contract_label=dict(type="str"),
+ subject_label=dict(type="str"),
)
module = AnsibleModule(
argument_spec=argument_spec,
@@ -286,13 +284,25 @@ def main():
provider_match = PROVIDER_MATCH_MAPPING.get(provider_match)
state = module.params.get("state")
tenant = module.params.get("tenant")
+ contract_label = module.params.get("contract_label")
+ subject_label = module.params.get("subject_label")
- aci_class = ACI_CLASS_MAPPING.get(contract_type)["class"]
- aci_rn = ACI_CLASS_MAPPING.get(contract_type)["rn"]
+ aci_class = ACI_CLASS_MAPPING[contract_type]["class"]
+ aci_rn = ACI_CLASS_MAPPING[contract_type]["rn"]
+ aci_name = ACI_CLASS_MAPPING[contract_type]["name"]
+ child_classes = []
- if contract_type == "consumer" and provider_match is not None:
+ if contract_type != "provider" and provider_match is not None:
module.fail_json(msg="the 'provider_match' is only configurable for Provided Contracts")
+ if contract_type in ["taboo", "interface", "intra_epg"] and (contract_label is not None or subject_label is not None):
+ module.fail_json(msg="the 'contract_label' and 'subject_label' are not configurable for {0} contracts".format(contract_type))
+
+ if contract_type not in ["taboo", "interface", "intra_epg"]:
+ contract_label_class = CONTRACT_LABEL_MAPPING.get(contract_type)
+ subject_label_class = SUBJ_LABEL_MAPPING.get(contract_type)
+ child_classes = [subject_label_class, contract_label_class]
+
aci = ACIModule(module)
aci.construct_url(
root_class=dict(
@@ -317,20 +327,23 @@ def main():
aci_class=aci_class,
aci_rn="{0}{1}".format(aci_rn, contract),
module_object=contract,
- target_filter={"tnVzBrCPName": contract},
+ target_filter={aci_name: contract},
),
+ child_classes=child_classes,
)
aci.get_existing()
if state == "present":
+ child_configs = []
+ if contract_label is not None:
+ child_configs.append({contract_label_class: {"attributes": {"name": contract_label}}})
+ if subject_label is not None:
+ child_configs.append({subject_label_class: {"attributes": {"name": subject_label}}})
aci.payload(
aci_class=aci_class,
- class_config=dict(
- matchT=provider_match,
- prio=priority,
- tnVzBrCPName=contract,
- ),
+ class_config={"matchT": provider_match, "prio": priority, aci_name: contract},
+ child_configs=child_configs,
)
aci.get_diff(aci_class=aci_class)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_extsubnet.py b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_extsubnet.py
index 6ecb3b27c..9d94ee44f 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_extsubnet.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_extsubnet.py
@@ -12,9 +12,9 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_l3out_extsubnet
-short_description: Manage External Subnet objects (l3extSubnet:extsubnet)
+short_description: Manage External Subnet objects (l3ext:Subnet)
description:
-- Manage External Subnet objects (l3extSubnet:extsubnet)
+- Manage External Subnet objects.
options:
tenant:
description:
@@ -99,7 +99,7 @@ seealso:
- module: cisco.aci.aci_domain
- module: cisco.aci.aci_vrf
- name: APIC Management Information Model reference
- description: More information about the internal APIC class B(l3ext:Out).
+ description: More information about the internal APIC class B(l3ext:Subnet).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Rostyslav Davydenko (@rost-d)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_floating_svi.py b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_floating_svi.py
new file mode 100644
index 000000000..b0e3ca7e3
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_floating_svi.py
@@ -0,0 +1,475 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Shreyas Srish <ssrish@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_l3out_floating_svi
+short_description: Manage Layer 3 Outside (L3Out) interfaces (l3ext:VirtualLIfP)
+description:
+- Manage L3Out interfaces on Cisco ACI fabrics.
+options:
+ tenant:
+ description:
+ - Name of an existing tenant.
+ type: str
+ aliases: [ tenant_name ]
+ required: true
+ l3out:
+ description:
+ - Name of an existing L3Out.
+ type: str
+ aliases: [ l3out_name ]
+ required: true
+ node_profile:
+ description:
+ - Name of the node profile.
+ type: str
+ aliases: [ node_profile_name, logical_node ]
+ required: true
+ interface_profile:
+ description:
+ - Name of the interface profile.
+ type: str
+ aliases: [ interface_profile_name, logical_interface ]
+ required: true
+ pod_id:
+ description:
+ - Pod ID to build the interface on.
+ type: str
+ node_id:
+ description:
+ - Node ID to build the interface on for Port-channels and single ports.
+ type: str
+ encap:
+ description:
+ - Encapsulation on the interface (e.g. "vlan-500")
+ type: str
+ encap_scope:
+ description:
+ - Encapsulation scope.
+ choices: [ vrf, local ]
+ type: str
+ address:
+ description:
+ - IP address.
+ type: str
+ aliases: [ addr, ip_address ]
+ mac_address:
+ description:
+ - The MAC address option of the interface.
+ type: str
+ link_local_address:
+ description:
+ - The link local address option of the interface.
+ type: str
+ mtu:
+ description:
+ - Interface MTU.
+ type: str
+ ipv6_dad:
+ description:
+ - IPv6 Duplicate Address Detection (DAD) feature.
+ type: str
+ choices: [ enabled, disabled]
+ mode:
+ description:
+ - The mode option for ext-svi interface.
+ type: str
+ choices: [ regular, native, untagged ]
+ dscp:
+ description:
+ - The target Differentiated Service (DSCP) value.
+ - The APIC defaults to C(unspecified) when unset during creation.
+ type: str
+ choices: [ AF11, AF12, AF13, AF21, AF22, AF23, AF31, AF32, AF33, AF41, AF42, AF43, CS0, CS1, CS2, CS3, CS4, CS5, CS6, CS7, EF, VA, unspecified ]
+ aliases: [ target_dscp ]
+ external_bridge_group_profile:
+ description:
+ - The external bridge group profile.
+ - Pass "" as the value to remove an existing external bridge group profile (See Examples).
+ - This is only supported in APIC v5.0 and above.
+ type: str
+ 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
+ auto_state:
+ description:
+ - SVI auto state.
+ type: str
+ choices: [ enabled, disabled ]
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+
+notes:
+- The C(tenant), C(l3out), C(logical_node_profile) and C(logical_interface_profile) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant), M(cisco.aci.aci_l3out), M(cisco.aci.aci_l3out_logical_node_profile), M(cisco.aci.aci_l3out_logical_interface_profile) \
+ modules can be used for this.
+seealso:
+- module: cisco.aci.aci_tenant
+- module: cisco.aci.aci_l3out
+- module: cisco.aci.aci_l3out_logical_node_profile
+- module: cisco.aci.aci_l3out_logical_interface_profile
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(l3ext:VirtualLIfP)
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Shreyas Srish (@shrsr)
+"""
+
+EXAMPLES = r"""
+- name: Create a Floating SVI
+ cisco.aci.aci_l3out_floating_svi:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ pod_id: 1
+ node_id: 201
+ encap: vlan-1
+ address: 23.45.67.90/24
+ external_bridge_group_profile: bridge1
+ state: present
+ delegate_to: localhost
+
+- name: Remove an external bridge group profile
+ cisco.aci.aci_l3out_floating_svi:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ pod_id: 1
+ node_id: 201
+ encap: vlan-1
+ address: 23.45.67.90/24
+ external_bridge_group_profile: ""
+ state: present
+ delegate_to: localhost
+
+- name: Remove a Floating SVI
+ cisco.aci.aci_l3out_floating_svi:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ pod_id: 1
+ node_id: 201
+ encap: vlan-1
+ state: absent
+ delegate_to: localhost
+
+- name: Query a Floating SVI
+ cisco.aci.aci_l3out_floating_svi:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ pod_id: 1
+ node_id: 201
+ encap: vlan-1
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all the Floating SVIs under an interface profile
+ cisco.aci.aci_l3out_floating_svi:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ state: query
+ delegate_to: localhost
+ register: query_results
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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_contract_dscp_spec
+
+
+def main():
+ argument_spec = aci_argument_spec()
+ argument_spec.update(aci_annotation_spec())
+ argument_spec.update(
+ tenant=dict(type="str", aliases=["tenant_name"], required=True),
+ l3out=dict(type="str", aliases=["l3out_name"], required=True),
+ node_profile=dict(type="str", aliases=["node_profile_name", "logical_node"], required=True),
+ interface_profile=dict(type="str", aliases=["interface_profile_name", "logical_interface"], required=True),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ pod_id=dict(type="str"),
+ node_id=dict(type="str"),
+ address=dict(type="str", aliases=["addr", "ip_address"]),
+ link_local_address=dict(type="str"),
+ mac_address=dict(type="str"),
+ mtu=dict(type="str"),
+ ipv6_dad=dict(type="str", choices=["enabled", "disabled"]),
+ mode=dict(type="str", choices=["regular", "native", "untagged"]),
+ encap=dict(type="str"),
+ encap_scope=dict(type="str", choices=["vrf", "local"]),
+ auto_state=dict(type="str", choices=["enabled", "disabled"]),
+ external_bridge_group_profile=dict(type="str"),
+ dscp=aci_contract_dscp_spec(direction="dscp"),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "present", ["pod_id", "node_id", "encap", "address"]],
+ ["state", "absent", ["pod_id", "node_id", "encap"]],
+ ],
+ )
+
+ tenant = module.params.get("tenant")
+ l3out = module.params.get("l3out")
+ node_profile = module.params.get("node_profile")
+ interface_profile = module.params.get("interface_profile")
+ state = module.params.get("state")
+ pod_id = module.params.get("pod_id")
+ node_id = module.params.get("node_id")
+ address = module.params.get("address")
+ mtu = module.params.get("mtu")
+ ipv6_dad = module.params.get("ipv6_dad")
+ link_local_address = module.params.get("link_local_address")
+ mac_address = module.params.get("mac_address")
+ mode = module.params.get("mode")
+ encap = module.params.get("encap")
+ encap_scope = "ctx" if module.params.get("encap_scope") == "vrf" else module.params.get("encap_scope")
+ auto_state = module.params.get("auto_state")
+ external_bridge_group_profile = module.params.get("external_bridge_group_profile")
+
+ aci = ACIModule(module)
+
+ node_dn = None
+ if pod_id and node_id:
+ node_dn = "topology/pod-{0}/node-{1}".format(pod_id, node_id)
+
+ child_classes = []
+ if external_bridge_group_profile is not None:
+ child_classes.append("l3extBdProfileCont")
+
+ 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="l3extOut",
+ aci_rn="out-{0}".format(l3out),
+ module_object=l3out,
+ target_filter={"name": l3out},
+ ),
+ subclass_2=dict(
+ aci_class="l3extLNodeP",
+ aci_rn="lnodep-{0}".format(node_profile),
+ module_object=node_profile,
+ target_filter={"name": node_profile},
+ ),
+ subclass_3=dict(
+ aci_class="l3extLIfP",
+ aci_rn="lifp-{0}".format(interface_profile),
+ module_object=interface_profile,
+ target_filter={"name": interface_profile},
+ ),
+ subclass_4=dict(
+ aci_class="l3extVirtualLIfP", aci_rn="vlifp-[{0}]-[{1}]".format(node_dn, encap), module_object=node_dn, target_filter={"nodeDn": node_dn}
+ ),
+ child_classes=child_classes,
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ child_configs = []
+ if external_bridge_group_profile is not None:
+ if external_bridge_group_profile == "" and isinstance(aci.existing, list) and len(aci.existing) > 0:
+ if aci.existing[0].get("l3extVirtualLIfP", {}).get("children") is not None:
+ child_configs.append(
+ dict(
+ l3extBdProfileCont=dict(
+ attributes=dict(status="deleted"),
+ ),
+ )
+ )
+ elif external_bridge_group_profile != "":
+ child_configs.append(
+ dict(
+ l3extBdProfileCont=dict(
+ attributes=dict(),
+ children=[
+ dict(
+ l3extRsBdProfile=dict(
+ attributes=dict(
+ tDn="uni/tn-{0}/bdprofile-{1}".format(tenant, external_bridge_group_profile),
+ ),
+ )
+ )
+ ],
+ )
+ )
+ )
+
+ aci.payload(
+ aci_class="l3extVirtualLIfP",
+ class_config=dict(
+ addr=address,
+ ipv6Dad=ipv6_dad,
+ mtu=mtu,
+ ifInstT="ext-svi",
+ mode=mode,
+ encap=encap,
+ encapScope=encap_scope,
+ autostate=auto_state,
+ llAddr=link_local_address,
+ mac=mac_address,
+ ),
+ child_configs=child_configs,
+ )
+
+ aci.get_diff(aci_class="l3extVirtualLIfP")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_floating_svi_path.py b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_floating_svi_path.py
new file mode 100644
index 000000000..3d7c45a33
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_floating_svi_path.py
@@ -0,0 +1,491 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Shreyas Srish <ssrish@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_l3out_floating_svi_path
+short_description: Manage Layer 3 Outside (L3Out) Floating SVI Path Attributes (l3ext:RsDynPathAtt)
+description:
+- Manages L3Out Floating SVI path attributes on Cisco ACI fabrics.
+options:
+ tenant:
+ description:
+ - Name of an existing tenant.
+ type: str
+ aliases: [ tenant_name ]
+ required: true
+ l3out:
+ description:
+ - Name of an existing L3Out.
+ type: str
+ aliases: [ l3out_name ]
+ required: true
+ node_profile:
+ description:
+ - Name of the node profile.
+ type: str
+ aliases: [ node_profile_name, logical_node ]
+ required: true
+ interface_profile:
+ description:
+ - Name of the interface profile.
+ type: str
+ aliases: [ interface_profile_name, logical_interface ]
+ required: true
+ pod_id:
+ description:
+ - Pod to build the interface on.
+ type: str
+ required: true
+ node_id:
+ description:
+ - Node to build the interface on for Port-channels and single ports.
+ type: str
+ required: true
+ encap:
+ description:
+ - Encapsulation on the interface (e.g. "vlan-500")
+ type: str
+ required: true
+ domain:
+ description:
+ - This option allows virtual machines to send frames with a mac address.
+ type: str
+ domain_type:
+ description:
+ - The domain type of the path.
+ - The physical domain type is only supported in APIC v5.0 and above.
+ type: str
+ choices: [ physical, vmware ]
+ access_encap:
+ description:
+ - The port encapsulation option.
+ type: str
+ floating_ip:
+ description:
+ - The floating IP address.
+ type: str
+ aliases: [ floating_address ]
+ forged_transmit:
+ description:
+ - This option allows virtual machines to send frames with a mac address.
+ - This is only supported in APIC v5.0 and above.
+ type: str
+ choices: [ enabled, disabled ]
+ mac_change:
+ description:
+ - The status of the mac address change support for port groups in an external VMM controller.
+ - This is only supported in APIC v5.0 and above.
+ type: str
+ choices: [ enabled, disabled ]
+ promiscuous_mode:
+ description:
+ - The status of promiscuous mode for port groups in an external VMM controller.
+ - This is only supported in APIC v5.0 and above.
+ type: str
+ choices: [ enabled, disabled ]
+ enhanced_lag_policy:
+ description:
+ - The enhanced lag policy of the path.
+ - Pass "" as the value to remove an existing enhanced lag policy (See Examples).
+ type: str
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+
+notes:
+- The C(tenant), C(l3out), C(logical_node_profile), C(logical_interface_profile) and C(floating_svi) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant), M(cisco.aci.aci_l3out), M(cisco.aci.aci_l3out_logical_node_profile), M(cisco.aci.aci_l3out_logical_interface_profile) and
+ M(cisco.aci.aci_l3out_floating_svi) can be used for this.
+seealso:
+- module: cisco.aci.aci_tenant
+- module: cisco.aci.aci_l3out
+- module: cisco.aci.aci_l3out_logical_node_profile
+- module: cisco.aci.aci_l3out_logical_interface_profile
+- module: cisco.aci.aci_l3out_floating_svi
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(l3ext:RsDynPathAtt))
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Shreyas Srish (@shrsr)
+"""
+
+EXAMPLES = r"""
+- name: Create a Floating SVI path attribute
+ cisco.aci.aci_l3out_floating_svi_path:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ pod_id: 1
+ node_id: 201
+ encap: vlan-1
+ floating_ip: 23.45.67.90/24
+ domain_type: virtual
+ domain: anstest
+ enhanced_lag_policy: enhanced
+ state: present
+ delegate_to: localhost
+
+- name: Remove enhanced lag policy from the path
+ cisco.aci.aci_l3out_floating_svi_path:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ pod_id: 1
+ node_id: 201
+ encap: vlan-1
+ floating_ip: 23.45.67.90/24
+ domain_type: virtual
+ domain: anstest
+ enhanced_lag_policy: ""
+ state: present
+ delegate_to: localhost
+
+- name: Remove a Floating SVI path attribute
+ cisco.aci.aci_l3out_floating_svi_path:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ pod_id: 1
+ node_id: 201
+ encap: vlan-1
+ domain_type: virtual
+ domain: anstest
+ state: absent
+ delegate_to: localhost
+
+- name: Query a Floating SVI path attribute
+ cisco.aci.aci_l3out_floating_svi_path:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ pod_id: 1
+ node_id: 201
+ encap: vlan-1
+ domain_type: virtual
+ domain: anstest
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all the Floating SVI path attributes
+ cisco.aci.aci_l3out_floating_svi_path:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ pod_id: 1
+ node_id: 201
+ encap: vlan-1
+ state: query
+ delegate_to: localhost
+ register: query_results
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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
+
+
+def main():
+ argument_spec = aci_argument_spec()
+ argument_spec.update(aci_annotation_spec())
+ argument_spec.update(
+ tenant=dict(type="str", aliases=["tenant_name"], required=True),
+ l3out=dict(type="str", aliases=["l3out_name"], required=True),
+ node_profile=dict(type="str", aliases=["node_profile_name", "logical_node"], required=True),
+ interface_profile=dict(type="str", aliases=["interface_profile_name", "logical_interface"], required=True),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ pod_id=dict(type="str", required=True),
+ node_id=dict(type="str", required=True),
+ encap=dict(type="str", required=True),
+ floating_ip=dict(type="str", aliases=["floating_address"]),
+ forged_transmit=dict(type="str", choices=["enabled", "disabled"]),
+ mac_change=dict(type="str", choices=["enabled", "disabled"]),
+ promiscuous_mode=dict(type="str", choices=["enabled", "disabled"]),
+ domain_type=dict(type="str", choices=["physical", "vmware"]),
+ domain=dict(type="str"),
+ enhanced_lag_policy=dict(type="str"),
+ access_encap=dict(type="str"),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "present", ["domain_type", "domain", "floating_ip"]],
+ ["state", "absent", ["domain_type", "domain"]],
+ ],
+ )
+
+ tenant = module.params.get("tenant")
+ l3out = module.params.get("l3out")
+ node_profile = module.params.get("node_profile")
+ interface_profile = module.params.get("interface_profile")
+ state = module.params.get("state")
+ pod_id = module.params.get("pod_id")
+ node_id = module.params.get("node_id")
+ floating_ip = module.params.get("floating_ip")
+ encap = module.params.get("encap")
+ forged_transmit = module.params.get("forged_transmit").capitalize() if module.params.get("forged_transmit") else None
+ mac_change = module.params.get("mac_change").capitalize() if module.params.get("mac_change") else None
+ promiscuous_mode = module.params.get("promiscuous_mode").capitalize() if module.params.get("promiscuous_mode") else None
+ domain_type = module.params.get("domain_type")
+ domain = module.params.get("domain")
+ enhanced_lag_policy = module.params.get("enhanced_lag_policy")
+ access_encap = module.params.get("access_encap")
+
+ aci = ACIModule(module)
+
+ node_dn = "topology/pod-{0}/node-{1}".format(pod_id, node_id)
+
+ tDn = None
+ if domain_type == "physical":
+ tDn = "uni/phys-{0}".format(domain)
+ elif domain_type == "vmware":
+ tDn = "uni/vmmp-VMware/dom-{0}".format(domain)
+
+ 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="l3extOut",
+ aci_rn="out-{0}".format(l3out),
+ module_object=l3out,
+ target_filter={"name": l3out},
+ ),
+ subclass_2=dict(
+ aci_class="l3extLNodeP",
+ aci_rn="lnodep-{0}".format(node_profile),
+ module_object=node_profile,
+ target_filter={"name": node_profile},
+ ),
+ subclass_3=dict(
+ aci_class="l3extLIfP",
+ aci_rn="lifp-{0}".format(interface_profile),
+ module_object=interface_profile,
+ target_filter={"name": interface_profile},
+ ),
+ subclass_4=dict(
+ aci_class="l3extVirtualLIfP", aci_rn="vlifp-[{0}]-[{1}]".format(node_dn, encap), module_object=node_dn, target_filter={"nodeDn": node_dn}
+ ),
+ subclass_5=dict(
+ aci_class="l3extRsDynPathAtt",
+ aci_rn="rsdynPathAtt-[{0}]".format(tDn),
+ module_object=tDn,
+ target_filter={"tDn": tDn},
+ ),
+ child_classes=["l3extVirtualLIfPLagPolAtt"],
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ child_configs = []
+ if enhanced_lag_policy is not None and domain_type == "vmware":
+ existing_enhanced_lag_policy = ""
+ if isinstance(aci.existing, list) and len(aci.existing) > 0:
+ for child in aci.existing[0].get("l3extRsDynPathAtt", {}).get("children", {}):
+ if child.get("l3extVirtualLIfPLagPolAtt"):
+ try:
+ existing_enhanced_lag_policy = child["l3extVirtualLIfPLagPolAtt"]["children"][0]["l3extRsVSwitchEnhancedLagPol"]["attributes"][
+ "tDn"
+ ].split("enlacplagp-")[1]
+ except (AttributeError, IndexError, KeyError):
+ existing_enhanced_lag_policy = ""
+
+ if enhanced_lag_policy == "":
+ child_configs.append(
+ dict(
+ l3extVirtualLIfPLagPolAtt=dict(
+ attributes=dict(status="deleted"),
+ ),
+ )
+ )
+
+ if enhanced_lag_policy != "":
+ child = [
+ dict(
+ l3extRsVSwitchEnhancedLagPol=dict(
+ attributes=dict(tDn="{0}/vswitchpolcont/enlacplagp-{1}".format(tDn, enhanced_lag_policy)),
+ )
+ ),
+ ]
+ if enhanced_lag_policy != existing_enhanced_lag_policy and existing_enhanced_lag_policy != "":
+ child.append(
+ dict(
+ l3extRsVSwitchEnhancedLagPol=dict(
+ attributes=dict(status="deleted", tDn="{0}/vswitchpolcont/enlacplagp-{1}".format(tDn, existing_enhanced_lag_policy)),
+ )
+ )
+ )
+ child_configs.append(dict(l3extVirtualLIfPLagPolAtt=dict(attributes=dict(), children=child)))
+
+ aci.payload(
+ aci_class="l3extRsDynPathAtt",
+ class_config=dict(
+ floatingAddr=floating_ip,
+ forgedTransmit=forged_transmit,
+ macChange=mac_change,
+ promMode=promiscuous_mode,
+ encap=access_encap,
+ ),
+ child_configs=child_configs,
+ )
+
+ aci.get_diff(aci_class="l3extRsDynPathAtt")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_floating_svi_path_secondary_ip.py b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_floating_svi_path_secondary_ip.py
new file mode 100644
index 000000000..b49c18169
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_floating_svi_path_secondary_ip.py
@@ -0,0 +1,398 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Shreyas Srish <ssrish@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_l3out_floating_svi_path_secondary_ip
+short_description: Manages Layer 3 Outside (L3Out) Floating SVI Path Attribute's Secondary IP addresses (l3ext:Ip)
+description:
+- Manages L3Out Floating SVI path attribute's secondary IP addresses on Cisco ACI fabrics.
+options:
+ tenant:
+ description:
+ - Name of an existing tenant.
+ type: str
+ aliases: [ tenant_name ]
+ required: true
+ l3out:
+ description:
+ - Name of an existing L3Out.
+ type: str
+ aliases: [ l3out_name ]
+ required: true
+ node_profile:
+ description:
+ - Name of the node profile.
+ type: str
+ aliases: [ node_profile_name, logical_node ]
+ required: true
+ interface_profile:
+ description:
+ - Name of the interface profile.
+ type: str
+ aliases: [ interface_profile_name, logical_interface ]
+ required: true
+ pod_id:
+ description:
+ - Pod to build the interface on.
+ type: str
+ required: true
+ node_id:
+ description:
+ - Node to build the interface on for Port-channels and single ports.
+ type: str
+ required: true
+ encap:
+ description:
+ - Encapsulation on the interface (e.g. "vlan-500")
+ type: str
+ required: true
+ domain:
+ description:
+ - This option allows virtual machines to send frames with a mac address.
+ type: str
+ required: true
+ domain_type:
+ description:
+ - The domain type of the path.
+ type: str
+ choices: [ physical, vmware ]
+ required: true
+ secondary_ip:
+ description:
+ - The secondary floating IP address.
+ type: str
+ aliases: [ secondary_floating_address ]
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+
+notes:
+- The C(tenant), C(l3out), C(logical_node_profile), C(logical_interface_profile) and C(floating_svi) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant), M(cisco.aci.aci_l3out), M(cisco.aci.aci_l3out_logical_node_profile), M(cisco.aci.aci_l3out_logical_interface_profile), \
+ M(cisco.aci.aci_l3out_floating_svi) and M(cisco.aci.aci_l3out_floating_svi_path) can be used for this.
+seealso:
+- module: cisco.aci.aci_tenant
+- module: cisco.aci.aci_l3out
+- module: cisco.aci.aci_l3out_logical_node_profile
+- module: cisco.aci.aci_l3out_logical_interface_profile
+- module: cisco.aci.aci_l3out_floating_svi
+- module: cisco.aci.aci_l3out_floating_svi_path
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(l3ext:Ip)
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Shreyas Srish (@shrsr)
+"""
+
+EXAMPLES = r"""
+- name: Create a Floating SVI path attribute secondary IP
+ cisco.aci.aci_l3out_floating_svi_path_secondary_ip:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ pod_id: 1
+ node_id: 201
+ encap: vlan-1
+ secondary_ip: 23.45.67.90/24
+ domain_type: virtual
+ domain: anstest
+ state: present
+ delegate_to: localhost
+
+- name: Remove a Floating SVI path attribute secondary IP
+ cisco.aci.aci_l3out_floating_svi_path_secondary_ip:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ pod_id: 1
+ node_id: 201
+ encap: vlan-1
+ secondary_ip: 23.45.67.90/24
+ domain_type: virtual
+ domain: anstest
+ state: absent
+ delegate_to: localhost
+
+- name: Query a Floating SVI path attribute secondary IP
+ cisco.aci.aci_l3out_floating_svi_path_secondary_ip:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ pod_id: 1
+ node_id: 201
+ encap: vlan-1
+ domain_type: virtual
+ domain: anstest
+ secondary_ip: 23.45.67.90/24
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all the secondary IPs under a Floating SVI path attribute
+ cisco.aci.aci_l3out_floating_svi_path_secondary_ip:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ pod_id: 1
+ node_id: 201
+ encap: vlan-1
+ domain_type: virtual
+ domain: anstest
+ state: query
+ delegate_to: localhost
+ register: query_results
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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_collections.cisco.aci.plugins.module_utils.aci import ACIModule, aci_argument_spec, aci_annotation_spec
+from ansible.module_utils.basic import AnsibleModule
+
+
+def main():
+ argument_spec = aci_argument_spec()
+ argument_spec.update(aci_annotation_spec())
+ argument_spec.update(
+ tenant=dict(type="str", aliases=["tenant_name"], required=True),
+ l3out=dict(type="str", aliases=["l3out_name"], required=True),
+ node_profile=dict(type="str", aliases=["node_profile_name", "logical_node"], required=True),
+ interface_profile=dict(type="str", aliases=["interface_profile_name", "logical_interface"], required=True),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ pod_id=dict(type="str", required=True),
+ node_id=dict(type="str", required=True),
+ encap=dict(type="str", required=True),
+ domain_type=dict(type="str", choices=["physical", "vmware"], required=True),
+ domain=dict(type="str", required=True),
+ secondary_ip=dict(type="str", aliases=["secondary_floating_address"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["secondary_ip"]],
+ ["state", "present", ["secondary_ip"]],
+ ],
+ )
+
+ tenant = module.params.get("tenant")
+ l3out = module.params.get("l3out")
+ node_profile = module.params.get("node_profile")
+ interface_profile = module.params.get("interface_profile")
+ pod_id = module.params.get("pod_id")
+ node_id = module.params.get("node_id")
+ encap = module.params.get("encap")
+ secondary_ip = module.params.get("secondary_ip")
+ domain_type = module.params.get("domain_type")
+ domain = module.params.get("domain")
+ state = module.params.get("state")
+
+ aci = ACIModule(module)
+
+ node_dn = "topology/pod-{0}/node-{1}".format(pod_id, node_id)
+
+ tDn = None
+ if domain_type == "physical":
+ tDn = "uni/phys-{0}".format(domain)
+ else:
+ tDn = "uni/vmmp-VMware/dom-{0}".format(domain)
+
+ 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="l3extOut",
+ aci_rn="out-{0}".format(l3out),
+ module_object=l3out,
+ target_filter={"name": l3out},
+ ),
+ subclass_2=dict(
+ aci_class="l3extLNodeP",
+ aci_rn="lnodep-{0}".format(node_profile),
+ module_object=node_profile,
+ target_filter={"name": node_profile},
+ ),
+ subclass_3=dict(
+ aci_class="l3extLIfP",
+ aci_rn="lifp-{0}".format(interface_profile),
+ module_object=interface_profile,
+ target_filter={"name": interface_profile},
+ ),
+ subclass_4=dict(
+ aci_class="l3extVirtualLIfP", aci_rn="vlifp-[{0}]-[{1}]".format(node_dn, encap), module_object=node_dn, target_filter={"nodeDn": node_dn}
+ ),
+ subclass_5=dict(
+ aci_class="l3extRsDynPathAtt",
+ aci_rn="rsdynPathAtt-[{0}]".format(tDn),
+ module_object=tDn,
+ target_filter={"tDn": tDn},
+ ),
+ subclass_6=dict(
+ aci_class="l3extIp",
+ aci_rn="addr-[{0}]".format(secondary_ip),
+ module_object=secondary_ip,
+ target_filter={"addr": secondary_ip},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(aci_class="l3extIp", class_config=dict(addr=secondary_ip, ipv6Dad="disabled"))
+
+ aci.get_diff(aci_class="l3extIp")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_floating_svi_secondary_ip.py b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_floating_svi_secondary_ip.py
new file mode 100644
index 000000000..ea71376dd
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_floating_svi_secondary_ip.py
@@ -0,0 +1,362 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Shreyas Srish <ssrish@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_l3out_floating_svi_secondary_ip
+short_description: Manages Layer 3 Outside (L3Out) Floating SVI Secondary IP addresses (l3ext:Ip)
+description:
+- Manages L3Out Floating SVI secondary IP addresses on Cisco ACI fabrics.
+options:
+ tenant:
+ description:
+ - Name of an existing tenant.
+ type: str
+ aliases: [ tenant_name ]
+ required: true
+ l3out:
+ description:
+ - Name of an existing L3Out.
+ type: str
+ aliases: [ l3out_name ]
+ required: true
+ node_profile:
+ description:
+ - Name of the node profile.
+ type: str
+ aliases: [ node_profile_name, logical_node ]
+ required: true
+ interface_profile:
+ description:
+ - Name of the interface profile.
+ type: str
+ aliases: [ interface_profile_name, logical_interface ]
+ required: true
+ pod_id:
+ description:
+ - Pod to build the interface on.
+ type: str
+ required: true
+ node_id:
+ description:
+ - Node to build the interface on for Port-channels and single ports.
+ type: str
+ required: true
+ encap:
+ description:
+ - Encapsulation on the interface (e.g. "vlan-500")
+ type: str
+ required: true
+ secondary_ip:
+ description:
+ - The secondary floating IP address.
+ type: str
+ aliases: [ secondary_floating_address ]
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+
+notes:
+- The C(tenant), C(l3out), C(logical_node_profile), C(logical_interface_profile) and C(floating_svi) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant), M(cisco.aci.aci_l3out), M(cisco.aci.aci_l3out_logical_node_profile), M(cisco.aci.aci_l3out_logical_interface_profile) and \
+ M(cisco.aci.aci_l3out_floating_svi) can be used for this.
+seealso:
+- module: cisco.aci.aci_tenant
+- module: cisco.aci.aci_l3out
+- module: cisco.aci.aci_l3out_logical_node_profile
+- module: cisco.aci.aci_l3out_logical_interface_profile
+- module: cisco.aci.aci_l3out_floating_svi
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(l3ext:Ip)
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Shreyas Srish (@shrsr)
+"""
+
+EXAMPLES = r"""
+- name: Create a Floating SVI secondary IP
+ cisco.aci.aci_l3out_floating_svi_secondary_ip:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ pod_id: 1
+ node_id: 201
+ encap: vlan-1
+ secondary_ip: 23.45.67.90/24
+ state: present
+ delegate_to: localhost
+
+- name: Remove a Floating SVI secondary IP
+ cisco.aci.aci_l3out_floating_svi_secondary_ip:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ pod_id: 1
+ node_id: 201
+ encap: vlan-1
+ secondary_ip: 23.45.67.90/24
+ state: absent
+ delegate_to: localhost
+
+- name: Query a Floating SVI secondary IP
+ cisco.aci.aci_l3out_floating_svi_secondary_ip:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ pod_id: 1
+ node_id: 201
+ encap: vlan-1
+ secondary_ip: 23.45.67.90/24
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all the secondary IPs under a Floating SVI
+ cisco.aci.aci_l3out_floating_svi_secondary_ip:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ pod_id: 1
+ node_id: 201
+ encap: vlan-1
+ state: query
+ delegate_to: localhost
+ register: query_results
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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_collections.cisco.aci.plugins.module_utils.aci import ACIModule, aci_argument_spec, aci_annotation_spec
+from ansible.module_utils.basic import AnsibleModule
+
+
+def main():
+ argument_spec = aci_argument_spec()
+ argument_spec.update(aci_annotation_spec())
+ argument_spec.update(
+ tenant=dict(type="str", aliases=["tenant_name"], required=True),
+ l3out=dict(type="str", aliases=["l3out_name"], required=True),
+ node_profile=dict(type="str", aliases=["node_profile_name", "logical_node"], required=True),
+ interface_profile=dict(type="str", aliases=["interface_profile_name", "logical_interface"], required=True),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ pod_id=dict(type="str", required=True),
+ node_id=dict(type="str", required=True),
+ encap=dict(type="str", required=True),
+ secondary_ip=dict(type="str", aliases=["secondary_floating_address"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["secondary_ip"]],
+ ["state", "present", ["secondary_ip"]],
+ ],
+ )
+
+ tenant = module.params.get("tenant")
+ l3out = module.params.get("l3out")
+ node_profile = module.params.get("node_profile")
+ interface_profile = module.params.get("interface_profile")
+ pod_id = module.params.get("pod_id")
+ node_id = module.params.get("node_id")
+ encap = module.params.get("encap")
+ secondary_ip = module.params.get("secondary_ip")
+ state = module.params.get("state")
+
+ aci = ACIModule(module)
+
+ node_dn = "topology/pod-{0}/node-{1}".format(pod_id, node_id)
+
+ 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="l3extOut",
+ aci_rn="out-{0}".format(l3out),
+ module_object=l3out,
+ target_filter={"name": l3out},
+ ),
+ subclass_2=dict(
+ aci_class="l3extLNodeP",
+ aci_rn="lnodep-{0}".format(node_profile),
+ module_object=node_profile,
+ target_filter={"name": node_profile},
+ ),
+ subclass_3=dict(
+ aci_class="l3extLIfP",
+ aci_rn="lifp-{0}".format(interface_profile),
+ module_object=interface_profile,
+ target_filter={"name": interface_profile},
+ ),
+ subclass_4=dict(
+ aci_class="l3extVirtualLIfP", aci_rn="vlifp-[{0}]-[{1}]".format(node_dn, encap), module_object=node_dn, target_filter={"nodeDn": node_dn}
+ ),
+ subclass_5=dict(
+ aci_class="l3extIp",
+ aci_rn="addr-[{0}]".format(secondary_ip),
+ module_object=secondary_ip,
+ target_filter={"addr": secondary_ip},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(aci_class="l3extIp", class_config=dict(addr=secondary_ip, ipv6Dad="enabled"))
+
+ aci.get_diff(aci_class="l3extIp")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_hsrp_group.py b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_hsrp_group.py
new file mode 100644
index 000000000..c6f7316b2
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_hsrp_group.py
@@ -0,0 +1,393 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Shreyas Srish (@shrsr) <ssrish@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_l3out_hsrp_group
+short_description: Manage HSRP group (hsrp:GroupP) of the HSRP interface profile (hsrp:IfP)
+description:
+- Manage HSRP group of the HSRP interface profile on Cisco ACI fabrics.
+options:
+ tenant:
+ description:
+ - Name of an existing tenant.
+ type: str
+ aliases: [ tenant_name ]
+ l3out:
+ description:
+ - Name of an existing L3Out.
+ type: str
+ aliases: [ l3out_name ]
+ node_profile:
+ description:
+ - Name of the node profile.
+ type: str
+ aliases: [ node_profile_name, logical_node ]
+ interface_profile:
+ description:
+ - Name of an existing interface profile.
+ type: str
+ aliases: [ interface_profile_name, logical_interface ]
+ hsrp_interface_group:
+ description:
+ - Name of the HSRP interface group.
+ type: str
+ aliases: [ name, hsrp_group ]
+ group_id:
+ description:
+ - The group id of the HSRP interface group.
+ type: int
+ ip:
+ description:
+ - The virtual IP address of the HSRP interface group.
+ type: str
+ mac:
+ description:
+ - The MAC address of the HSRP interface group.
+ type: str
+ group_name:
+ description:
+ - The group name is used to define and manage the specific HSRP interface group, facilitating high availability in the network.
+ type: str
+ description:
+ description:
+ - The description of the HSRP interface group.
+ type: str
+ aliases: [ descr ]
+ group_type:
+ description:
+ - The type of the HSRP interface group.
+ type: str
+ choices: [ ipv4, ipv6 ]
+ ip_obtain_mode:
+ description:
+ - The mode of method used to obtain the IP address.
+ type: str
+ choices: [ admin, auto, learn ]
+ group_policy:
+ description:
+ - The group policy of the HSRP interface group.
+ type: str
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+notes:
+- The C(tenant), C(l3out), C(logical_node_profile), C(logical_interface_profile) and C(hsrp_interface_profile) must exist before using this module in
+ your playbook. The M(cisco.aci.aci_tenant), M(cisco.aci.aci_l3out), M(cisco.aci.aci_l3out_logical_node_profile),
+ M(cisco.aci.aci_l3out_logical_interface_profile) and M(cisco.aci.aci_l3out_hsrp_interface_profile) can be used for this.
+seealso:
+- module: aci_tenant
+- module: aci_l3out
+- module: aci_l3out_logical_node_profile
+- module: aci_l3out_logical_interface_profile
+- module: aci_l3out_hsrp_interface_profile
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(hsrp:IfP).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Shreyas Srish (@shrsr)
+"""
+
+EXAMPLES = r"""
+- name: Add a new HSRP group
+ cisco.aci.aci_l3out_hsrp_group:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ hsrp_interface_group: group1
+ ip: 12.34.56.32
+ group_type: ipv4
+ ip_obtain_mode: admin
+ group_policy: default
+ state: present
+ delegate_to: localhost
+
+- name: Delete a HSRP group
+ cisco.aci.aci_l3out_hsrp_group:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ hsrp_interface_group: group1
+ ip: 12.34.56.32
+ group_type: ipv4
+ ip_obtain_mode: admin
+ group_policy: default
+ state: absent
+ delegate_to: localhost
+
+- name: Query a HSRP group
+ cisco.aci.aci_l3out_hsrp_group:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ hsrp_interface_group: group1
+ ip: 12.34.56.32
+ group_type: ipv4
+ ip_obtain_mode: admin
+ group_policy: default
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all HSRP groups
+ cisco.aci.aci_l3out_hsrp_group:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ state: query
+ delegate_to: localhost
+ register: query_result
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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"]),
+ l3out=dict(type="str", aliases=["l3out_name"]),
+ node_profile=dict(type="str", aliases=["node_profile_name", "logical_node"]),
+ interface_profile=dict(type="str", aliases=["interface_profile_name", "logical_interface"]),
+ hsrp_interface_group=dict(type="str", aliases=["name", "hsrp_group"]),
+ group_id=dict(type="int"),
+ ip=dict(type="str"),
+ mac=dict(type="str"),
+ group_name=dict(type="str"),
+ description=dict(type="str", aliases=["descr"]),
+ group_type=dict(type="str", choices=["ipv4", "ipv6"]),
+ ip_obtain_mode=dict(type="str", choices=["admin", "auto", "learn"]),
+ group_policy=dict(type="str"),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["tenant", "l3out", "node_profile", "interface_profile", "hsrp_interface_group"]],
+ ["state", "present", ["tenant", "l3out", "node_profile", "interface_profile", "hsrp_interface_group"]],
+ ],
+ )
+
+ tenant = module.params.get("tenant")
+ l3out = module.params.get("l3out")
+ node_profile = module.params.get("node_profile")
+ interface_profile = module.params.get("interface_profile")
+ hsrp_interface_group = module.params.get("hsrp_interface_group")
+ group_id = module.params.get("group_id")
+ ip = module.params.get("ip")
+ mac = module.params.get("mac")
+ group_name = module.params.get("group_name")
+ description = module.params.get("description")
+ group_type = module.params.get("group_type")
+ ip_obtain_mode = module.params.get("ip_obtain_mode")
+ group_policy = module.params.get("group_policy")
+ state = module.params.get("state")
+
+ 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="l3extOut",
+ aci_rn="out-{0}".format(l3out),
+ module_object=l3out,
+ target_filter={"name": l3out},
+ ),
+ subclass_2=dict(
+ aci_class="l3extLNodeP",
+ aci_rn="lnodep-{0}".format(node_profile),
+ module_object=node_profile,
+ target_filter={"name": node_profile},
+ ),
+ subclass_3=dict(
+ aci_class="l3extLIfP",
+ aci_rn="lifp-[{0}]".format(interface_profile),
+ module_object=interface_profile,
+ target_filter={"name": interface_profile},
+ ),
+ subclass_4=dict(
+ aci_class="hsrpIfP",
+ aci_rn="hsrpIfP",
+ module_object=interface_profile,
+ target_filter={"name": interface_profile},
+ ),
+ subclass_5=dict(
+ aci_class="hsrpGroupP",
+ aci_rn="hsrpGroupP-{0}".format(hsrp_interface_group),
+ module_object=hsrp_interface_group,
+ target_filter={"name": hsrp_interface_group},
+ ),
+ child_classes=["hsrpRsGroupPol"],
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class="hsrpGroupP",
+ class_config=dict(groupAf=group_type, groupId=group_id, groupName=group_name, ip=ip, ipObtainMode=ip_obtain_mode, mac=mac, descr=description),
+ child_configs=[dict(hsrpRsGroupPol=dict(attributes=dict(tnHsrpGroupPolName=group_policy)))] if group_policy is not None else [],
+ )
+
+ aci.get_diff(aci_class="hsrpGroupP")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_hsrp_interface_profile.py b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_hsrp_interface_profile.py
new file mode 100644
index 000000000..634a7f2f5
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_hsrp_interface_profile.py
@@ -0,0 +1,320 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Shreyas Srish (@shrsr) <ssrish@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_l3out_hsrp_interface_profile
+short_description: Manages Layer 3 Outside (L3Out) HSRP interface profile (hsrp:IfP)
+description:
+- Manages L3Out HSRP interface profile on Cisco ACI fabrics.
+options:
+ tenant:
+ description:
+ - Name of an existing tenant.
+ type: str
+ aliases: [ tenant_name ]
+ l3out:
+ description:
+ - Name of an existing L3Out.
+ type: str
+ aliases: [ l3out_name ]
+ node_profile:
+ description:
+ - Name of the node profile.
+ type: str
+ aliases: [ node_profile_name, logical_node ]
+ interface_profile:
+ description:
+ - Name of an existing interface profile.
+ type: str
+ aliases: [ interface_profile_name, logical_interface ]
+ hsrp_policy:
+ description:
+ - Name of an existing HSRP interface policy.
+ type: str
+ aliases: [ name, hsrp_policy_name ]
+ version:
+ description:
+ - The version of the compatibility catalog.
+ type: str
+ choices: [ v1, v2 ]
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+notes:
+- The C(tenant), C(l3out), C(logical_node_profile) and C(logical_interface_profile) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant), M(cisco.aci.aci_l3out), M(cisco.aci.aci_l3out_logical_node_profile) and M(cisco.aci.aci_l3out_logical_interface_profile)
+ can be used for this.
+- If C(hsrp_policy) is used, it must exist before using this module in your playbook.
+ The M(cisco.aci.aci_interface_policy_hsrp) can be used for this.
+seealso:
+- module: aci_tenant
+- module: aci_l3out
+- module: aci_l3out_logical_node_profile
+- module: aci_l3out_logical_interface_profile
+- module: aci_interface_policy_hsrp
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(hsrp:IfP).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Shreyas Srish (@shrsr)
+"""
+
+EXAMPLES = r"""
+- name: Add a new HSRP interface profile
+ cisco.aci.aci_l3out_hsrp_interface_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ hsrp_policy: default
+ state: present
+ delegate_to: localhost
+
+- name: Delete a HSRP interface profile
+ cisco.aci.aci_l3out_hsrp_interface_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ hsrp_policy: default
+ state: absent
+ delegate_to: localhost
+
+- name: Query a HSRP interface profile
+ cisco.aci.aci_l3out_hsrp_interface_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ hsrp_policy: default
+ state: query
+ delegate_to: localhost
+ register: query_result
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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"]),
+ l3out=dict(type="str", aliases=["l3out_name"]),
+ node_profile=dict(type="str", aliases=["node_profile_name", "logical_node"]),
+ interface_profile=dict(type="str", aliases=["interface_profile_name", "logical_interface"]),
+ hsrp_policy=dict(type="str", aliases=["name", "hsrp_policy_name"]),
+ version=dict(type="str", choices=["v1", "v2"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["tenant", "l3out", "node_profile", "interface_profile"]],
+ ["state", "present", ["tenant", "l3out", "node_profile", "interface_profile"]],
+ ],
+ )
+
+ tenant = module.params.get("tenant")
+ l3out = module.params.get("l3out")
+ node_profile = module.params.get("node_profile")
+ interface_profile = module.params.get("interface_profile")
+ hsrp_policy = module.params.get("hsrp_policy")
+ version = module.params.get("version")
+ state = module.params.get("state")
+
+ 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="l3extOut",
+ aci_rn="out-{0}".format(l3out),
+ module_object=l3out,
+ target_filter={"name": l3out},
+ ),
+ subclass_2=dict(
+ aci_class="l3extLNodeP",
+ aci_rn="lnodep-{0}".format(node_profile),
+ module_object=node_profile,
+ target_filter={"name": node_profile},
+ ),
+ subclass_3=dict(
+ aci_class="l3extLIfP",
+ aci_rn="lifp-[{0}]".format(interface_profile),
+ module_object=interface_profile,
+ target_filter={"name": interface_profile},
+ ),
+ subclass_4=dict(
+ aci_class="hsrpIfP",
+ aci_rn="hsrpIfP",
+ module_object=interface_profile,
+ target_filter={"name": interface_profile},
+ ),
+ child_classes=["hsrpRsIfPol"],
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ child_configs = []
+ if hsrp_policy is not None:
+ child_configs = [dict(hsrpRsIfPol=dict(attributes=dict(tnHsrpIfPolName=hsrp_policy)))]
+
+ aci.payload(aci_class="hsrpIfP", class_config=dict(version=version), child_configs=child_configs)
+
+ aci.get_diff(aci_class="hsrpIfP")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_hsrp_secondary_vip.py b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_hsrp_secondary_vip.py
new file mode 100644
index 000000000..c9902ba76
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_hsrp_secondary_vip.py
@@ -0,0 +1,344 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Shreyas Srish (@shrsr) <ssrish@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_l3out_hsrp_secondary_vip
+short_description: Manage HSRP Secondary Virtual IP of a HSRP group (hsrp:SecVip)
+description:
+- Manage HSRP Secondary Virtual IP of a HSRP group on Cisco ACI fabrics.
+options:
+ tenant:
+ description:
+ - Name of an existing tenant.
+ type: str
+ aliases: [ tenant_name ]
+ l3out:
+ description:
+ - Name of an existing L3Out.
+ type: str
+ aliases: [ l3out_name ]
+ node_profile:
+ description:
+ - Name of the node profile.
+ type: str
+ aliases: [ node_profile_name, logical_node ]
+ interface_profile:
+ description:
+ - Name of an existing interface profile.
+ type: str
+ aliases: [ name, interface_profile_name, logical_interface ]
+ hsrp_interface_group:
+ description:
+ - Name of an existing HSRP group.
+ type: str
+ aliases: [ name, hsrp_group ]
+ secondary_virtual_ip:
+ description:
+ - The version of the compatibility catalog.
+ type: str
+ aliases: [ vip, secondary_vip ]
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+notes:
+- The C(tenant), C(l3out), C(logical_node_profile), C(logical_interface_profile), C(hsrp_interface_profile) and C(hsrp_group) must exist before using
+ this module in your playbook. The M(cisco.aci.aci_tenant), M(cisco.aci.aci_l3out), M(cisco.aci.aci_l3out_logical_node_profile),
+ M(cisco.aci.aci_l3out_logical_interface_profile), M(cisco.aci.aci_l3out_hsrp_interface_profile) and M(cisco.aci.aci_l3out_hsrp_group) can be used for
+ this.
+seealso:
+- module: aci_tenant
+- module: aci_l3out
+- module: aci_l3out_logical_node_profile
+- module: aci_l3out_logical_interface_profile
+- module: aci_l3out_hsrp_interface_profile
+- module: aci_l3out_hsrp_group
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(hsrp:SecVip).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Shreyas Srish (@shrsr)
+"""
+
+EXAMPLES = r"""
+- name: Add a HSRP secondary virtual ip
+ cisco.aci.aci_l3out_hsrp_secondary_vip:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ hsrp_group: my_hsrp_group
+ secondary_virtual_ip: 191.1.1.1
+ state: present
+ delegate_to: localhost
+
+- name: Delete a HSRP secondary virtual ip
+ cisco.aci.aci_l3out_hsrp_secondary_vip:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ hsrp_group: my_hsrp_interface_group
+ secondary_virtual_ip: 191.1.1.1
+ state: absent
+ delegate_to: localhost
+
+- name: Query a HSRP secondary virtual ip
+ cisco.aci.aci_l3out_hsrp_secondary_vip:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ hsrp_group: my_hsrp_group
+ secondary_virtual_ip: 191.1.1.1
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all HSRP secondary virtual ips
+ cisco.aci.aci_l3out_hsrp_secondary_vip:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ hsrp_group: my_hsrp_group
+ state: query
+ delegate_to: localhost
+ register: query_result
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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"]),
+ l3out=dict(type="str", aliases=["l3out_name"]),
+ node_profile=dict(type="str", aliases=["node_profile_name", "logical_node"]),
+ interface_profile=dict(type="str", aliases=["interface_profile_name", "logical_interface"]),
+ hsrp_interface_group=dict(type="str", aliases=["name", "hsrp_group"]),
+ secondary_virtual_ip=dict(type="str", aliases=["vip", "secondary_vip"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["tenant", "l3out", "node_profile", "interface_profile", "hsrp_interface_group", "secondary_virtual_ip"]],
+ ["state", "present", ["tenant", "l3out", "node_profile", "interface_profile", "hsrp_interface_group", "secondary_virtual_ip"]],
+ ],
+ )
+
+ tenant = module.params.get("tenant")
+ l3out = module.params.get("l3out")
+ node_profile = module.params.get("node_profile")
+ interface_profile = module.params.get("interface_profile")
+ hsrp_interface_group = module.params.get("hsrp_interface_group")
+ secondary_virtual_ip = module.params.get("secondary_virtual_ip")
+ state = module.params.get("state")
+
+ 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="l3extOut",
+ aci_rn="out-{0}".format(l3out),
+ module_object=l3out,
+ target_filter={"name": l3out},
+ ),
+ subclass_2=dict(
+ aci_class="l3extLNodeP",
+ aci_rn="lnodep-{0}".format(node_profile),
+ module_object=node_profile,
+ target_filter={"name": node_profile},
+ ),
+ subclass_3=dict(
+ aci_class="l3extLIfP",
+ aci_rn="lifp-[{0}]".format(interface_profile),
+ module_object=interface_profile,
+ target_filter={"name": interface_profile},
+ ),
+ subclass_4=dict(
+ aci_class="hsrpIfP",
+ aci_rn="hsrpIfP",
+ module_object=interface_profile,
+ target_filter={"name": interface_profile},
+ ),
+ subclass_5=dict(
+ aci_class="hsrpGroupP",
+ aci_rn="hsrpGroupP-{0}".format(hsrp_interface_group),
+ module_object=hsrp_interface_group,
+ target_filter={"name": hsrp_interface_group},
+ ),
+ subclass_6=dict(
+ aci_class="hsrpSecVip",
+ aci_rn="hsrpSecVip-[{0}]".format(secondary_virtual_ip),
+ module_object=secondary_virtual_ip,
+ target_filter={"ip": secondary_virtual_ip},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(aci_class="hsrpSecVip", class_config=dict(ip=secondary_virtual_ip))
+
+ aci.get_diff(aci_class="hsrpSecVip")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_interface.py b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_interface.py
index f9a43b012..1f8b86070 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_interface.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_interface.py
@@ -1,6 +1,8 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+# Copyright: (c) 2021, Tim Cragg (@timcragg)
+# Copyright: (c) 2023, Akini Ross (@akinross) <akinross@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
@@ -51,14 +53,19 @@ options:
type: str
path_ep:
description:
- - Path to interface
- - Interface Policy Group name for Port-channels and vPCs
- - Port number for single ports (e.g. "eth1/12")
+ - Path to interface.
+ - Interface Policy Group name for Port-channels and vPCs.
+ - Port number for single ports (e.g. "eth1/12").
type: str
encap:
description:
- - encapsulation on the interface (e.g. "vlan-500")
+ - The encapsulation on the interface (e.g. "vlan-500").
type: str
+ encap_scope:
+ description:
+ - The scope of the encapsulation on the interface.
+ type: str
+ choices: [ vrf, local ]
address:
description:
- IP address.
@@ -80,7 +87,7 @@ options:
choices: [ l3-port, sub-interface, ext-svi ]
mode:
description:
- - Interface mode, only used if instance_type is ext-svi
+ - Interface mode, only used if instance_type is ext-svi.
type: str
choices: [ regular, native, untagged ]
state:
@@ -95,19 +102,51 @@ options:
- SVI auto state.
type: str
choices: [ enabled, disabled ]
+ description:
+ description:
+ - The description of the interface.
+ type: str
+ aliases: [ descr]
+ mac:
+ description:
+ - The MAC address of the interface.
+ type: str
+ aliases: [ mac_address ]
+ micro_bfd:
+ description:
+ - Enable micro BFD on the interface.
+ - Micro BFD should only be configured on Infra SR-MPLS L3Outs Direct Port Channel Interfaces.
+ type: bool
+ micro_bfd_destination:
+ description:
+ - The micro BFD destination address of the interface.
+ type: str
+ aliases: [ micro_bfd_address, micro_bfd_destination_address ]
+ micro_bfd_timer:
+ description:
+ - The micro BFD start timer in seconds.
+ - The APIC defaults to C(0) when unset during creation.
+ type: int
+ aliases: [ micro_bfd_start_timer, micro_bfd_start ]
extends_documentation_fragment:
- cisco.aci.aci
- cisco.aci.annotation
+notes:
+- The C(tenant), C(l3out), C(node_profile) and the C(interface_profile) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant), M(cisco.aci.aci_l3out), M(cisco.aci.aci_l3out_logical_node_profile) and
+ M(cisco.aci.aci_l3out_logical_interface_profile) can be used for this.
seealso:
+- module: aci_tenant
- module: aci_l3out
- module: aci_l3out_logical_node_profile
+- module: aci_l3out_logical_interface_profile
- name: APIC Management Information Model reference
description: More information about the internal APIC class B(l3ext:RsPathL3OutAtt)
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Tim Cragg (@timcragg)
-- Marcel Zehnder (@maercu)
+- Akini Ross (@akinross)
"""
EXAMPLES = r"""
@@ -146,6 +185,25 @@ EXAMPLES = r"""
state: present
delegate_to: localhost
+- name: Add direct port channel interface in the infra SR-MPLS l3out interface profile with micro BFD enabled
+ aci_l3out_interface:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: infra
+ l3out: ansible_infra_sr_mpls_l3out
+ interface_profile: ansible_infra_sr_mpls_l3out_interface_profile
+ pod_id: 1
+ node_id: 101
+ path_ep: pc_ansible_test
+ interface_type: l3-port
+ addr: 192.168.90.1/24
+ micro_bfd: true
+ micro_bfd_destination: 192.168.90.2
+ micro_bfd_timer: 75
+ state: present
+ delegate_to: localhost
+
- name: Delete an interface
cisco.aci.aci_l3out_interface:
host: apic
@@ -307,15 +365,28 @@ def main():
interface_type=dict(type="str", choices=["l3-port", "sub-interface", "ext-svi"]),
mode=dict(type="str", choices=["regular", "native", "untagged"]),
encap=dict(type="str"),
+ encap_scope=dict(type="str", choices=["vrf", "local"]),
auto_state=dict(type="str", choices=["enabled", "disabled"]),
+ description=dict(type="str", aliases=["descr"]),
+ mac=dict(type="str", aliases=["mac_address"]),
+ micro_bfd=dict(type="bool"),
+ micro_bfd_destination=dict(type="str", aliases=["micro_bfd_address", "micro_bfd_destination_address"]),
+ micro_bfd_timer=dict(type="int", aliases=["micro_bfd_start_timer", "micro_bfd_start"]),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
- required_if=[["state", "present", ["interface_type", "pod_id", "node_id", "path_ep"]], ["state", "absent", ["pod_id", "node_id", "path_ep"]]],
+ required_if=[
+ ["state", "present", ["interface_type", "pod_id", "node_id", "path_ep"]],
+ ["state", "absent", ["pod_id", "node_id", "path_ep"]],
+ ["micro_bfd", True, ["micro_bfd_destination"]],
+ ],
+ required_by={"micro_bfd_timer": "micro_bfd", "micro_bfd_destination": "micro_bfd"},
)
+ aci = ACIModule(module)
+
tenant = module.params.get("tenant")
l3out = module.params.get("l3out")
node_profile = module.params.get("node_profile")
@@ -330,9 +401,14 @@ def main():
interface_type = module.params.get("interface_type")
mode = module.params.get("mode")
encap = module.params.get("encap")
+ encap_scope = module.params.get("encap_scope")
auto_state = module.params.get("auto_state")
+ description = module.params.get("description")
+ mac = module.params.get("mac")
+ micro_bfd = aci.boolean(module.params.get("micro_bfd"))
+ micro_bfd_destination = module.params.get("micro_bfd_destination")
+ micro_bfd_timer = module.params.get("micro_bfd_timer")
- aci = ACIModule(module)
if node_id and "-" in node_id:
path_type = "protpaths"
else:
@@ -342,6 +418,12 @@ def main():
if pod_id and node_id and path_ep:
path_dn = "topology/pod-{0}/{1}-{2}/pathep-[{3}]".format(pod_id, path_type, node_id, path_ep)
+ child_classes = []
+ child_configs = []
+ if micro_bfd is not None:
+ child_classes.append("bfdMicroBfdP")
+ child_configs.append(dict(bfdMicroBfdP=dict(attributes=dict(adminState=micro_bfd, dst=micro_bfd_destination, stTm=micro_bfd_timer))))
+
aci.construct_url(
root_class=dict(
aci_class="fvTenant",
@@ -367,7 +449,13 @@ def main():
module_object=interface_profile,
target_filter={"name": interface_profile},
),
- subclass_4=dict(aci_class="l3extRsPathL3OutAtt", aci_rn="rspathL3OutAtt-[{0}]".format(path_dn), module_object=path_dn, target_filter={"tDn": path_dn}),
+ subclass_4=dict(
+ aci_class="l3extRsPathL3OutAtt",
+ aci_rn="rspathL3OutAtt-[{0}]".format(path_dn),
+ module_object=path_dn,
+ target_filter={"tDn": path_dn},
+ ),
+ child_classes=child_classes,
)
aci.get_existing()
@@ -375,7 +463,20 @@ def main():
if state == "present":
aci.payload(
aci_class="l3extRsPathL3OutAtt",
- class_config=dict(tDn=path_dn, addr=address, ipv6Dad=ipv6_dad, mtu=mtu, ifInstT=interface_type, mode=mode, encap=encap, autostate=auto_state),
+ class_config=dict(
+ tDn=path_dn,
+ addr=address,
+ ipv6Dad=ipv6_dad,
+ mtu=mtu,
+ ifInstT=interface_type,
+ mode=mode,
+ encap=encap,
+ encapScope="ctx" if encap_scope == "vrf" else encap_scope,
+ autostate=auto_state,
+ descr=description,
+ mac=mac,
+ ),
+ child_configs=child_configs,
)
aci.get_diff(aci_class="l3extRsPathL3OutAtt")
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_interface_secondary_ip.py b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_interface_secondary_ip.py
index d8311dad5..e127e1ff6 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_interface_secondary_ip.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_interface_secondary_ip.py
@@ -16,9 +16,9 @@ ANSIBLE_METADATA = {
DOCUMENTATION = r"""
---
module: aci_l3out_interface_secondary_ip
-short_description: Manage Layer 3 Outside (L3Out) interface secondary IP addresses (l3ext:Ip).
+short_description: Manage Layer 3 Outside (L3Out) interface secondary IP addresses (l3ext:Ip)
description:
-- Manage Layer 3 Outside (L3Out) interface secondary IP addresses (l3ext:Ip).
+- Manage Layer 3 Outside (L3Out) interface secondary IP addresses.
options:
tenant:
description:
@@ -89,7 +89,7 @@ seealso:
- module: aci_l3out_logical_interface_profile
- module: aci_l3out_logical_interface
- name: APIC Management Information Model reference
- description: More information about the internal APIC class B(l3ext:RsPathL3OutAtt)
+ description: More information about the internal APIC class B(l3ext:Ip)
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Marcel Zehnder (@maercu)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_logical_interface_profile.py b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_logical_interface_profile.py
index db5890205..cd32ccb5a 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_logical_interface_profile.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_logical_interface_profile.py
@@ -1,6 +1,7 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+# Copyright: (c) 2024, Gaspard Micol (@gmicol) <gmicol@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
@@ -18,39 +19,96 @@ description:
options:
tenant:
description:
- - Name of an existing tenant.
+ - The name of an existing tenant.
type: str
aliases: [ tenant_name ]
l3out:
description:
- - Name of an existing L3Out.
+ - The name of an existing L3Out.
type: str
aliases: [ l3out_name ]
node_profile:
description:
- - Name of the node profile.
+ - The name of the node profile.
type: str
aliases: [ node_profile_name, logical_node ]
interface_profile:
description:
- - Name of the interface profile.
+ - The name of the logical interface profile.
type: str
aliases: [ name, interface_profile_name, logical_interface ]
nd_policy:
description:
- - Name of the neighbor discovery interface policy.
+ - The name of the neighbor discovery interface policy.
type: str
- default: ""
egress_dpp_policy:
description:
- - Name of the egress data plane policing policy.
+ - The name of the egress data plane policing policy.
type: str
- default: ""
ingress_dpp_policy:
description:
- - Name of the ingress data plane policing policy.
+ - The name of the ingress data plane policing policy.
type: str
- default: ""
+ qos_priority:
+ description:
+ - The QoS priority class ID.
+ - The APIC defaults to C(unspecified) when unset during creation.
+ type: str
+ choices: [ level1, level2, level3, level4, level5, level6, unspecified ]
+ aliases: [ priority, prio ]
+ qos_custom_policy:
+ description:
+ - The name of the QoS custom policy.
+ type: str
+ aliases: [ qos_custom_policy_name ]
+ pim_v4_interface_profile:
+ description:
+ - The PIM IPv4 interface profile.
+ type: dict
+ suboptions:
+ tenant:
+ description:
+ - The name of the tenant to which the PIM IPv4 interface policy belongs.
+ type: str
+ aliases: [ tenant_name ]
+ pim:
+ description:
+ - The name of the PIM IPv4 interface policy.
+ type: str
+ aliases: [ pim_interface_policy, name ]
+ aliases: [ pim_v4 ]
+ pim_v6_interface_profile:
+ description:
+ - The PIM IPv6 interface profile.
+ type: dict
+ suboptions:
+ tenant:
+ description:
+ - The name of the tenant to which the PIM IPv6 interface policy belongs.
+ type: str
+ aliases: [ tenant_name ]
+ pim:
+ description:
+ - The name of the PIM IPv6 interface policy.
+ type: str
+ aliases: [ pim_interface_policy, name ]
+ aliases: [ pim_v6 ]
+ igmp_interface_profile:
+ description:
+ - The IGMP interface profile.
+ type: dict
+ suboptions:
+ tenant:
+ description:
+ - The name of the tenant to which the IGMP interface policy belongs.
+ type: str
+ aliases: [ tenant_name ]
+ igmp:
+ description:
+ - The name of the IGMP interface policy.
+ type: str
+ aliases: [ igmp_interface_policy, name ]
+ aliases: [ igmp ]
description:
description:
- The description for the logical interface profile.
@@ -68,14 +126,19 @@ extends_documentation_fragment:
- cisco.aci.annotation
- cisco.aci.owner
+notes:
+- The I(tenant), I(l3out) and I(node_profile) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant), M(cisco.aci.aci_l3out) and M(cisco.aci.aci_l3out_logical_node_profile) can be used for this.
seealso:
-- module: aci_l3out
-- module: aci_l3out_logical_node_profile
+- module: cisco.aci.aci_tenant
+- module: cisco.aci.aci_l3out
+- module: cisco.aci.aci_l3out_logical_node_profile
- name: APIC Management Information Model reference
- description: More information about the internal APIC classes
+ description: More information about the internal APIC class B(l3ext:LIfP).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Marcel Zehnder (@maercu)
+- Gaspard Micol (@gmicol)
"""
EXAMPLES = r"""
@@ -91,7 +154,7 @@ EXAMPLES = r"""
state: present
delegate_to: localhost
-- name: Delete an interface profile
+- name: Query an interface profile
cisco.aci.aci_l3out_logical_interface_profile:
host: apic
username: admin
@@ -100,30 +163,30 @@ EXAMPLES = r"""
l3out: my_l3out
node_profile: my_node_profile
interface_profile: my_interface_profile
- state: absent
+ state: query
delegate_to: localhost
+ register: query_result
-- name: Query an interface profile
+- name: Query all interface profiles
cisco.aci.aci_l3out_logical_interface_profile:
host: apic
username: admin
password: SomeSecretPassword
- tenant: my_tenant
- l3out: my_l3out
- node_profile: my_node_profile
- interface_profile: my_interface_profile
state: query
delegate_to: localhost
register: query_result
-- name: Query all interface profiles
+- name: Delete an interface profile
cisco.aci.aci_l3out_logical_interface_profile:
host: apic
username: admin
password: SomeSecretPassword
- state: query
+ tenant: my_tenant
+ l3out: my_l3out
+ node_profile: my_node_profile
+ interface_profile: my_interface_profile
+ state: absent
delegate_to: localhost
- register: query_result
"""
RETURN = r"""
@@ -233,7 +296,14 @@ url:
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
+from ansible_collections.cisco.aci.plugins.module_utils.aci import (
+ ACIModule,
+ aci_argument_spec,
+ aci_annotation_spec,
+ aci_owner_spec,
+ pim_interface_profile_spec,
+ igmp_interface_profile_spec,
+)
def main():
@@ -245,9 +315,14 @@ def main():
l3out=dict(type="str", aliases=["l3out_name"]),
node_profile=dict(type="str", aliases=["node_profile_name", "logical_node"]),
interface_profile=dict(type="str", aliases=["name", "interface_profile_name", "logical_interface"]),
- nd_policy=dict(type="str", default=""),
- egress_dpp_policy=dict(type="str", default=""),
- ingress_dpp_policy=dict(type="str", default=""),
+ nd_policy=dict(type="str"),
+ egress_dpp_policy=dict(type="str"),
+ ingress_dpp_policy=dict(type="str"),
+ qos_priority=dict(type="str", choices=["level1", "level2", "level3", "level4", "level5", "level6", "unspecified"], aliases=["priority", "prio"]),
+ qos_custom_policy=dict(type="str", aliases=["qos_custom_policy_name"]),
+ pim_v4_interface_profile=dict(type="dict", options=pim_interface_profile_spec(), aliases=["pim_v4"]),
+ pim_v6_interface_profile=dict(type="dict", options=pim_interface_profile_spec(), aliases=["pim_v6"]),
+ igmp_interface_profile=dict(type="dict", options=igmp_interface_profile_spec(), aliases=["igmp"]),
state=dict(type="str", default="present", choices=["absent", "present", "query"]),
description=dict(type="str", aliases=["descr"]),
)
@@ -268,11 +343,19 @@ def main():
nd_policy = module.params.get("nd_policy")
egress_dpp_policy = module.params.get("egress_dpp_policy")
ingress_dpp_policy = module.params.get("ingress_dpp_policy")
+ qos_priority = module.params.get("qos_priority")
+ qos_custom_policy = module.params.get("qos_custom_policy")
description = module.params.get("description")
state = module.params.get("state")
aci = ACIModule(module)
+ extra_child_classes = dict(
+ pimIPV6IfP=dict(rs_class="pimRsV6IfPol", attribute_input=module.params.get("pim_v6_interface_profile")),
+ pimIfP=dict(rs_class="pimRsIfPol", attribute_input=module.params.get("pim_v4_interface_profile")),
+ igmpIfP=dict(rs_class="igmpRsIfPol", attribute_input=module.params.get("igmp_interface_profile")),
+ )
+
aci.construct_url(
root_class=dict(
aci_class="fvTenant",
@@ -294,11 +377,11 @@ def main():
),
subclass_3=dict(
aci_class="l3extLIfP",
- aci_rn="lifp-[{0}]".format(interface_profile),
+ aci_rn="lifp-{0}".format(interface_profile),
module_object=interface_profile,
target_filter={"name": interface_profile},
),
- child_classes=["l3extRsNdIfPol", "l3extRsIngressQosDppPol", "l3extRsEgressQosDppPol"],
+ child_classes=list(extra_child_classes.keys()) + ["l3extRsEgressQosDppPol", "l3extRsIngressQosDppPol", "l3extRsLIfPCustQosPol", "l3extRsNdIfPol"],
)
aci.get_existing()
@@ -308,8 +391,67 @@ def main():
dict(l3extRsNdIfPol=dict(attributes=dict(tnNdIfPolName=nd_policy))),
dict(l3extRsIngressQosDppPol=dict(attributes=dict(tnQosDppPolName=ingress_dpp_policy))),
dict(l3extRsEgressQosDppPol=dict(attributes=dict(tnQosDppPolName=egress_dpp_policy))),
+ dict(l3extRsLIfPCustQosPol=dict(attributes=dict(tnQosCustomPolName=qos_custom_policy))),
]
- aci.payload(aci_class="l3extLIfP", class_config=dict(name=interface_profile, descr=description), child_configs=child_configs)
+ for class_name, attribute in extra_child_classes.items():
+ attribute_input = attribute.get("attribute_input")
+ if attribute_input is not None:
+ rs_class = attribute.get("rs_class")
+ if all(value is None for value in attribute_input.values()) and isinstance(aci.existing, list) and len(aci.existing) > 0:
+ for child in aci.existing[0].get("l3extLIfP", {}).get("children", {}):
+ if child.get(class_name):
+ child_configs.append(
+ {
+ class_name: dict(
+ attributes=dict(status="deleted"),
+ ),
+ }
+ )
+ elif all(value is not None for value in attribute_input.values()):
+ if rs_class in ["pimRsV6IfPol", "pimRsIfPol"]:
+ child_configs.append(
+ {
+ class_name: dict(
+ attributes={},
+ children=[
+ {
+ rs_class: dict(
+ attributes=dict(
+ tDn="uni/tn-{0}/pimifpol-{1}".format(attribute_input.get("tenant"), attribute_input.get("pim"))
+ )
+ )
+ },
+ ],
+ )
+ }
+ )
+ elif rs_class == "igmpRsIfPol":
+ child_configs.append(
+ {
+ class_name: dict(
+ attributes={},
+ children=[
+ {
+ rs_class: dict(
+ attributes=dict(
+ tDn="uni/tn-{0}/igmpIfPol-{1}".format(attribute_input.get("tenant"), attribute_input.get("igmp"))
+ )
+ )
+ },
+ ],
+ )
+ }
+ )
+
+ aci.payload(
+ aci_class="l3extLIfP",
+ class_config=dict(
+ name=interface_profile,
+ prio=qos_priority,
+ descr=description,
+ ),
+ child_configs=child_configs,
+ )
aci.get_diff(aci_class="l3extLIfP")
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_logical_interface_profile_ospf_policy.py b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_logical_interface_profile_ospf_policy.py
index 798a82111..2d1a407ae 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_logical_interface_profile_ospf_policy.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_logical_interface_profile_ospf_policy.py
@@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2022, Jason Juenger (@jasonjuenger) <jasonjuenger@gmail.com>
+# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@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
@@ -13,9 +14,9 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_l3out_logical_interface_profile_ospf_policy
-short_description: Manage Layer 3 Outside (L3Out) logical interface profile (l3ext:LIfP) OSPF policy (ospfIfP)
+short_description: Manage Layer 3 Outside (L3Out) OSPF interface profile (ospf:IfP)
description:
-- Manage L3Out interface profile OSPF policies on Cisco ACI fabrics.
+- Manage L3Out logical interface profile OSPF policies on Cisco ACI fabrics.
options:
tenant:
description:
@@ -64,14 +65,22 @@ extends_documentation_fragment:
- cisco.aci.annotation
- cisco.aci.owner
+notes:
+- The C(tenant), C(l3out), C(node_profile), C(interface_profile) and C(ospf_policy) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant), M(cisco.aci.aci_l3out), M(cisco.aci.aci_l3out_logical_node_profile), M(cisco.aci.aci_l3out_logical_interface_profile)
+ and (cisco.aci.aci_interface_policy_ospf) can be used for this.
seealso:
-- module: aci_l3out
-- module: aci_l3out_logical_node_profile
+- module: cisco.aci.aci_tenant
+- module: cisco.aci.aci_l3out
+- module: cisco.aci.aci_l3out_logical_node_profile
+- module: cisco.aci.aci_l3out_logical_interface_profile
+- module: cisco.aci.aci_interface_policy_ospf
- name: APIC Management Information Model reference
- description: More information about the internal APIC classes
+ description: More information about the internal APIC class B(ospf:IfP).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Jason Juenger (@jasonjuenger)
+- Gaspard Micol (@gmicol)
"""
EXAMPLES = r"""
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_logical_interface_vpc_member.py b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_logical_interface_vpc_member.py
index 4ddd32161..822c53af7 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_logical_interface_vpc_member.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_logical_interface_vpc_member.py
@@ -94,7 +94,7 @@ notes:
seealso:
- module: cisco.aci.aci_l3out_logical_interface_profile
- name: APIC Management Information Model reference
- description: More information about the internal APIC class B(l3ext:Out).
+ description: More information about the internal APIC class B(l3ext:Member).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Anvitha Jain (@anvitha-jain)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_logical_node.py b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_logical_node.py
index 33c8a22a5..7ab756566 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_logical_node.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_logical_node.py
@@ -1,6 +1,8 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+# Copyright: (c) 2021, Marcel Zehnder (@maercu)
+# Copyright: (c) 2023, Akini Ross (@akinross) <akinross@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
@@ -52,9 +54,20 @@ options:
loopback_address:
description:
- The loopback IP address.
+ - The BGP-EVPN loopback IP address for Infra SR-MPLS L3Outs.
- A configured loopback address can be removed by passing an empty string (see Examples).
type: str
aliases: [ loopback ]
+ mpls_transport_loopback_address:
+ description:
+ - The MPLS transport loopback IP address for Infra SR-MPLS L3Outs.
+ type: str
+ aliases: [ mpls_transport_loopback ]
+ sid:
+ description:
+ - The Segment ID (SID) Index for Infra SR-MPLS L3Outs.
+ type: str
+ aliases: [ segment_id ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
@@ -70,10 +83,11 @@ seealso:
- module: aci_l3out
- module: aci_l3out_logical_node_profile
- name: APIC Management Information Model reference
- description: More information about the internal APIC classes B(vmm:DomP)
+ description: More information about the internal APIC classes B(l3ext:RsNodeL3OutAtt)
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Marcel Zehnder (@maercu)
+- Akini Ross (@akinross)
"""
EXAMPLES = r"""
@@ -92,6 +106,22 @@ EXAMPLES = r"""
state: present
delegate_to: localhost
+- name: Add a node to a infra SR-MPLS l3out node profile
+ cisco.aci.aci_l3out_logical_node: &aci_infra_node_profile_node
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: infra
+ l3out: ansible_infra_sr_mpls_l3out
+ node_profile: ansible_infra_sr_mpls_l3out_node_profile
+ pod_id: 1
+ node_id: 113
+ router_id_as_loopback: no
+ loopback_address: 50.0.0.1
+ mpls_transport_loopback_address: 51.0.0.1
+ sid: 500
+ delegate_to: localhost
+
- name: Remove a loopback address from a node in node profile
cisco.aci.aci_l3out_logical_node:
host: apic
@@ -264,6 +294,8 @@ def main():
router_id=dict(type="str"),
router_id_as_loopback=dict(type="str", default="yes", choices=["yes", "no"]),
loopback_address=dict(type="str", aliases=["loopback"]),
+ mpls_transport_loopback_address=dict(type="str", aliases=["mpls_transport_loopback"]),
+ sid=dict(type="str", aliases=["segment_id"]),
state=dict(type="str", default="present", choices=["absent", "present", "query"]),
)
@@ -274,6 +306,8 @@ def main():
["state", "absent", ["tenant", "l3out", "node_profile", "pod_id", "node_id"]],
["state", "present", ["tenant", "l3out", "node_profile", "pod_id", "node_id"]],
],
+ required_by={"mpls_transport_loopback_address": "loopback_address"},
+ required_together=[("mpls_transport_loopback_address", "sid")],
)
tenant = module.params.get("tenant")
@@ -284,6 +318,8 @@ 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")
+ mpls_transport_loopback_address = module.params.get("mpls_transport_loopback_address")
+ sid = module.params.get("sid")
state = module.params.get("state")
tdn = None
@@ -294,6 +330,9 @@ def main():
child_classes = ["l3extLoopBackIfP"]
+ if mpls_transport_loopback_address is not None:
+ child_classes.append("mplsNodeSidP")
+
child_configs = []
aci.construct_url(
@@ -333,7 +372,12 @@ def main():
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))))
+ loopback_address_config = dict(l3extLoopBackIfP=dict(attributes=dict(addr=loopback_address), children=[]))
+ if mpls_transport_loopback_address:
+ loopback_address_config["l3extLoopBackIfP"]["children"].append(
+ dict(mplsNodeSidP=dict(attributes=dict(loopbackAddr=mpls_transport_loopback_address, sidoffset=sid)))
+ )
+ child_configs.append(loopback_address_config)
aci.payload(
aci_class="l3extRsNodeL3OutAtt",
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_logical_node_profile.py b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_logical_node_profile.py
index 10eefd018..ac6b87ebe 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_logical_node_profile.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_logical_node_profile.py
@@ -1,6 +1,7 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+# Copyright: (c) 2023, Akini Ross (@akinross) <akinross@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
@@ -43,6 +44,12 @@ options:
type: str
choices: [ AF11, AF12, AF13, AF21, AF22, AF23, AF31, AF32, AF33, AF41, AF42, AF43, CS0, CS1, CS2, CS3, CS4, CS5, CS6, CS7, EF, VA, unspecified ]
aliases: [ target_dscp ]
+ mpls_custom_qos_policy:
+ description:
+ - The MPLS custom QoS policy name for the node profile.
+ - This argument should only be used for Infra SR-MPLS L3Outs.
+ aliases: [ mpls_custom_qos_policy_name ]
+ type: str
state:
description:
- Use C(present) or C(absent) for adding or removing.
@@ -62,10 +69,11 @@ extends_documentation_fragment:
seealso:
- module: aci_l3out
- name: APIC Management Information Model reference
- description: More information about the internal APIC classes B(vmm:DomP)
+ description: More information about the internal APIC classes B(l3ext:LNodeP).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Jason Juenger (@jasonjuenger)
+- Akini Ross (@akinross)
"""
EXAMPLES = r"""
@@ -82,6 +90,18 @@ EXAMPLES = r"""
state: present
delegate_to: localhost
+- name: Add a new node profile with MPLS custom QOS policy to SR-MPLS infra l3out
+ cisco.aci.aci_l3out_logical_node_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: infra
+ l3out: infra_sr_mpls_l3out
+ node_profile: infra_sr_mpls_l3out_node_profile
+ mpls_custom_qos_policy: infra_mpls_custom_qos_policy
+ state: present
+ delegate_to: localhost
+
- name: Delete a node profile
cisco.aci.aci_l3out_logical_node_profile:
host: apic
@@ -264,6 +284,8 @@ def main():
],
aliases=["target_dscp"],
),
+ # alias=dict(type="str"), not implemented because of different (api/alias/mo/uni/) api endpoint
+ mpls_custom_qos_policy=dict(type="str", aliases=["mpls_custom_qos_policy_name"]),
state=dict(type="str", default="present", choices=["absent", "present", "query"]),
name_alias=dict(type="str"),
)
@@ -282,11 +304,16 @@ def main():
l3out = module.params.get("l3out")
description = module.params.get("description")
dscp = module.params.get("dscp")
+ mpls_custom_qos_policy = module.params.get("mpls_custom_qos_policy")
state = module.params.get("state")
name_alias = module.params.get("name_alias")
aci = ACIModule(module)
+ child_classes = []
+ if mpls_custom_qos_policy is not None:
+ child_classes.append("l3extRsLNodePMplsCustQosPol")
+
aci.construct_url(
root_class=dict(
aci_class="fvTenant",
@@ -306,11 +333,21 @@ def main():
module_object=node_profile,
target_filter={"name": node_profile},
),
+ child_classes=child_classes,
)
aci.get_existing()
if state == "present":
+ child_configs = []
+ if mpls_custom_qos_policy is not None:
+ if mpls_custom_qos_policy == "":
+ child_configs.append(dict(l3extRsLNodePMplsCustQosPol=dict(attributes=dict(status="deleted"))))
+ else:
+ child_configs.append(
+ dict(l3extRsLNodePMplsCustQosPol=dict(attributes=dict(tDn="uni/tn-infra/qosmplscustom-{0}".format(mpls_custom_qos_policy))))
+ )
+
aci.payload(
aci_class="l3extLNodeP",
class_config=dict(
@@ -319,6 +356,7 @@ def main():
targetDscp=dscp,
nameAlias=name_alias,
),
+ child_configs=child_configs,
)
aci.get_diff(aci_class="l3extLNodeP")
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_static_routes.py b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_static_routes.py
index 039593366..a8c410bb5 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_static_routes.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_static_routes.py
@@ -15,7 +15,7 @@ DOCUMENTATION = r"""
module: aci_l3out_static_routes
short_description: Manage Static routes object (l3ext:ipRouteP)
description:
-- Manage External Subnet objects (l3ext:ipRouteP)
+- Manage External Subnet objects.
options:
description:
description:
@@ -86,7 +86,7 @@ seealso:
- module: cisco.aci.aci_tenant
- module: cisco.aci.aci_l3out
- name: APIC Management Information Model reference
- description: More information about the internal APIC class B(l3ext:Out).
+ description: More information about the internal APIC class B(l3ext:ipRouteP).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Anvitha Jain(@anvitha-jain)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_static_routes_nexthop.py b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_static_routes_nexthop.py
index 36c3afa36..b475bba5c 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_static_routes_nexthop.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_static_routes_nexthop.py
@@ -65,7 +65,7 @@ seealso:
- module: aci_l3out_logical_node_profile_to_node
- module: aci_l3out_static_routes
- name: APIC Management Information Model reference
- description: More information about the internal APIC classes B(vmm:DomP)
+ description: More information about the internal APIC classes B(ip:NexthopP)
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Marcel Zehnder (@maercu)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_l3out_to_sr_mpls_infra_l3out.py b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_to_sr_mpls_infra_l3out.py
new file mode 100644
index 000000000..db621d5c8
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_l3out_to_sr_mpls_infra_l3out.py
@@ -0,0 +1,355 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Akini Ross (@akinross) <akinross@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": "certified",
+}
+
+DOCUMENTATION = r"""
+---
+module: aci_l3out_to_sr_mpls_infra_l3out
+short_description: Manage Layer 3 Outside (L3Out) to SR-MPLS Infra L3Outs objects (l3ext:ConsLbl)
+description:
+- Manage Layer 3 Outside (L3Out) to SR-MPLS Infra L3Outs objects on Cisco ACI fabrics.
+options:
+ tenant:
+ description:
+ - The name of an existing tenant.
+ type: str
+ aliases: [ tenant_name ]
+ l3out:
+ description:
+ - The name of an existing SR MPLS VRF L3Out.
+ type: str
+ aliases: [ l3out_name, name ]
+ infra_l3out:
+ description:
+ - The name of an existing SR-MPLS Infra L3Out.
+ type: str
+ aliases: [ infra_l3out_name ]
+ external_epg:
+ description:
+ - The distinguished name (DN) of the external EPG.
+ type: str
+ aliases: [ external_epg_dn ]
+ outbound_route_map:
+ description:
+ - The distinguished name (DN) of the outbound route map.
+ type: str
+ aliases: [ outbound_route_map_dn, outbound ]
+ inbound_route_map:
+ description:
+ - The distinguished name (DN) of the inbound route map.
+ - Use an empty string to remove the inbound route map.
+ type: str
+ aliases: [ inbound_route_map_dn, inbound ]
+ description:
+ description:
+ - Description for the L3Out.
+ 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) and C(l3out) used must exist before using this module in your playbook.
+- The M(cisco.aci.aci_tenant) and M(cisco.aci.aci_l3out) modules can be used for this.
+seealso:
+- module: cisco.aci.aci_tenant
+- module: cisco.aci.aci_l3out
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(l3ext:ConsLbl).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Akini Ross (@akinross)
+"""
+
+EXAMPLES = r"""
+- name: Add a new l3out to sr-mpls infra l3out
+ cisco.aci.aci_l3out_to_sr_mpls_infra_l3out:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: production
+ l3out: prod_l3out
+ description: L3Out for Production tenant
+ infra_l3out: infra_l3out_name
+ external_epg: uni/tn-production/out-l3out_name/instP-external_epg_name
+ outbound_route_map: uni/tn-production/prof-outbound_route_map_name
+ inbound_route_map: uni/tn-production/prof-inbound_route_map_name
+ state: present
+ delegate_to: localhost
+
+- name: Delete a l3out to sr-mpls infra l3out
+ cisco.aci.aci_l3out_to_sr_mpls_infra_l3out:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: production
+ l3out: prod_l3out
+ infra_l3out: infra_l3out_name
+ state: absent
+ delegate_to: localhost
+
+- name: Query a l3out to sr-mpls infra l3out
+ cisco.aci.aci_l3out_to_sr_mpls_infra_l3out:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: production
+ l3out: prod_l3out
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all l3out to sr-mpls infra l3outs
+ cisco.aci.aci_l3out_to_sr_mpls_infra_l3out:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+ register: query_all_result
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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
+ l3out=dict(type="str", aliases=["l3out_name", "name"]), # Not required for querying all objects
+ description=dict(type="str", aliases=["descr"]),
+ infra_l3out=dict(type="str", aliases=["infra_l3out_name"]),
+ external_epg=dict(type="str", aliases=["external_epg_dn"]),
+ outbound_route_map=dict(type="str", aliases=["outbound_route_map_dn", "outbound"]),
+ inbound_route_map=dict(type="str", aliases=["inbound_route_map_dn", "inbound"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ name_alias=dict(type="str"),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["l3out", "tenant", "infra_l3out"]],
+ ["state", "present", ["l3out", "tenant", "infra_l3out", "external_epg", "outbound_route_map"]],
+ ],
+ )
+
+ aci = ACIModule(module)
+
+ tenant = module.params.get("tenant")
+ l3out = module.params.get("l3out")
+ description = module.params.get("description")
+ infra_l3out = module.params.get("infra_l3out")
+ external_epg = module.params.get("external_epg")
+ outbound_route_map = module.params.get("outbound_route_map")
+ inbound_route_map = module.params.get("inbound_route_map")
+ state = module.params.get("state")
+ name_alias = module.params.get("name_alias")
+
+ # l3extRsProvLblDef, bgpDomainIdAllocator are auto-generated classes, added for query output
+ child_classes = ["l3extRsLblToInstP", "l3extRsLblToProfile", "l3extRsProvLblDef", "bgpDomainIdAllocator"]
+
+ 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="l3extOut",
+ aci_rn="out-{0}".format(l3out),
+ module_object=l3out,
+ target_filter={"name": l3out},
+ ),
+ subclass_2=dict(
+ aci_class="l3extConsLbl",
+ aci_rn="conslbl-{0}".format(infra_l3out),
+ module_object=infra_l3out,
+ target_filter={"name": infra_l3out},
+ ),
+ child_classes=child_classes,
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ child_configs = []
+
+ if aci.existing:
+ children = aci.existing[0].get("l3extConsLbl", {}).get("children", [])
+ for child in children:
+ if child.get("l3extRsLblToProfile"):
+ tdn = child.get("l3extRsLblToProfile").get("attributes").get("tDn")
+ direction = child.get("l3extRsLblToProfile").get("attributes").get("direction")
+ route_map = outbound_route_map if direction == "export" else inbound_route_map
+ # Inbound route-map is removed when input is different or an empty string, otherwise ignored.
+ if route_map is not None and tdn != route_map:
+ child_configs.append(dict(l3extRsLblToProfile=dict(attributes=dict(tDn=tdn, direction=direction, status="deleted"))))
+ elif child.get("l3extRsLblToInstP"):
+ tdn = child.get("l3extRsLblToInstP").get("attributes").get("tDn")
+ if tdn != external_epg:
+ child_configs.append(dict(l3extRsLblToInstP=dict(attributes=dict(tDn=tdn, status="deleted"))))
+
+ child_configs.append(dict(l3extRsLblToProfile=dict(attributes=dict(tDn=outbound_route_map, direction="export"))))
+ child_configs.append(dict(l3extRsLblToInstP=dict(attributes=dict(tDn=external_epg))))
+
+ if inbound_route_map:
+ child_configs.append(dict(l3extRsLblToProfile=dict(attributes=dict(tDn=inbound_route_map, direction="import"))))
+
+ aci.payload(
+ aci_class="l3extConsLbl",
+ class_config=dict(
+ name=infra_l3out,
+ descr=description,
+ nameAlias=name_alias,
+ ),
+ child_configs=child_configs,
+ )
+
+ aci.get_diff(aci_class="l3extConsLbl")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_maintenance_group_node.py b/ansible_collections/cisco/aci/plugins/modules/aci_maintenance_group_node.py
index be97ede40..30fb14403 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_maintenance_group_node.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_maintenance_group_node.py
@@ -15,7 +15,7 @@ DOCUMENTATION = r"""
module: aci_maintenance_group_node
short_description: Manage maintenance group nodes (fabric:NodeBlk)
description:
-- Manage maintenance group nodes
+- Manage maintenance group nodes.
options:
group:
description:
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_match_route_destination.py b/ansible_collections/cisco/aci/plugins/modules/aci_match_route_destination.py
index 973d70561..1ba471c9d 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_match_route_destination.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_match_route_destination.py
@@ -14,7 +14,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_match_route_destination
-short_description: Manage Match action rule term based on the Route Destination. (rtctrl:MatchRtDest)
+short_description: Manage Match action rule term based on the Route Destination (rtctrl:MatchRtDest)
description:
- Match action rule terms based on the Route Destination for Subject Profiles on Cisco ACI fabrics.
options:
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_netflow_exporter_policy.py b/ansible_collections/cisco/aci/plugins/modules/aci_netflow_exporter_policy.py
new file mode 100644
index 000000000..e45eb6217
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_netflow_exporter_policy.py
@@ -0,0 +1,490 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@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_netflow_exporter_policy
+short_description: Manage Netflow Exporter Policy (netflow:ExporterPol)
+description:
+- Manage Netflow Exporter Policies for tenants on Cisco ACI fabrics.
+- Exporter information for bootstrapping the netflow Collection agent.
+options:
+ tenant:
+ description:
+ - The name of an existing tenant.
+ type: str
+ aliases: [ tenant_name ]
+ netflow_exporter_policy:
+ description:
+ - The name of the Netflow Exporter Policy.
+ type: str
+ aliases: [ netflow_exporter, netflow_exporter_name, name ]
+ dscp:
+ description:
+ - The IP DSCP value.
+ - The APIC defaults to C(CS2) when unset during creation.
+ It defaults to C(VA) for APIC versions 4.2 or prior.
+ type: str
+ choices: [ AF11, AF12, AF13, AF21, AF22, AF23, AF31, AF32, AF33, AF41, AF42, AF43, CS0, CS1, CS2, CS3, CS4, CS5, CS6, CS7, EF, VA, unspecified ]
+ destination_address:
+ description:
+ - The remote node destination IP address.
+ type: str
+ destination_port:
+ description:
+ - The remote node destination port.
+ - Accepted values are any valid TCP/UDP port range.
+ - The APIC defaults to C(unspecified) when unset during creation.
+ type: str
+ source_ip_type:
+ description:
+ - The type of Exporter source IP Address.
+ - It can be one of the available management IP Address for a given leaf or a custom IP Address.
+ type: str
+ choices: [ custom_source_ip, inband_management_ip, out_of_band_management_ip, ptep ]
+ custom_source_address:
+ description:
+ - The custom source IP address.
+ - It can only be used if O(source_ip_type=custom_source_ip).
+ type: str
+ associated_epg:
+ description:
+ - The associated EPG.
+ - To remove the current associated EPG, pass an empty dictionary.
+ type: dict
+ aliases: [ epg ]
+ suboptions:
+ tenant:
+ description:
+ - The name of the tenant to which the associated AP/EPG belong.
+ type: str
+ ap:
+ description:
+ - The name of the associated Application Profile to which the associated EPG belongs.
+ type: str
+ epg:
+ description:
+ - The name of the associated EPG.
+ type: str
+ associated_extepg:
+ description:
+ - The associated external EPG.
+ - To remove the current associated external EPG, pass an empty dictionary.
+ type: dict
+ aliases: [ external_epg, associated_external_epg ]
+ suboptions:
+ tenant:
+ description:
+ - The name of the tenant to which the associated L3Out/external EPG belong.
+ type: str
+ l3out:
+ description:
+ - The name of the L3Out to which the associated external EPG belongs.
+ type: str
+ extepg:
+ description:
+ - The name of the associated EPG.
+ type: str
+ associated_vrf:
+ description:
+ - The associated VRF.
+ - To remove the current associated VRF, pass an empty dictionary.
+ type: dict
+ aliases: [ vrf, context, associated_context ]
+ suboptions:
+ tenant:
+ description:
+ - The name of the tenant to which the associated VRF belongs.
+ type: str
+ vrf:
+ description:
+ - The name of the associated VRF.
+ type: str
+ description:
+ description:
+ - The description for the Netflow Exporter Policy.
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+notes:
+- The I(tenant) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant) can be used for this.
+- The I(associated_epg) and I(associated_extepg) are mutually exclusive.
+- If the I(associated_epg) is used, the I(epg), the(tenant) and
+ the I(ap) must exist before using this module in your play book.
+ The M(cisco.aci.aci_epg) and the M(cisco.aci.aci_ap) can be used for this.
+- If the I(associated_extepg) is used, the I(extepg), the(tenant) and
+ the I(l3out) must exist before using this module in your play book.
+ The M(cisco.aci.aci_l3out_extepg) and the M(cisco.aci.aci_l3out) can be used for this.
+- If the I(associated_vrf) is used, the I(vrf) and the I(tenant) must exist
+ before using this module in your play book.
+ The M(cisco.aci.aci_vrf) can be used for this.
+seealso:
+- module: cisco.aci.aci_tenant
+- module: cisco.aci.aci_vrf
+- module: cisco.aci.aci_ap
+- module: cisco.aci.aci_epg
+- module: cisco.aci.aci_l3out
+- module: cisco.aci.aci_l3out_extepg
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(netflow:ExporterPol).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Gaspard Micol (@gmicol)
+"""
+
+EXAMPLES = r"""
+- name: Add a new Netflow Exporter Policy
+ cisco.aci.aci_netflow_exporter_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ netflow_exporter_policy: my_netflow_exporter_policy
+ dscp: CS2
+ destination_address: 11.11.11.1
+ destination_port: 25
+ source_ip_type: custom_source_ip
+ custom_source_address: 11.11.11.2
+ associated_epg:
+ tenant: my_tenant
+ ap: my_ap
+ epg: my_epg
+ associated_vrf:
+ tenant: my_tenant
+ vrf: my_vrf
+ state: present
+ delegate_to: localhost
+
+- name: Remove associated EPG and VRF from the new Netflow Exporter Policy
+ cisco.aci.aci_netflow_exporter_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ netflow_exporter_policy: my_netflow_exporter_policy
+ associated_epg: {}
+ associated_vrf: {}
+ delegate_to: localhost
+
+- name: Query a Netflow Exporter Policy
+ cisco.aci.aci_netflow_exporter_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ netflow_exporter_policy: my_netflow_exporter_policy
+ state: query
+ delegate_to: localhost
+
+- name: Query all Netflow Exporter Policies in my_tenant
+ cisco.aci.aci_netflow_exporter_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ state: query
+ delegate_to: localhost
+
+- name: Query all Netflow Exporter Policies
+ cisco.aci.aci_netflow_exporter_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+
+- name: Delete a Netflow Exporter Policy
+ cisco.aci.aci_netflow_exporter_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ netflow_exporter_policy: my_netflow_exporter_policy
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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,
+ aci_contract_dscp_spec,
+ associated_netflow_exporter_epg_spec,
+ associated_netflow_exporter_extepg_spec,
+ associated_netflow_exporter_vrf_spec,
+)
+from ansible_collections.cisco.aci.plugins.module_utils.constants import MATCH_SOURCE_IP_TYPE_NETFLOW_EXPORTER_MAPPING
+
+
+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"]),
+ netflow_exporter_policy=dict(type="str", aliases=["netflow_exporter", "netflow_exporter_name", "name"]),
+ dscp=dict((k, aci_contract_dscp_spec()[k]) for k in aci_contract_dscp_spec() if k != "aliases"),
+ destination_address=dict(type="str"),
+ destination_port=dict(type="str"),
+ source_ip_type=dict(type="str", choices=list(MATCH_SOURCE_IP_TYPE_NETFLOW_EXPORTER_MAPPING.keys())),
+ custom_source_address=dict(type="str"),
+ associated_epg=dict(type="dict", aliases=["epg"], options=associated_netflow_exporter_epg_spec()),
+ associated_extepg=dict(type="dict", aliases=["external_epg", "associated_external_epg"], options=associated_netflow_exporter_extepg_spec()),
+ associated_vrf=dict(type="dict", aliases=["vrf", "associated_context", "context"], options=associated_netflow_exporter_vrf_spec()),
+ description=dict(type="str", aliases=["descr"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["tenant", "netflow_exporter_policy"]],
+ ["state", "present", ["tenant", "netflow_exporter_policy", "destination_address", "destination_port"]],
+ ],
+ mutually_exclusive=[["associated_epg", "associated_extepg"]],
+ )
+
+ tenant = module.params.get("tenant")
+ description = module.params.get("description")
+ netflow_exporter_policy = module.params.get("netflow_exporter_policy")
+ dscp = module.params.get("dscp")
+ destination_address = module.params.get("destination_address")
+ destination_port = module.params.get("destination_port")
+ source_ip_type = MATCH_SOURCE_IP_TYPE_NETFLOW_EXPORTER_MAPPING.get(module.params.get("source_ip_type"))
+ custom_source_address = module.params.get("custom_source_address")
+ associated_epg = module.params.get("associated_epg")
+ associated_extepg = module.params.get("associated_extepg")
+ associated_vrf = module.params.get("associated_vrf")
+ state = module.params.get("state")
+
+ aci = ACIModule(module)
+
+ child_classes = ["netflowRsExporterToCtx", "netflowRsExporterToEPg"]
+
+ 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="netflowExporterPol",
+ aci_rn="exporterpol-{0}".format(netflow_exporter_policy),
+ module_object=netflow_exporter_policy,
+ target_filter={"name": netflow_exporter_policy},
+ ),
+ child_classes=child_classes,
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ child_configs = []
+ if associated_vrf is not None:
+ if all(value is None for value in associated_vrf.values()) and isinstance(aci.existing, list) and len(aci.existing) > 0:
+ for child in aci.existing[0].get("netflowExporterPol", {}).get("children", {}):
+ if child.get("netflowRsExporterToCtx"):
+ child_configs.extend([dict(netflowRsExporterToCtx=dict(attributes=dict(status="deleted")))])
+ elif all(value is not None for value in associated_vrf.values()):
+ child_configs.extend(
+ [
+ dict(
+ netflowRsExporterToCtx=dict(
+ attributes=dict(tDn="uni/tn-{0}/ctx-{1}".format(associated_vrf.get("tenant"), associated_vrf.get("vrf")))
+ )
+ ),
+ ]
+ )
+ if associated_epg is not None:
+ if all(value is None for value in associated_epg.values()) and isinstance(aci.existing, list) and len(aci.existing) > 0:
+ for child in aci.existing[0].get("netflowExporterPol", {}).get("children", {}):
+ if child.get("netflowRsExporterToEPg"):
+ child_configs.extend([dict(netflowRsExporterToEPg=dict(attributes=dict(status="deleted")))])
+ elif all(value is not None for value in associated_epg.values()):
+ child_configs.extend(
+ [
+ dict(
+ netflowRsExporterToEPg=dict(
+ attributes=dict(
+ tDn="uni/tn-{0}/ap-{1}/epg-{2}".format(associated_epg.get("tenant"), associated_epg.get("ap"), associated_epg.get("epg"))
+ )
+ )
+ ),
+ ]
+ )
+ elif associated_extepg is not None:
+ if all(value is None for value in associated_extepg.values()) and isinstance(aci.existing, list) and len(aci.existing) > 0:
+ for child in aci.existing[0].get("netflowExporterPol", {}).get("children", {}):
+ if child.get("netflowRsExporterToEPg"):
+ child_configs.extend([dict(netflowRsExporterToEPg=dict(attributes=dict(status="deleted")))])
+ elif all(value is not None for value in associated_extepg.values()):
+ child_configs.extend(
+ [
+ dict(
+ netflowRsExporterToEPg=dict(
+ attributes=dict(
+ tDn="uni/tn-{0}/out-{1}/instP-{2}".format(
+ associated_extepg.get("tenant"), associated_extepg.get("l3out"), associated_extepg.get("extepg")
+ )
+ )
+ )
+ ),
+ ]
+ )
+ aci.payload(
+ aci_class="netflowExporterPol",
+ class_config=dict(
+ name=netflow_exporter_policy,
+ descr=description,
+ dscp=dscp,
+ dstAddr=destination_address,
+ dstPort=destination_port,
+ sourceIpType=source_ip_type,
+ srcAddr=custom_source_address,
+ ),
+ child_configs=child_configs,
+ )
+
+ aci.get_diff(aci_class="netflowExporterPol")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_netflow_monitor_policy.py b/ansible_collections/cisco/aci/plugins/modules/aci_netflow_monitor_policy.py
new file mode 100644
index 000000000..462187609
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_netflow_monitor_policy.py
@@ -0,0 +1,300 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@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_netflow_monitor_policy
+short_description: Manage Netflow Monitor Policy (netflow:MonitorPol)
+description:
+- Manage Netflow Monitor Policies for tenants on Cisco ACI fabrics.
+options:
+ tenant:
+ description:
+ - The name of an existing tenant.
+ type: str
+ aliases: [ tenant_name ]
+ netflow_monitor_policy:
+ description:
+ - The name of the Netflow Monitor Policy.
+ type: str
+ aliases: [ netflow_monitor, netflow_monitor_name, name ]
+ netflow_record_policy:
+ description:
+ - The name of the Netflow Record Policy.
+ - To remove the current Netflow Record Policy, pass an empty string.
+ type: str
+ aliases: [ netflow_record, netflow_record_name ]
+ description:
+ description:
+ - The description for the Netflow Monitor Policy.
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+notes:
+- The I(tenant) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant) can be used for this.
+- If the I(netflow_record_policy) is used, it must exist before using this module in your playbook.
+ The M(cisco.aci.aci_netflow_record_policy) can be used for this.
+seealso:
+- module: cisco.aci.aci_tenant
+- module: cisco.aci.aci_netflow_record_policy
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(netflow:MonitorPol).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Gaspard Micol (@gmicol)
+"""
+
+EXAMPLES = r"""
+- name: Add a new Netflow Monitor Policy
+ cisco.aci.aci_netflow_monitor_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ netflow_monitor_policy: my_netflow_monitor_policy
+ netflow_record_policy: my_netflow_record_policy
+ state: present
+ delegate_to: localhost
+
+- name: Query a Netflow Monitor Policy
+ cisco.aci.aci_netflow_monitor_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ netflow_monitor_policy: my_netflow_monitor_policy
+ state: query
+ delegate_to: localhost
+
+- name: Query all Netflow Monitor Policies in my_tenant
+ cisco.aci.aci_netflow_monitor_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ state: query
+ delegate_to: localhost
+
+- name: Query all Netflow Monitor Policies
+ cisco.aci.aci_netflow_monitor_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+
+- name: Delete a Netflow Monitor Policy
+ cisco.aci.aci_netflow_monitor_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ netflow_monitor_policy: my_netflow_monitor_policy
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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"]),
+ netflow_monitor_policy=dict(type="str", aliases=["netflow_monitor", "netflow_monitor_name", "name"]),
+ netflow_record_policy=dict(type="str", aliases=["netflow_record", "netflow_record_name"]),
+ description=dict(type="str", aliases=["descr"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["tenant", "netflow_monitor_policy"]],
+ ["state", "present", ["tenant", "netflow_monitor_policy"]],
+ ],
+ )
+
+ tenant = module.params.get("tenant")
+ description = module.params.get("description")
+ netflow_monitor_policy = module.params.get("netflow_monitor_policy")
+ netflow_record_policy = module.params.get("netflow_record_policy")
+ state = module.params.get("state")
+
+ aci = ACIModule(module)
+
+ child_classes = ["netflowRsMonitorToRecord"]
+
+ 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="netflowMonitorPol",
+ aci_rn="monitorpol-{0}".format(netflow_monitor_policy),
+ module_object=netflow_monitor_policy,
+ target_filter={"name": netflow_monitor_policy},
+ ),
+ child_classes=child_classes,
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ child_configs = []
+ child_configs.append(dict(netflowRsMonitorToRecord=dict(attributes=dict(tnNetflowRecordPolName=netflow_record_policy))))
+ aci.payload(
+ aci_class="netflowMonitorPol",
+ class_config=dict(
+ name=netflow_monitor_policy,
+ descr=description,
+ ),
+ child_configs=child_configs,
+ )
+
+ aci.get_diff(aci_class="netflowMonitorPol")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_netflow_monitor_to_exporter.py b/ansible_collections/cisco/aci/plugins/modules/aci_netflow_monitor_to_exporter.py
new file mode 100644
index 000000000..50e2f2524
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_netflow_monitor_to_exporter.py
@@ -0,0 +1,290 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@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_netflow_monitor_to_exporter
+short_description: Manage Netflow Monitor to Exporter (netflow:RsMonitorToExporter)
+description:
+- Link Netflow Exporter policies to Netflow Monitor policies for tenants on Cisco ACI fabrics.
+options:
+ tenant:
+ description:
+ - The name of an existing tenant.
+ type: str
+ aliases: [ tenant_name ]
+ netflow_monitor_policy:
+ description:
+ - The name of the Netflow Monitor Policy.
+ type: str
+ aliases: [ netflow_monitor, netflow_monitor_name, name ]
+ netflow_exporter_policy:
+ description:
+ - The name of the Netflow Exporter Policy.
+ type: str
+ aliases: [ netflow_exporter, netflow_exporter_name ]
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+notes:
+- The I(tenant), I(netflow_monitor_policy) and I(netflow_exporter_policy) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant), M(cisco.aci.aci_netflow_monitor_policy), M(cisco.aci.aci_netflow_exporter_policy) can be used for this.
+seealso:
+- module: cisco.aci.aci_tenant
+- module: cisco.aci.aci_netflow_monitor_policy
+- module: cisco.aci.aci_netflow_exporter_policy
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(netflow:RsMonitorToExporter).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Gaspard Micol (@gmicol)
+"""
+
+EXAMPLES = r"""
+- name: Add a new Netflow Monitor Policy
+ cisco.aci.aci_netflow_monitor_to_exporter:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ netflow_monitor_policy: my_netflow_monitor_policy
+ netflow_exporter_policy: my_netflow_exporter_policy
+ state: present
+ delegate_to: localhost
+
+- name: Query a Netflow Monitor Policy
+ cisco.aci.aci_netflow_monitor_to_exporter:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ netflow_monitor_policy: my_netflow_monitor_policy
+ netflow_exporter_policy: my_netflow_exporter_policy
+ state: query
+ delegate_to: localhost
+
+- name: Query all Netflow Monitor Policies in my_tenant
+ cisco.aci.aci_netflow_monitor_to_exporter:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ state: query
+ delegate_to: localhost
+
+- name: Query all Netflow Monitor Policies
+ cisco.aci.aci_netflow_monitor_to_exporter:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+
+- name: Delete a Netflow Monitor Policy
+ cisco.aci.aci_netflow_monitor_to_exporter:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ netflow_monitor_policy: my_netflow_monitor_policy
+ netflow_exporter_policy: my_netflow_exporter_policy
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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"]),
+ netflow_monitor_policy=dict(type="str", aliases=["netflow_monitor", "netflow_monitor_name", "name"]),
+ netflow_exporter_policy=dict(type="str", aliases=["netflow_exporter", "netflow_exporter_name"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["tenant", "netflow_monitor_policy", "netflow_exporter_policy"]],
+ ["state", "present", ["tenant", "netflow_monitor_policy", "netflow_exporter_policy"]],
+ ],
+ )
+
+ tenant = module.params.get("tenant")
+ netflow_monitor_policy = module.params.get("netflow_monitor_policy")
+ netflow_exporter_policy = module.params.get("netflow_exporter_policy")
+ state = module.params.get("state")
+
+ 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="netflowMonitorPol",
+ aci_rn="monitorpol-{0}".format(netflow_monitor_policy),
+ module_object=netflow_monitor_policy,
+ target_filter={"name": netflow_monitor_policy},
+ ),
+ subclass_2=dict(
+ aci_class="netflowRsMonitorToExporter",
+ aci_rn="rsmonitorToExporter-{0}".format(netflow_exporter_policy),
+ module_object=netflow_exporter_policy,
+ target_filter={"tnNetflowExporterPolName": netflow_exporter_policy},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class="netflowRsMonitorToExporter",
+ class_config=dict(tnNetflowExporterPolName=netflow_exporter_policy),
+ )
+
+ aci.get_diff(aci_class="netflowRsMonitorToExporter")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_netflow_record_policy.py b/ansible_collections/cisco/aci/plugins/modules/aci_netflow_record_policy.py
new file mode 100644
index 000000000..e2f04af0c
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_netflow_record_policy.py
@@ -0,0 +1,313 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@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_netflow_record_policy
+short_description: Manage Netflow Record Policy (netflow:RecordPol)
+description:
+- Manage Netflow Record Policies for tenants on Cisco ACI fabrics.
+options:
+ tenant:
+ description:
+ - The name of an existing tenant.
+ type: str
+ aliases: [ tenant_name ]
+ netflow_record_policy:
+ description:
+ - The name of the Netflow Record Policy.
+ type: str
+ aliases: [ netflow_record, netflow_record_name, name ]
+ collect:
+ description:
+ - The collect parameters for the flow record.
+ - The APIC defaults to C(source_interface) when unset during creation.
+ type: list
+ elements: str
+ choices: [ bytes_counter, pkts_counter, pkt_disposition, sampler_id, source_interface, tcp_flags, first_pkt_timestamp, recent_pkt_timestamp ]
+ match:
+ description:
+ - The match parameters for the flow record.
+ type: list
+ elements: str
+ choices: [ destination_ipv4_v6, destination_ipv4, destination_ipv6, destination_mac, destination_port, ethertype, ip_protocol, source_ipv4_v6,
+ source_ipv4, source_ipv6, source_mac, source_port, ip_tos, unspecified, vlan ]
+ description:
+ description:
+ - The description for the Netflow Record Policy.
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+notes:
+- The I(tenant) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant) 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(netflow:RecordPol).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Gaspard Micol (@gmicol)
+"""
+
+EXAMPLES = r"""
+- name: Add a new Netflow Record Policy
+ cisco.aci.aci_netflow_record_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ netflow_record_policy: my_netflow_record_policy
+ collect: [pkts_counter, pkt_disposition]
+ match: [destination_ipv4, source_ipv4]
+ state: present
+ delegate_to: localhost
+
+- name: Query a Netflow Record Policy
+ cisco.aci.aci_netflow_record_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ netflow_record_policy: my_netflow_record_policy
+ state: query
+ delegate_to: localhost
+
+- name: Query all Netflow Record Policies in my_tenant
+ cisco.aci.aci_netflow_record_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ state: query
+ delegate_to: localhost
+
+- name: Query all Netflow Record Policies
+ cisco.aci.aci_netflow_record_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+
+- name: Delete a Netflow Record Policy
+ cisco.aci.aci_netflow_record_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ netflow_record_policy: my_netflow_record_policy
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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
+from ansible_collections.cisco.aci.plugins.module_utils.constants import MATCH_COLLECT_NETFLOW_RECORD_MAPPING, MATCH_MATCH_NETFLOW_RECORD_MAPPING
+
+
+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"]),
+ netflow_record_policy=dict(type="str", aliases=["netflow_record", "netflow_record_name", "name"]),
+ collect=dict(type="list", elements="str", choices=list(MATCH_COLLECT_NETFLOW_RECORD_MAPPING.keys())),
+ match=dict(type="list", elements="str", choices=list(MATCH_MATCH_NETFLOW_RECORD_MAPPING.keys())),
+ description=dict(type="str", aliases=["descr"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["tenant", "netflow_record_policy"]],
+ ["state", "present", ["tenant", "netflow_record_policy"]],
+ ],
+ )
+
+ tenant = module.params.get("tenant")
+ description = module.params.get("description")
+ netflow_record_policy = module.params.get("netflow_record_policy")
+ state = module.params.get("state")
+
+ if module.params.get("collect") is not None:
+ collect = ",".join(sorted(MATCH_COLLECT_NETFLOW_RECORD_MAPPING.get(v) for v in module.params.get("collect")))
+ else:
+ collect = None
+
+ if module.params.get("match") is not None:
+ match = ",".join(sorted(MATCH_MATCH_NETFLOW_RECORD_MAPPING.get(v) for v in module.params.get("match")))
+ else:
+ match = None
+
+ 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="netflowRecordPol",
+ aci_rn="recordpol-{0}".format(netflow_record_policy),
+ module_object=netflow_record_policy,
+ target_filter={"name": netflow_record_policy},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class="netflowRecordPol",
+ class_config=dict(
+ name=netflow_record_policy,
+ collect=collect,
+ match=match,
+ descr=description,
+ ),
+ )
+
+ aci.get_diff(aci_class="netflowRecordPol")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_node_block.py b/ansible_collections/cisco/aci/plugins/modules/aci_node_block.py
new file mode 100644
index 000000000..d2f86a275
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_node_block.py
@@ -0,0 +1,390 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2024, Gaspard Micol (@gmicol) <gmicol@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": "certified"}
+
+DOCUMENTATION = r"""
+---
+module: aci_node_block
+short_description: Manage Node Block (infra:NodeBlk)
+description:
+- Manage Node Blocks on Cisco ACI fabrics.
+- A node block is a range of nodes. Each node block begins with the first port and ends with the last port.
+options:
+ switch_profile:
+ description:
+ - The name of the Fabric access policy leaf/spine switch profile.
+ type: str
+ aliases:
+ - leaf_profile_name
+ - leaf_profile
+ - switch_profile_name
+ - spine_switch_profile
+ - spine_switch_profile_name
+ access_port_selector:
+ description:
+ - The name of the Fabric access policy leaf/spine switch port selector.
+ type: str
+ aliases: [ access_port_selector_name, port_selector, port_selector_name ]
+ node_block:
+ description:
+ - The name of the Node Block.
+ type: str
+ aliases: [ node_block_name, name ]
+ description:
+ description:
+ - The description for the Node Block.
+ type: str
+ aliases: [ node_block_description ]
+ from_port:
+ description:
+ - The beginning of the port range block for the Node Block.
+ type: str
+ aliases: [ from, from_port_range ]
+ to_port:
+ description:
+ - The end of the port range block for the Node Block.
+ type: str
+ aliases: [ to, to_port_range ]
+ type_node:
+ description:
+ - The type of Node Block to be created under respective access port.
+ type: str
+ choices: [ leaf, spine ]
+ aliases: [ type ]
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+
+notes:
+- If Adding a port block on an access leaf switch port selector of I(type) C(leaf),
+ The I(switch_profile) and I(access_port_selector) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_switch_policy_leaf_profile) and M(cisco.aci.aci_switch_leaf_selector) modules can be used for this.
+- If Adding a port block on an access switch port selector of C(type) C(spine),
+ The I(switch_profile) and I(access_port_selector) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_access_spine_switch_profile) and M(cisco.aci.aci_access_spine_switch_selector) modules can be used for this.
+seealso:
+- module: cisco.aci.aci_switch_policy_leaf_profile
+- module: cisco.aci.aci_switch_leaf_selector
+- module: cisco.aci.aci_access_spine_switch_profile
+- module: cisco.aci.aci_access_spine_switch_selector
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC classes B(infra:NodeBlk).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Gaspard Micol (@gmicol)
+"""
+
+EXAMPLES = r"""
+- name: Add a new Node Block associated to a switch policy leaf profile selector
+ cisco.aci.aci_node_block:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ switch_profile: my_leaf_switch_profile
+ access_port_selector: my_leaf_switch_selector
+ node_block: my_node_block
+ from_port: 1011
+ to_port: 1011
+ type_node: leaf
+ state: present
+ delegate_to: localhost
+
+- name: Add a new Node Block associated to a switch policy spine profile selector
+ cisco.aci.aci_node_block:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ switch_profile: my_spine_switch_profile
+ access_port_selector: my_spine_switch_selector
+ node_block: my_node_block
+ from_port: 1012
+ to_port: 1012
+ type_node: spine
+ state: present
+ delegate_to: localhost
+
+- name: Query a Node Block associated to a switch policy leaf profile selector
+ cisco.aci.aci_node_block:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ switch_profile: my_leaf_switch_profile
+ access_port_selector: my_leaf_switch_selector
+ node_block: my_node_block
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all Node Blocks under the switch policy leaf profile selector
+ cisco.aci.aci_node_block:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ switch_profile: my_leaf_switch_profile
+ access_port_selector: my_leaf_switch_selector
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all Node Blocks
+ cisco.aci.aci_node_block:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Remove a Node Block associated to a switch policy leaf profile selector
+ cisco.aci.aci_node_block:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ switch_profile: my_leaf_switch_profile
+ access_port_selector: my_leaf_switch_selector
+ node_block: my_node_block
+ type_node: leaf
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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
+
+
+def main():
+ argument_spec = aci_argument_spec()
+ argument_spec.update(aci_annotation_spec())
+ argument_spec.update(
+ switch_profile=dict(
+ type="str",
+ aliases=[
+ "leaf_profile_name",
+ "leaf_profile",
+ "switch_profile_name",
+ "spine_switch_profile",
+ "spine_switch_profile_name",
+ ],
+ ), # Not required for querying all objects
+ access_port_selector=dict(
+ type="str",
+ aliases=[
+ "access_port_selector_name",
+ "port_selector",
+ "port_selector_name",
+ ],
+ ), # Not required for querying all objects
+ node_block=dict(type="str", aliases=["node_block_name", "name"]), # Not required for querying all objects
+ description=dict(type="str", aliases=["node_block_description"]),
+ from_port=dict(type="str", aliases=["from", "from_port_range"]),
+ to_port=dict(type="str", aliases=["to", "to_port_range"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ type_node=dict(type="str", choices=["leaf", "spine"], aliases=["type"]), # Not required for querying all objects
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["switch_profile", "access_port_selector", "node_block", "type_node"]],
+ ["state", "present", ["switch_profile", "access_port_selector", "node_block", "type_node"]],
+ ],
+ )
+
+ switch_profile = module.params.get("switch_profile")
+ access_port_selector = module.params.get("access_port_selector")
+ node_block = module.params.get("node_block")
+ description = module.params.get("description")
+ from_port = module.params.get("from_port")
+ to_port = module.params.get("to_port")
+ state = module.params.get("state")
+ type_node = module.params.get("type_node")
+
+ aci = ACIModule(module)
+
+ if type_node == "spine":
+ subclass_1 = dict(
+ aci_class="infraSpineP",
+ aci_rn="spprof-{0}".format(switch_profile),
+ module_object=switch_profile,
+ target_filter={"name": switch_profile},
+ )
+ subclass_2 = dict(
+ aci_class="infraSpineS",
+ aci_rn="spines-{0}-typ-range".format(access_port_selector),
+ module_object=access_port_selector,
+ target_filter={"name": access_port_selector},
+ )
+ else:
+ subclass_1 = dict(
+ aci_class="infraNodeP",
+ aci_rn="nprof-{0}".format(switch_profile),
+ module_object=switch_profile,
+ target_filter={"name": switch_profile},
+ )
+ subclass_2 = dict(
+ aci_class="infraLeafS",
+ aci_rn="leaves-{0}-typ-range".format(access_port_selector),
+ module_object=access_port_selector,
+ target_filter={"name": access_port_selector},
+ )
+ aci.construct_url(
+ root_class=dict(
+ aci_class="infraInfra",
+ aci_rn="infra",
+ ),
+ subclass_1=subclass_1,
+ subclass_2=subclass_2,
+ subclass_3=dict(
+ aci_class="infraNodeBlk",
+ aci_rn="nodeblk-{0}".format(node_block),
+ module_object=node_block,
+ target_filter={"name": node_block},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class="infraNodeBlk",
+ class_config=dict(
+ descr=description,
+ name=node_block,
+ from_=from_port,
+ to_=to_port,
+ ),
+ )
+
+ aci.get_diff(aci_class="infraNodeBlk")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_node_mgmt_epg.py b/ansible_collections/cisco/aci/plugins/modules/aci_node_mgmt_epg.py
index be8fe1838..161ce36f3 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_node_mgmt_epg.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_node_mgmt_epg.py
@@ -11,7 +11,7 @@ __metaclass__ = type
DOCUMENTATION = r"""
---
module: aci_node_mgmt_epg
-short_description: In band or Out of band management EPGs
+short_description: In band or Out of band management EPGs (mgmt:OoB and mgmt:InB)
description:
- Cisco ACI Fabric Node EPGs
options:
@@ -45,6 +45,10 @@ extends_documentation_fragment:
- cisco.aci.aci
- cisco.aci.annotation
+seealso:
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC classes B(mgmt:OoB) and B(mgmt:InB).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Shreyas Srish (@shrsr)
"""
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_ntp_policy.py b/ansible_collections/cisco/aci/plugins/modules/aci_ntp_policy.py
index 7fc8abde3..1adb35cc3 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_ntp_policy.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_ntp_policy.py
@@ -17,9 +17,9 @@ ANSIBLE_METADATA = {
DOCUMENTATION = r"""
---
module: aci_ntp_policy
-short_description: Manage NTP policies.
+short_description: Manage NTP policies (datetime:Pol)
description:
-- Manage NTP policy (datetimePol) configuration on Cisco ACI fabrics.
+- Manage NTP policy configuration on Cisco ACI fabrics.
options:
name:
description:
@@ -64,7 +64,7 @@ extends_documentation_fragment:
seealso:
- name: APIC Management Information Model reference
- description: More information about the internal APIC class B(datetimePol).
+ description: More information about the internal APIC class B(datetime:Pol).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Tim Cragg (@timcragg)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_ntp_server.py b/ansible_collections/cisco/aci/plugins/modules/aci_ntp_server.py
index 3e40b652a..e8a94a03b 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_ntp_server.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_ntp_server.py
@@ -17,7 +17,7 @@ ANSIBLE_METADATA = {
DOCUMENTATION = r"""
---
module: aci_ntp_server
-short_description: Manage NTP servers.
+short_description: Manage NTP servers (datetime:NtpProv)
description:
- Manage NTP server (datetimeNtpProv) configuration on Cisco ACI fabrics.
options:
@@ -74,7 +74,7 @@ notes:
The M(cisco.aci.aci_ntp_policy) module can be used for this.
seealso:
- name: APIC Management Information Model reference
- description: More information about the internal APIC class B(datetimeNtpProv).
+ description: More information about the internal APIC class B(datetime:NtpProv).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Tim Cragg (@timcragg)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_pim_route_map_entry.py b/ansible_collections/cisco/aci/plugins/modules/aci_pim_route_map_entry.py
new file mode 100644
index 000000000..79ad849a7
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_pim_route_map_entry.py
@@ -0,0 +1,329 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@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_pim_route_map_entry
+short_description: Manage Protocol-Independent Multicast (PIM) Route Map Entry (pim:RouteMapEntry)
+description:
+- Manage PIM Route Map Entries for the PIM route Map Policies on Cisco ACI fabrics.
+options:
+ tenant:
+ description:
+ - The name of an existing tenant.
+ type: str
+ aliases: [ tenant_name ]
+ pim_route_map_policy:
+ description:
+ - The name of the PIM Route Map policy.
+ type: str
+ aliases: [ route_map_policy_name ]
+ order:
+ description:
+ - The PIM Route Map Entry order.
+ type: int
+ source_ip:
+ description:
+ - The Multicast Source IP.
+ type: str
+ group_ip:
+ description:
+ - The Multicast Group IP.
+ type: str
+ rp_ip:
+ description:
+ - The Multicast Rendezvous Point (RP) IP.
+ type: str
+ aliases: [ rendezvous_point_ip ]
+ action:
+ description:
+ - The route action.
+ - The APIC defaults to C(permit) when unset during creation.
+ type: str
+ choices: [ permit, deny ]
+ description:
+ description:
+ - The description for the PIM Route Map entry.
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+notes:
+- The C(tenant) and the C(pim_route_map_policy) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant) and M(cisco.aci.aci_pim_route_map_policy) can be used for this.
+seealso:
+- module: cisco.aci.aci_tenant
+- module: cisco.aci.aci_pim_route_map_policy
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(pim:RouteMapEntry).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Gaspard Micol (@gmicol)
+"""
+
+EXAMPLES = r"""
+- name: Add a new PIM Route Map Entry
+ cisco.aci.aci_pim_route_map_entry:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ pim_route_map_policy: my_pim_route_map_policy
+ order: 1
+ source_ip: 1.1.1.1/24
+ group_ip: 224.0.0.1/24
+ rp_ip: 1.1.1.2
+ action: permit
+ state: present
+ delegate_to: localhost
+
+- name: Query a PIM Route Map Entry
+ cisco.aci.aci_pim_route_map_entry:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ pim_route_map_policy: my_pim_route_map_policy
+ order: 1
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all PIM Route Map Entries in my_pim_route_map_policy
+ cisco.aci.aci_pim_route_map_entry:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ pim_route_map_policy: my_pim_route_map_policy
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Delete a PIM Route Map Entry
+ cisco.aci.aci_pim_route_map_entry:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ pim_route_map_policy: my_pim_route_map_policy
+ order: 1
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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"]),
+ pim_route_map_policy=dict(type="str", aliases=["route_map_policy_name"]),
+ description=dict(type="str", aliases=["descr"]),
+ order=dict(type="int"),
+ source_ip=dict(type="str"),
+ group_ip=dict(type="str"),
+ rp_ip=dict(type="str", aliases=["rendezvous_point_ip"]),
+ action=dict(type="str", choices=["permit", "deny"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["tenant", "pim_route_map_policy", "order"]],
+ ["state", "present", ["tenant", "pim_route_map_policy", "order"]],
+ ],
+ )
+
+ tenant = module.params.get("tenant")
+ description = module.params.get("description")
+ pim_route_map_policy = module.params.get("pim_route_map_policy")
+ order = module.params.get("order")
+ source_ip = module.params.get("source_ip")
+ group_ip = module.params.get("group_ip")
+ rp_ip = module.params.get("rp_ip")
+ action = module.params.get("action")
+ state = module.params.get("state")
+
+ 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="pimRouteMapPol",
+ aci_rn="rtmap-{0}".format(pim_route_map_policy),
+ module_object=pim_route_map_policy,
+ target_filter={"name": pim_route_map_policy},
+ ),
+ subclass_2=dict(
+ aci_class="pimRouteMapEntry",
+ aci_rn="rtmapentry-{0}".format(order),
+ module_object=order,
+ target_filter={"order": order},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class="pimRouteMapEntry",
+ class_config=dict(
+ name=pim_route_map_policy,
+ descr=description,
+ action=action,
+ grp=group_ip,
+ order=order,
+ rp=rp_ip,
+ src=source_ip,
+ ),
+ )
+
+ aci.get_diff(aci_class="pimRouteMapEntry")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_pim_route_map_policy.py b/ansible_collections/cisco/aci/plugins/modules/aci_pim_route_map_policy.py
new file mode 100644
index 000000000..06c7c7b29
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_pim_route_map_policy.py
@@ -0,0 +1,276 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@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_pim_route_map_policy
+short_description: Manage Protocol-Independent Multicast (PIM) Route Map Policy (pim:RouteMapPol)
+description:
+- Manage PIM Route Map Policies for tenants on Cisco ACI fabrics.
+options:
+ tenant:
+ description:
+ - The name of an existing tenant.
+ type: str
+ aliases: [ tenant_name ]
+ pim_route_map_policy:
+ description:
+ - The name of the PIM Route Map policy.
+ type: str
+ aliases: [ route_map_policy_name, name ]
+ description:
+ description:
+ - The description for the PIM Route Map policy.
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+notes:
+- The C(tenant) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant) 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(pim:RouteMapPol).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Gaspard Micol (@gmicol)
+"""
+
+EXAMPLES = r"""
+- name: Add a new PIM Route Map policy
+ cisco.aci.aci_pim_route_map_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ pim_route_map_policy: my_pim_route_map_policy
+ state: present
+ delegate_to: localhost
+
+- name: Query a PIM Route Map policy
+ cisco.aci.aci_pim_route_map_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ pim_route_map_policy: my_pim_route_map_policy
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all PIM Route Map policies in my_tenant
+ cisco.aci.aci_pim_route_map_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Delete a PIM Route Map policy
+ cisco.aci.aci_pim_route_map_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ pim_route_map_policy: my_pim_route_map_policy
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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"]),
+ pim_route_map_policy=dict(type="str", aliases=["route_map_policy_name", "name"]),
+ description=dict(type="str", aliases=["descr"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["tenant", "pim_route_map_policy"]],
+ ["state", "present", ["tenant", "pim_route_map_policy"]],
+ ],
+ )
+
+ tenant = module.params.get("tenant")
+ description = module.params.get("description")
+ pim_route_map_policy = module.params.get("pim_route_map_policy")
+ state = module.params.get("state")
+
+ 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="pimRouteMapPol",
+ aci_rn="rtmap-{0}".format(pim_route_map_policy),
+ module_object=pim_route_map_policy,
+ target_filter={"name": pim_route_map_policy},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class="pimRouteMapPol",
+ class_config=dict(
+ name=pim_route_map_policy,
+ descr=description,
+ ),
+ )
+
+ aci.get_diff(aci_class="pimRouteMapPol")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_qos_custom_policy.py b/ansible_collections/cisco/aci/plugins/modules/aci_qos_custom_policy.py
new file mode 100644
index 000000000..c5200b0f7
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_qos_custom_policy.py
@@ -0,0 +1,284 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@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_qos_custom_policy
+short_description: Manage QoS Custom Policy (qos:CustomPol)
+description:
+- Manage QoS Custom Policies for tenants on Cisco ACI fabrics.
+- The custom QoS policy enables different levels of service to be assigned to network traffic,
+ including specifications for the Differentiated Services Code Point (DSCP) value(s), and the 802.1p Dot1p priority.
+options:
+ tenant:
+ description:
+ - The name of an existing tenant.
+ type: str
+ aliases: [ tenant_name ]
+ qos_custom_policy:
+ description:
+ - The name of the QoS Custom Policy.
+ type: str
+ aliases: [ qos_custom_policy_name, name ]
+ description:
+ description:
+ - The description for the QoS Custom Policy.
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+notes:
+- The I(tenant) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant) 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(qos:CustomPol).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Gaspard Micol (@gmicol)
+"""
+
+EXAMPLES = r"""
+- name: Add a new QoS Custom Policy
+ cisco.aci.aci_qos_custom_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ qos_custom_policy: my_qos_custom_policy
+ state: present
+ delegate_to: localhost
+
+- name: Query a QoS Custom Policy
+ cisco.aci.aci_qos_custom_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ qos_custom_policy: my_qos_custom_policy
+ state: query
+ delegate_to: localhost
+
+- name: Query all QoS Custom Policies in my_tenant
+ cisco.aci.aci_qos_custom_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ state: query
+ delegate_to: localhost
+
+- name: Query all QoS Custom Policies
+ cisco.aci.aci_qos_custom_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+
+- name: Delete a QoS Custom Policy
+ cisco.aci.aci_qos_custom_policy:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ qos_custom_policy: my_qos_custom_policy
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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"]),
+ qos_custom_policy=dict(type="str", aliases=["qos_custom_policy_name", "name"]),
+ description=dict(type="str", aliases=["descr"]),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["tenant", "qos_custom_policy"]],
+ ["state", "present", ["tenant", "qos_custom_policy"]],
+ ],
+ )
+
+ tenant = module.params.get("tenant")
+ description = module.params.get("description")
+ qos_custom_policy = module.params.get("qos_custom_policy")
+ state = module.params.get("state")
+
+ 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="qosCustomPol",
+ aci_rn="qoscustom-{0}".format(qos_custom_policy),
+ module_object=qos_custom_policy,
+ target_filter={"name": qos_custom_policy},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class="qosCustomPol",
+ class_config=dict(
+ name=qos_custom_policy,
+ descr=description,
+ ),
+ )
+
+ aci.get_diff(aci_class="qosCustomPol")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_qos_dot1p_class.py b/ansible_collections/cisco/aci/plugins/modules/aci_qos_dot1p_class.py
new file mode 100644
index 000000000..f6939af20
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_qos_dot1p_class.py
@@ -0,0 +1,355 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@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_qos_dot1p_class
+short_description: Manage QoS Dot1P Class (qos:Dot1PClass)
+description:
+- Manage Dot1P Class levels for QoS Custom Policies on Cisco ACI fabrics.
+- The class level for Dot1P to prioritize the map.
+options:
+ tenant:
+ description:
+ - The name of an existing tenant.
+ type: str
+ aliases: [ tenant_name ]
+ qos_custom_policy:
+ description:
+ - The name of the QoS Custom Policy.
+ type: str
+ aliases: [ qos_custom_policy_name ]
+ priority:
+ description:
+ - The desired QoS class level to be used.
+ - The APIC defaults to C(unspecified) when unset during creation.
+ type: str
+ choices: [ level1, level2, level3, level4, level5, level6, unspecified ]
+ aliases: [ prio ]
+ dot1p_from:
+ description:
+ - The Dot1P range starting value.
+ type: str
+ choices: [ background, best_effort, excellent_effort, critical_applications, video, voice, internetwork_control, network_control, unspecified ]
+ dot1p_to:
+ description:
+ - The Dot1P range ending value.
+ type: str
+ choices: [ background, best_effort, excellent_effort, critical_applications, video, voice, internetwork_control, network_control, unspecified ]
+ dot1p_target:
+ description:
+ - The Dot1P target value.
+ - The APIC defaults to C(unspecified) when unset during creation.
+ type: str
+ choices: [ AF11, AF12, AF13, AF21, AF22, AF23, AF31, AF32, AF33, AF41, AF42, AF43, CS0, CS1, CS2, CS3, CS4, CS5, CS6, CS7, EF, VA, unspecified ]
+ aliases: [ target ]
+ target_cos:
+ description:
+ - The target COS to be driven based on the range of input values of Dot1P coming into the fabric.
+ - The APIC defaults to C(unspecified) when unset during creation.
+ type: str
+ choices: [ background, best_effort, excellent_effort, critical_applications, video, voice, internetwork_control, network_control, unspecified ]
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+notes:
+- The I(tenant) and I(qos_custom_policy) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant) and the M(cisco.aci.aci_qos_custom_policy) can be used for this.
+seealso:
+- module: cisco.aci.aci_tenant
+- module: cisco.aci.aci_qos_custom_policy
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(qos:Dot1PClass).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Gaspard Micol (@gmicol)
+"""
+
+EXAMPLES = r"""
+- name: Add a new QoS dot1P Class
+ cisco.aci.aci_qos_dot1p_class:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ qos_custom_policy: my_qos_custom_policy
+ priority: level3
+ dot1p_from: best_effort
+ dot1p_to: excellent_effort
+ dot1p_target: unspecified
+ target_cos: unspecified
+ state: present
+ delegate_to: localhost
+
+- name: Query a QoS dot1P Class
+ cisco.aci.aci_qos_dot1p_class:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ qos_custom_policy: my_qos_custom_policy
+ dot1p_from: best_effort
+ dot1p_to: excellent_effort
+ state: query
+ delegate_to: localhost
+
+- name: Query all QoS dot1P Classes in my_qos_custom_policy
+ cisco.aci.aci_qos_dot1p_class:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ qos_custom_policy: my_qos_custom_policy
+ state: query
+ delegate_to: localhost
+
+- name: Query all QoS dot1P Classes
+ cisco.aci.aci_qos_dot1p_class:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+
+- name: Delete a QoS dot1P Class
+ cisco.aci.aci_qos_dot1p_class:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ qos_custom_policy: my_qos_custom_policy
+ dot1p_from: best_effort
+ dot1p_to: excellent_effort
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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,
+ aci_contract_dscp_spec,
+)
+from ansible_collections.cisco.aci.plugins.module_utils.constants import MATCH_TARGET_COS_MAPPING
+
+
+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"]),
+ qos_custom_policy=dict(type="str", aliases=["qos_custom_policy_name"]),
+ priority=dict(
+ type="str",
+ choices=[
+ "level1",
+ "level2",
+ "level3",
+ "level4",
+ "level5",
+ "level6",
+ "unspecified",
+ ],
+ aliases=["prio"],
+ ),
+ dot1p_from=dict(type="str", choices=list(MATCH_TARGET_COS_MAPPING.keys())),
+ dot1p_to=dict(type="str", choices=list(MATCH_TARGET_COS_MAPPING.keys())),
+ dot1p_target=aci_contract_dscp_spec(),
+ target_cos=dict(type="str", choices=list(MATCH_TARGET_COS_MAPPING.keys())),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["tenant", "qos_custom_policy", "dot1p_from", "dot1p_to"]],
+ ["state", "present", ["tenant", "qos_custom_policy", "dot1p_from", "dot1p_to"]],
+ ],
+ )
+
+ tenant = module.params.get("tenant")
+ qos_custom_policy = module.params.get("qos_custom_policy")
+ priority = module.params.get("priority")
+ dot1p_from = MATCH_TARGET_COS_MAPPING.get(module.params.get("dot1p_from"))
+ dot1p_to = MATCH_TARGET_COS_MAPPING.get(module.params.get("dot1p_to"))
+ dot1p_target = module.params.get("dot1p_target")
+ target_cos = MATCH_TARGET_COS_MAPPING.get(module.params.get("target_cos"))
+ state = module.params.get("state")
+
+ 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="qosCustomPol",
+ aci_rn="qoscustom-{0}".format(qos_custom_policy),
+ module_object=qos_custom_policy,
+ target_filter={"name": qos_custom_policy},
+ ),
+ subclass_2=dict(
+ aci_class="qosDot1PClass",
+ aci_rn="dot1P-{0}-{1}".format(dot1p_from, dot1p_to),
+ module_object=qos_custom_policy,
+ target_filter={"from": dot1p_from, "to": dot1p_to},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class="qosDot1PClass",
+ class_config={
+ "prio": priority,
+ "from": dot1p_from,
+ "to": dot1p_to,
+ "target": dot1p_target,
+ "targetCos": target_cos,
+ },
+ )
+
+ aci.get_diff(aci_class="qosDot1PClass")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_qos_dscp_class.py b/ansible_collections/cisco/aci/plugins/modules/aci_qos_dscp_class.py
new file mode 100644
index 000000000..18219d0c0
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_qos_dscp_class.py
@@ -0,0 +1,356 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@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_qos_dscp_class
+short_description: Manage QoS DSCP Class (qos:DscpClass)
+description:
+- Manage QoS Custom Differentiated Services Code Point (DSCP) Class levels for QoS Custom Policies on Cisco ACI fabrics.
+- The class level for DSCP to prioritize the map.
+options:
+ tenant:
+ description:
+ - The name of an existing tenant.
+ type: str
+ aliases: [ tenant_name ]
+ qos_custom_policy:
+ description:
+ - The name of the QoS Custom Policy.
+ type: str
+ aliases: [ qos_custom_policy_name ]
+ priority:
+ description:
+ - The desired QoS class level to be used.
+ - The APIC defaults to C(level3) when unset during creation.
+ type: str
+ choices: [ level1, level2, level3, level4, level5, level6, unspecified ]
+ aliases: [ prio ]
+ dscp_from:
+ description:
+ - The DSCP range starting value.
+ type: str
+ choices: [ AF11, AF12, AF13, AF21, AF22, AF23, AF31, AF32, AF33, AF41, AF42, AF43, CS0, CS1, CS2, CS3, CS4, CS5, CS6, CS7, EF, VA, unspecified ]
+ dscp_to:
+ description:
+ - The DSCP range ending value.
+ type: str
+ choices: [ AF11, AF12, AF13, AF21, AF22, AF23, AF31, AF32, AF33, AF41, AF42, AF43, CS0, CS1, CS2, CS3, CS4, CS5, CS6, CS7, EF, VA, unspecified ]
+ dscp_target:
+ description:
+ - The DSCP target value.
+ - The APIC defaults to C(unspecified) when unset during creation.
+ type: str
+ choices: [ AF11, AF12, AF13, AF21, AF22, AF23, AF31, AF32, AF33, AF41, AF42, AF43, CS0, CS1, CS2, CS3, CS4, CS5, CS6, CS7, EF, VA, unspecified ]
+ aliases: [ target ]
+ target_cos:
+ description:
+ - The target COS to be driven based on the range of input values of DSCP coming into the fabric.
+ - The APIC defaults to C(unspecified) when unset during creation.
+ type: str
+ choices: [ background, best_effort, excellent_effort, critical_applications, video, voice, internetwork_control, network_control, unspecified ]
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+notes:
+- The I(tenant) and I(qos_custom_policy) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant) and the M(cisco.aci.aci_qos_custom_policy) can be used for this.
+seealso:
+- module: cisco.aci.aci_tenant
+- module: cisco.aci.aci_qos_custom_policy
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(qos:DscpClass).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Gaspard Micol (@gmicol)
+"""
+
+EXAMPLES = r"""
+- name: Add a new QoS DSCP Class
+ cisco.aci.aci_qos_dscp_class:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ qos_custom_policy: my_qos_custom_policy
+ priority: level3
+ dscp_from: AF11
+ dscp_to: AF21
+ dscp_target: unspecified
+ target_cos: best_effort
+ state: present
+ delegate_to: localhost
+
+- name: Query a QoS DSCP Class
+ cisco.aci.aci_qos_dscp_class:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ qos_custom_policy: my_qos_custom_policy
+ dscp_from: AF11
+ dscp_to: AF21
+ state: query
+ delegate_to: localhost
+
+- name: Query all QoS DSCP Classes in my_qos_custom_policy
+ cisco.aci.aci_qos_dscp_class:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ qos_custom_policy: my_qos_custom_policy
+ state: query
+ delegate_to: localhost
+
+- name: Query all QoS DSCP Classes
+ cisco.aci.aci_qos_dscp_class:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+
+- name: Delete a QoS DSCP Class
+ cisco.aci.aci_qos_dscp_class:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: my_tenant
+ qos_custom_policy: my_qos_custom_policy
+ dscp_from: AF11
+ dscp_to: AF21
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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,
+ aci_contract_dscp_spec,
+)
+from ansible_collections.cisco.aci.plugins.module_utils.constants import MATCH_TARGET_COS_MAPPING
+
+
+def main():
+ new_dscp_spec = dict((k, aci_contract_dscp_spec()[k]) for k in aci_contract_dscp_spec() if k != "aliases")
+ 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"]),
+ qos_custom_policy=dict(type="str", aliases=["qos_custom_policy_name"]),
+ priority=dict(
+ type="str",
+ choices=[
+ "level1",
+ "level2",
+ "level3",
+ "level4",
+ "level5",
+ "level6",
+ "unspecified",
+ ],
+ aliases=["prio"],
+ ),
+ dscp_from=new_dscp_spec,
+ dscp_to=new_dscp_spec,
+ dscp_target=aci_contract_dscp_spec(),
+ target_cos=dict(type="str", choices=list(MATCH_TARGET_COS_MAPPING.keys())),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["tenant", "qos_custom_policy", "dscp_from", "dscp_to"]],
+ ["state", "present", ["tenant", "qos_custom_policy", "dscp_from", "dscp_to"]],
+ ],
+ )
+
+ tenant = module.params.get("tenant")
+ qos_custom_policy = module.params.get("qos_custom_policy")
+ priority = module.params.get("priority")
+ dscp_from = module.params.get("dscp_from")
+ dscp_to = module.params.get("dscp_to")
+ dscp_target = module.params.get("dscp_target")
+ target_cos = MATCH_TARGET_COS_MAPPING.get(module.params.get("target_cos"))
+ state = module.params.get("state")
+
+ 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="qosCustomPol",
+ aci_rn="qoscustom-{0}".format(qos_custom_policy),
+ module_object=qos_custom_policy,
+ target_filter={"name": qos_custom_policy},
+ ),
+ subclass_2=dict(
+ aci_class="qosDscpClass",
+ aci_rn="dcsp-{0}-{1}".format(dscp_from, dscp_to),
+ module_object=qos_custom_policy,
+ target_filter={"from": dscp_from, "to": dscp_to},
+ ),
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class="qosDscpClass",
+ class_config={
+ "prio": priority,
+ "from": dscp_from,
+ "to": dscp_to,
+ "target": dscp_target,
+ "targetCos": target_cos,
+ },
+ )
+
+ aci.get_diff(aci_class="qosDscpClass")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_rest.py b/ansible_collections/cisco/aci/plugins/modules/aci_rest.py
index ad73cb5bd..43986592a 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_rest.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_rest.py
@@ -3,6 +3,7 @@
# Copyright: (c) 2017, Dag Wieers (@dagwieers) <dag@wieers.com>
# Copyright: (c) 2020, Cindy Zhao (@cizhao) <cizhao@cisco.com>
+# Copyright: (c) 2023, Samita Bhattacharjee (@samitab) <samitab@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
@@ -62,6 +63,7 @@ options:
default: false
extends_documentation_fragment:
- cisco.aci.aci
+- cisco.aci.annotation
notes:
- Certain payloads are known not to be idempotent, so be careful when constructing payloads,
@@ -73,6 +75,7 @@ notes:
- XML payloads require the C(lxml) and C(xmljson) python libraries. For JSON payloads nothing special is needed.
- If you do not have any attributes, it may be necessary to add the "attributes" key with an empty dictionnary "{}" for value
as the APIC does expect the entry to precede any children.
+- Annotation set directly in c(src) or C(content) will take precedent over the C(annotation) parameter.
seealso:
- module: cisco.aci.aci_tenant
- name: Cisco APIC REST API Configuration Guide
@@ -81,6 +84,7 @@ seealso:
author:
- Dag Wieers (@dagwieers)
- Cindy Zhao (@cizhao)
+- Samita Bhattacharjee (@samitab)
"""
EXAMPLES = r"""
@@ -284,8 +288,11 @@ except Exception:
HAS_YAML = False
from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.cisco.aci.plugins.module_utils.aci import ACIModule, aci_argument_spec
+from ansible_collections.cisco.aci.plugins.module_utils.aci import ACIModule, aci_argument_spec, aci_annotation_spec
from ansible.module_utils._text import to_text
+from ansible_collections.cisco.aci.plugins.module_utils.annotation_unsupported import (
+ ANNOTATION_UNSUPPORTED,
+)
def update_qsl(url, params):
@@ -303,6 +310,33 @@ def update_qsl(url, params):
return url + "?" + "&".join(["%s=%s" % (k, v) for k, v in params.items()])
+def add_annotation(annotation, payload):
+ """Add annotation to payload only if it has not already been added"""
+ if annotation and isinstance(payload, dict):
+ for key, val in payload.items():
+ if key in ANNOTATION_UNSUPPORTED:
+ continue
+ att = val.get("attributes", {})
+ if "annotation" not in att.keys():
+ att["annotation"] = annotation
+ # Recursively add annotation to children
+ children = val.get("children", None)
+ if children:
+ for child in children:
+ add_annotation(annotation, child)
+
+
+def add_annotation_xml(annotation, tree):
+ """Add annotation to payload xml only if it has not already been added"""
+ if annotation:
+ for element in tree.iter():
+ if element.tag in ANNOTATION_UNSUPPORTED:
+ continue
+ ann = element.get("annotation")
+ if ann is None:
+ element.set("annotation", annotation)
+
+
class ACIRESTModule(ACIModule):
def changed(self, d):
"""Check ACI response for changes"""
@@ -335,6 +369,7 @@ class ACIRESTModule(ACIModule):
def main():
argument_spec = aci_argument_spec()
+ argument_spec.update(aci_annotation_spec())
argument_spec.update(
path=dict(type="str", required=True, aliases=["uri"]),
method=dict(type="str", default="get", choices=["delete", "get", "post"], aliases=["action"]),
@@ -353,6 +388,7 @@ def main():
path = module.params.get("path")
src = module.params.get("src")
rsp_subtree_preserve = module.params.get("rsp_subtree_preserve")
+ annotation = module.params.get("annotation")
# Report missing file
file_exists = False
@@ -388,21 +424,27 @@ def main():
if rest_type == "json":
if content and isinstance(content, dict):
# Validate inline YAML/JSON
+ add_annotation(annotation, payload)
payload = json.dumps(payload)
elif payload and isinstance(payload, str) and HAS_YAML:
try:
# Validate YAML/JSON string
- payload = json.dumps(yaml.safe_load(payload))
+ payload = yaml.safe_load(payload)
+ add_annotation(annotation, payload)
+ payload = json.dumps(payload)
except Exception as e:
module.fail_json(msg="Failed to parse provided JSON/YAML payload: {0}".format(to_text(e)), exception=to_text(e), payload=payload)
elif rest_type == "xml" and HAS_LXML_ETREE:
if content and isinstance(content, dict) and HAS_XMLJSON_COBRA:
# Validate inline YAML/JSON
+ add_annotation(annotation, payload)
payload = etree.tostring(cobra.etree(payload)[0], encoding="unicode")
elif payload and isinstance(payload, str):
try:
# Validate XML string
- payload = etree.tostring(etree.fromstring(payload), encoding="unicode")
+ payload = etree.fromstring(payload)
+ add_annotation_xml(annotation, payload)
+ payload = etree.tostring(payload, encoding="unicode")
except Exception as e:
module.fail_json(msg="Failed to parse provided XML payload: {0}".format(to_text(e)), payload=payload)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_snmp_client.py b/ansible_collections/cisco/aci/plugins/modules/aci_snmp_client.py
index a7c01dc8e..545167377 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_snmp_client.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_snmp_client.py
@@ -12,7 +12,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_snmp_client
-short_description: Manage SNMP clients (snmp:ClientP).
+short_description: Manage SNMP clients (snmp:ClientP)
description:
- Manage SNMP clients
options:
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_snmp_client_group.py b/ansible_collections/cisco/aci/plugins/modules/aci_snmp_client_group.py
index 7f7b12504..b18d4aecc 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_snmp_client_group.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_snmp_client_group.py
@@ -12,7 +12,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_snmp_client_group
-short_description: Manage SNMP client groups (snmp:ClientGrpP).
+short_description: Manage SNMP client groups (snmp:ClientGrpP)
description:
- Manage SNMP client groups
options:
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_snmp_community_policy.py b/ansible_collections/cisco/aci/plugins/modules/aci_snmp_community_policy.py
index 446962165..1494a6bbe 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_snmp_community_policy.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_snmp_community_policy.py
@@ -12,7 +12,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_snmp_community_policy
-short_description: Manage SNMP community policies (snmp:CommunityP).
+short_description: Manage SNMP community policies (snmp:CommunityP)
description:
- Manage SNMP community policies
options:
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_snmp_policy.py b/ansible_collections/cisco/aci/plugins/modules/aci_snmp_policy.py
index c3956db2f..3295453a7 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_snmp_policy.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_snmp_policy.py
@@ -12,9 +12,9 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_snmp_policy
-short_description: Manage Syslog groups (snmp:Pol).
+short_description: Manage Syslog groups (snmp:Pol)
description:
-- Manage syslog policies
+- Manage syslog policies.
options:
admin_state:
description:
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_snmp_user.py b/ansible_collections/cisco/aci/plugins/modules/aci_snmp_user.py
index 9e9b6d852..23e7c6f3e 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_snmp_user.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_snmp_user.py
@@ -14,9 +14,9 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_snmp_user
-short_description: Manage SNMP v3 Users (snmp:UserP).
+short_description: Manage SNMP v3 Users (snmp:UserP)
description:
-- Manage SNMP v3 Users
+- Manage SNMP v3 Users.
- Note that all properties within the snmpUserP class are Create-only. To modify any property of an existing user, you must delete and re-create it.
options:
auth_type:
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_static_node_mgmt_address.py b/ansible_collections/cisco/aci/plugins/modules/aci_static_node_mgmt_address.py
index 62602487e..bc99969be 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_static_node_mgmt_address.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_static_node_mgmt_address.py
@@ -13,7 +13,7 @@ __metaclass__ = type
DOCUMENTATION = r"""
---
module: aci_static_node_mgmt_address
-short_description: In band or Out of band management IP address
+short_description: In band or Out of band management IP address (mgmt:RsOoBStNode and mgmt:RsInBStNode)
description:
- Cisco ACI Fabric Node IP address
options:
@@ -65,6 +65,10 @@ extends_documentation_fragment:
- cisco.aci.aci
- cisco.aci.annotation
+seealso:
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC classes B(mgmt:RsOoBStNode) and B(mgmt:RsInBStNode).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Sudhakar Shet Kudtarkar (@kudtarkar1)
- Lionel Hercot (@lhercot)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_subject_label.py b/ansible_collections/cisco/aci/plugins/modules/aci_subject_label.py
new file mode 100644
index 000000000..a68c39d8f
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_subject_label.py
@@ -0,0 +1,746 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2022, Mark Ciecior (@markciecior)
+# Copyright: (c) 2024, Akini Ross <akinross@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": "certified"}
+
+DOCUMENTATION = r"""
+---
+module: aci_subject_label
+short_description: Manage Subject Labels (vz:ConsSubjLbl and vz:ProvSubjLbl)
+description:
+- Manage Subject Labels on Cisco ACI fabrics.
+options:
+ tenant:
+ description:
+ - The name of the Tenant.
+ type: str
+ aliases: [ tenant_name ]
+ l2out:
+ description:
+ - The name of the L2Out.
+ type: str
+ aliases: [ l2out_name ]
+ l3out:
+ description:
+ - The name of the L3Out.
+ type: str
+ aliases: [ l3out_name ]
+ external_epg:
+ description:
+ - The name of the External End Point Group.
+ type: str
+ aliases: [ extepg, extepg_name, external_epg_name ]
+ contract:
+ description:
+ - The name of the Contract.
+ type: str
+ aliases: [ contract_name ]
+ subject:
+ description:
+ - The name of the Subject.
+ type: str
+ aliases: [ subject_name ]
+ ap:
+ description:
+ - The name of the Application Profile.
+ type: str
+ aliases: [ app_profile, app_profile_name, application_profile, application_profile_name]
+ epg:
+ description:
+ - The name of the End Point Group.
+ type: str
+ aliases: [ epg_name ]
+ esg:
+ description:
+ - The name of the Endpoint Security Group.
+ type: str
+ aliases: [ esg_name ]
+ subject_label:
+ description:
+ - The name of the Subject Label.
+ type: str
+ aliases: [ subject_label_name, name, label ]
+ subject_label_type:
+ description:
+ - Determines the type of the Subject Label.
+ type: str
+ required: true
+ choices: [ consumer, provider ]
+ aliases: [ type ]
+ complement:
+ description:
+ - Whether complement is enabled on the Subject Label.
+ - The APIC defaults to C(false) when unset during creation.
+ type: bool
+ tag:
+ description:
+ - The color of a policy label of the Subject Label.
+ - The APIC defaults to C(yellow-green) when unset during creation.
+ type: str
+ choices:
+ - alice_blue
+ - antique_white
+ - aqua
+ - aquamarine
+ - azure
+ - beige
+ - bisque
+ - black
+ - blanched_almond
+ - blue
+ - blue_violet
+ - brown
+ - burlywood
+ - cadet_blue
+ - chartreuse
+ - chocolate
+ - coral
+ - cornflower_blue
+ - cornsilk
+ - crimson
+ - cyan
+ - dark_blue
+ - dark_cyan
+ - dark_goldenrod
+ - dark_gray
+ - dark_green
+ - dark_khaki
+ - dark_magenta
+ - dark_olive_green
+ - dark_orange
+ - dark_orchid
+ - dark_red
+ - dark_salmon
+ - dark_sea_green
+ - dark_slate_blue
+ - dark_slate_gray
+ - dark_turquoise
+ - dark_violet
+ - deep_pink
+ - deep_sky_blue
+ - dim_gray
+ - dodger_blue
+ - fire_brick
+ - floral_white
+ - forest_green
+ - fuchsia
+ - gainsboro
+ - ghost_white
+ - gold
+ - goldenrod
+ - gray
+ - green
+ - green_yellow
+ - honeydew
+ - hot_pink
+ - indian_red
+ - indigo
+ - ivory
+ - khaki
+ - lavender
+ - lavender_blush
+ - lawn_green
+ - lemon_chiffon
+ - light_blue
+ - light_coral
+ - light_cyan
+ - light_goldenrod_yellow
+ - light_gray
+ - light_green
+ - light_pink
+ - light_salmon
+ - light_sea_green
+ - light_sky_blue
+ - light_slate_gray
+ - light_steel_blue
+ - light_yellow
+ - lime
+ - lime_green
+ - linen
+ - magenta
+ - maroon
+ - medium_aquamarine
+ - medium_blue
+ - medium_orchid
+ - medium_purple
+ - medium_sea_green
+ - medium_slate_blue
+ - medium_spring_green
+ - medium_turquoise
+ - medium_violet_red
+ - midnight_blue
+ - mint_cream
+ - misty_rose
+ - moccasin
+ - navajo_white
+ - navy
+ - old_lace
+ - olive
+ - olive_drab
+ - orange
+ - orange_red
+ - orchid
+ - pale_goldenrod
+ - pale_green
+ - pale_turquoise
+ - pale_violet_red
+ - papaya_whip
+ - peachpuff
+ - peru
+ - pink
+ - plum
+ - powder_blue
+ - purple
+ - red
+ - rosy_brown
+ - royal_blue
+ - saddle_brown
+ - salmon
+ - sandy_brown
+ - sea_green
+ - seashell
+ - sienna
+ - silver
+ - sky_blue
+ - slate_blue
+ - slate_gray
+ - snow
+ - spring_green
+ - steel_blue
+ - tan
+ - teal
+ - thistle
+ - tomato
+ - turquoise
+ - violet
+ - wheat
+ - white
+ - white_smoke
+ - yellow
+ - yellow_green
+ description:
+ description:
+ - The description for the Subject Label.
+ 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
+
+seealso:
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(vz:ConsSubjLbl) and (vz:ProvSubjLbl).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Mark Ciecior (@markciecior)
+- Akini Ross (@akinross)
+"""
+
+EXAMPLES = r"""
+- name: Add a Subject Label on a Contract Subject
+ cisco.aci.aci_subject_label:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: production
+ contract: web
+ subject: web_subject
+ subject_label: web_subject_label
+ subject_type: consumer
+ state: present
+ delegate_to: localhost
+
+- name: Add a Subject Label on a L2Out External EPG
+ cisco.aci.aci_subject_label:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: production
+ l2out: l2out_name
+ external_epg: external_epg_name
+ subject_label: l2out_subject_label
+ subject_type: consumer
+ state: present
+ delegate_to: localhost
+
+- name: Add a Subject Label on a L3Out External EPG
+ cisco.aci.aci_subject_label:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: production
+ l3out: l3out_name
+ external_epg: external_epg_name
+ subject_label: l3out_subject_label
+ subject_type: consumer
+ state: present
+ delegate_to: localhost
+
+- name: Add a Subject Label on a L3Out External EPG Contract
+ cisco.aci.aci_subject_label:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: production
+ l3out: l3out_name
+ external_epg: external_epg_name
+ contract: web
+ subject_label: l3out_subject_label
+ subject_type: consumer
+ state: present
+ delegate_to: localhost
+
+- name: Add a Subject Label on a ESG
+ cisco.aci.aci_subject_label:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: production
+ ap: app_profile_name
+ esg: esg_name
+ subject_label: esg_subject_label
+ subject_type: consumer
+ state: present
+ delegate_to: localhost
+
+- name: Add a Subject Label on a EPG
+ cisco.aci.aci_subject_label:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: production
+ ap: app_profile_name
+ epg: epg_name
+ subject_label: epg_subject_label
+ subject_type: consumer
+ state: present
+ delegate_to: localhost
+
+- name: Add a Subject Label on a EPG Contract
+ cisco.aci.aci_subject_label:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: production
+ ap: app_profile_name
+ epg: epg_name
+ contract: web
+ subject_label: epg_subject_label
+ subject_type: consumer
+ state: present
+ delegate_to: localhost
+
+- name: Query a Subject Label on a Contract Subject
+ cisco.aci.aci_subject_label:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: production
+ contract: web
+ subject: web_subject
+ subject_label: web_subject_label
+ subject_type: consumer
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query all Subject Labels
+ cisco.aci.aci_subject_label:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Remove a Subject Label on a Contract Subject
+ cisco.aci.aci_subject_label:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ tenant: production
+ contract: web
+ subject: web_subject
+ subject_label: web_subject_label
+ subject_type: consumer
+ state: absent
+ delegate_to: localhost
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+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
+from ansible_collections.cisco.aci.plugins.module_utils.constants import ACI_CLASS_MAPPING, SUBJ_LABEL_MAPPING, SUBJ_LABEL_RN, POLICY_LABEL_COLORS
+
+
+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"]),
+ l2out=dict(type="str", aliases=["l2out_name"]),
+ l3out=dict(type="str", aliases=["l3out_name"]),
+ external_epg=dict(type="str", aliases=["extepg", "extepg_name", "external_epg_name"]),
+ contract=dict(type="str", aliases=["contract_name"]),
+ subject=dict(type="str", aliases=["subject_name"]),
+ ap=dict(type="str", aliases=["app_profile", "app_profile_name", "application_profile", "application_profile_name"]),
+ epg=dict(type="str", aliases=["epg_name"]),
+ esg=dict(type="str", aliases=["esg_name"]),
+ complement=dict(type="bool"),
+ description=dict(type="str", aliases=["descr"]),
+ subject_label=dict(type="str", aliases=["subject_label_name", "name", "label"]),
+ subject_label_type=dict(type="str", choices=["consumer", "provider"], aliases=["type"], required=True),
+ tag=dict(type="str", choices=POLICY_LABEL_COLORS),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ name_alias=dict(type="str"),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "present", ["tenant", "subject_label"]],
+ ["state", "present", ["l2out", "l3out", "epg", "esg", "subject"], True],
+ ["state", "absent", ["tenant", "subject_label"]],
+ ["state", "absent", ["l2out", "l3out", "epg", "esg", "subject"], True],
+ ],
+ mutually_exclusive=[
+ ["l2out", "l3out", "epg", "esg", "subject"],
+ ["esg", "contract"],
+ ["l2out", "contract"],
+ ],
+ required_by={
+ "subject": ["contract"],
+ "l2out": ["external_epg"],
+ "l3out": ["external_epg"],
+ "epg": ["ap"],
+ "esg": ["ap"],
+ },
+ )
+
+ aci = ACIModule(module)
+
+ tenant = module.params.get("tenant")
+ l2out = module.params.get("l2out")
+ l3out = module.params.get("l3out")
+ external_epg = module.params.get("external_epg")
+ contract = module.params.get("contract")
+ subject_label_type = module.params.get("subject_label_type")
+ subject = module.params.get("subject")
+ ap = module.params.get("ap")
+ epg = module.params.get("epg")
+ esg = module.params.get("esg")
+ complement = aci.boolean(module.params.get("complement"))
+ description = module.params.get("description")
+ subject_label = module.params.get("subject_label")
+ tag = module.params.get("tag")
+ state = module.params.get("state")
+ name_alias = module.params.get("name_alias")
+
+ aci_class = SUBJ_LABEL_MAPPING.get(subject_label_type)
+ aci_rn = SUBJ_LABEL_RN.get(subject_label_type) + subject_label if subject_label else None
+
+ if contract:
+ contract_rn = ACI_CLASS_MAPPING.get(subject_label_type).get("rn") + contract
+ contract_class = ACI_CLASS_MAPPING.get(subject_label_type).get("class")
+
+ root_class = dict(
+ aci_class="fvTenant",
+ aci_rn="tn-{0}".format(tenant),
+ module_object=tenant,
+ target_filter={"name": tenant},
+ )
+ subclass_1 = None
+ subclass_2 = None
+ subclass_3 = None
+ subclass_4 = None
+ if esg:
+ subclass_1 = dict(
+ aci_class="fvAp",
+ aci_rn="ap-{0}".format(ap),
+ module_object=ap,
+ target_filter={"name": ap},
+ )
+ subclass_2 = dict(
+ aci_class="fvESg",
+ aci_rn="esg-{0}".format(esg),
+ module_object=esg,
+ target_filter={"name": esg},
+ )
+ subclass_3 = dict(
+ aci_class=aci_class,
+ aci_rn=aci_rn,
+ module_object=subject_label,
+ target_filter={"name": subject_label},
+ )
+ elif l2out:
+ subclass_1 = dict(
+ aci_class="l2extOut",
+ aci_rn="l2out-{0}".format(l2out),
+ module_object=l2out,
+ target_filter={"name": l2out},
+ )
+ subclass_2 = dict(
+ aci_class="l2extInstP",
+ aci_rn="instP-{0}".format(external_epg),
+ module_object=external_epg,
+ target_filter={"name": external_epg},
+ )
+ subclass_3 = dict(
+ aci_class=aci_class,
+ aci_rn=aci_rn,
+ module_object=subject_label,
+ target_filter={"name": subject_label},
+ )
+ elif epg:
+ subclass_1 = dict(
+ aci_class="fvAp",
+ aci_rn="ap-{0}".format(ap),
+ module_object=ap,
+ target_filter={"name": ap},
+ )
+ subclass_2 = dict(
+ aci_class="fvAEPg",
+ aci_rn="epg-{0}".format(epg),
+ module_object=epg,
+ target_filter={"name": epg},
+ )
+ if contract:
+ subclass_3 = dict(
+ aci_class=contract_class,
+ aci_rn=contract_rn,
+ module_object=contract,
+ target_filter={"name": contract},
+ )
+ subclass_4 = dict(
+ aci_class=aci_class,
+ aci_rn=aci_rn,
+ module_object=subject_label,
+ target_filter={"name": subject_label},
+ )
+ else:
+ subclass_3 = dict(
+ aci_class=aci_class,
+ aci_rn=aci_rn,
+ module_object=subject_label,
+ target_filter={"name": subject_label},
+ )
+ elif l3out:
+ subclass_1 = subclass_1 = dict(
+ aci_class="l3extOut",
+ aci_rn="out-{0}".format(l3out),
+ module_object=l3out,
+ target_filter={"name": l3out},
+ )
+ subclass_2 = dict(
+ aci_class="l3extInstP",
+ aci_rn="instP-{0}".format(external_epg),
+ module_object=external_epg,
+ target_filter={"name": external_epg},
+ )
+ if contract:
+ subclass_3 = dict(
+ aci_class=contract_class,
+ aci_rn=contract_rn,
+ module_object=contract,
+ target_filter={"name": contract},
+ )
+ subclass_4 = dict(
+ aci_class=aci_class,
+ aci_rn=aci_rn,
+ module_object=subject_label,
+ target_filter={"name": subject_label},
+ )
+ else:
+ subclass_3 = dict(
+ aci_class=aci_class,
+ aci_rn=aci_rn,
+ module_object=subject_label,
+ target_filter={"name": subject_label},
+ )
+ elif subject:
+ subclass_1 = dict(
+ aci_class="vzBrCP",
+ aci_rn="brc-{0}".format(contract),
+ module_object=contract,
+ target_filter={"name": contract},
+ )
+ subclass_2 = dict(
+ aci_class="vzSubj",
+ aci_rn="subj-{0}".format(subject),
+ module_object=subject,
+ target_filter={"name": subject},
+ )
+ subclass_3 = dict(
+ aci_class=aci_class,
+ aci_rn=aci_rn,
+ module_object=subject_label,
+ target_filter={"name": subject_label},
+ )
+ else: # Query scenario without any filters forcing class query on the subject_label_class
+ root_class = dict(
+ aci_class=aci_class,
+ aci_rn=aci_rn,
+ module_object=subject_label,
+ target_filter={"name": subject_label},
+ )
+
+ aci.construct_url(
+ root_class=root_class,
+ subclass_1=subclass_1,
+ subclass_2=subclass_2,
+ subclass_3=subclass_3,
+ subclass_4=subclass_4,
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ aci.payload(
+ aci_class=aci_class,
+ class_config=dict(
+ name=subject_label,
+ descr=description,
+ nameAlias=name_alias,
+ isComplement=complement,
+ tag=tag.replace("_", "-") if tag else None,
+ ),
+ )
+
+ aci.get_diff(aci_class=aci_class)
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_switch_leaf_selector.py b/ansible_collections/cisco/aci/plugins/modules/aci_switch_leaf_selector.py
index 2b850f1cd..bf081bd57 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_switch_leaf_selector.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_switch_leaf_selector.py
@@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2017, Bruno Calogero <brunocalogero@hotmail.com>
+# Copyright: (c) 2024, Gaspard Micol (@gmicol) <gmicol@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
@@ -13,7 +14,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_switch_leaf_selector
-short_description: Bind leaf selectors to switch policy leaf profiles (infra:LeafS, infra:NodeBlk, infra:RsAccNodePGrep)
+short_description: Bind leaf selectors to switch policy leaf profiles (infra:LeafS, infra:NodeBlk, and infra:RsAccNodePGrep)
description:
- Bind leaf selectors (with node block range and policy group) to switch policy leaf profiles on Cisco ACI fabrics.
options:
@@ -82,6 +83,7 @@ seealso:
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Bruno Calogero (@brunocalogero)
+- Gaspard Micol (@gmicol)
"""
EXAMPLES = r"""
@@ -266,7 +268,7 @@ def main():
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
- required_if=[["state", "absent", ["leaf_profile", "leaf"]], ["state", "present", ["leaf_profile", "leaf", "leaf_node_blk", "from", "to"]]],
+ required_if=[["state", "absent", ["leaf_profile", "leaf"]], ["state", "present", ["leaf_profile", "leaf"]]],
)
description = module.params.get("description")
@@ -280,19 +282,21 @@ def main():
state = module.params.get("state")
name_alias = module.params.get("name_alias")
- # Build child_configs dynamically
- child_configs = [
- dict(
- infraNodeBlk=dict(
- attributes=dict(
- descr=leaf_node_blk_description,
- name=leaf_node_blk,
- from_=from_,
- to_=to_,
+ child_configs = []
+ # Add infraNodeBlk only when leaf_node_blk was defined
+ if leaf_node_blk is not None:
+ child_configs.append(
+ dict(
+ infraNodeBlk=dict(
+ attributes=dict(
+ descr=leaf_node_blk_description,
+ name=leaf_node_blk,
+ from_=from_,
+ to_=to_,
+ ),
),
),
- ),
- ]
+ )
# Add infraRsAccNodePGrp only when policy_group was defined
if policy_group is not None:
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_switch_policy_vpc_protection_group.py b/ansible_collections/cisco/aci/plugins/modules/aci_switch_policy_vpc_protection_group.py
index a7994db73..507c84a17 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_switch_policy_vpc_protection_group.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_switch_policy_vpc_protection_group.py
@@ -13,7 +13,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_switch_policy_vpc_protection_group
-short_description: Manage switch policy explicit vPC protection groups (fabric:ExplicitGEp, fabric:NodePEp).
+short_description: Manage switch policy explicit vPC protection groups (fabric:ExplicitGEp and fabric:NodePEp).
description:
- Manage switch policy explicit vPC protection groups on Cisco ACI fabrics.
options:
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_syslog_group.py b/ansible_collections/cisco/aci/plugins/modules/aci_syslog_group.py
index bab3379a1..205c3593b 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_syslog_group.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_syslog_group.py
@@ -12,9 +12,9 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_syslog_group
-short_description: Manage Syslog groups (syslog:Group, syslog:Console, syslog:File and syslog:Prof).
+short_description: Manage Syslog groups (syslog:Group, syslog:Console, syslog:File and syslog:Prof)
description:
-- Manage syslog groups
+- Manage syslog groups.
options:
admin_state:
description:
@@ -72,7 +72,7 @@ extends_documentation_fragment:
seealso:
- name: APIC Management Information Model reference
- description: More information about the internal APIC classes B(syslog:Group).
+ description: More information about the internal APIC classes B(syslog:Group), B(syslog:Console), B(syslog:File) and B(syslog:Prof).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Tim Cragg (@timcragg)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_syslog_remote_dest.py b/ansible_collections/cisco/aci/plugins/modules/aci_syslog_remote_dest.py
index b3c1a02b4..43d2e85eb 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_syslog_remote_dest.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_syslog_remote_dest.py
@@ -12,10 +12,9 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_syslog_remote_dest
-short_description: Manage Syslog Remote Destinations (syslog:RemoteDest).
+short_description: Manage Syslog Remote Destinations (syslog:RemoteDest)
description:
-- Manage remote destinations for syslog messages within
- an existing syslog group object
+- Manage remote destinations for syslog messages within an existing syslog group object.
options:
admin_state:
description:
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_syslog_source.py b/ansible_collections/cisco/aci/plugins/modules/aci_syslog_source.py
index b0bb61bb5..0e3bc6b78 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_syslog_source.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_syslog_source.py
@@ -15,7 +15,7 @@ DOCUMENTATION = r"""
module: aci_syslog_source
short_description: Manage Syslog Source objects (syslog:Src)
description:
-- Manage Syslog Source objects
+- Manage Syslog Source objects.
options:
name:
description:
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_system.py b/ansible_collections/cisco/aci/plugins/modules/aci_system.py
index 6a3349ec0..53e2b90e8 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_system.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_system.py
@@ -13,7 +13,7 @@ DOCUMENTATION = r"""
module: aci_system
short_description: Query the ACI system information (top:System)
description:
-- Query the ACI system information (top:System) on Cisco ACI.
+- Query the ACI system information on Cisco ACI.
author:
- Lionel Hercot (@lhercot)
options:
@@ -30,10 +30,11 @@ options:
type: str
notes:
-- More information about the internal APIC class B(top:System) from
- L(the APIC Management Information Model reference,https://developer.cisco.com/docs/apic-mim-ref/).
- This module is used to query system information for both cloud and on-premises controllers.
-
+seealso:
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(top:System).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
extends_documentation_fragment:
- cisco.aci.aci
"""
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_tag.py b/ansible_collections/cisco/aci/plugins/modules/aci_tag.py
index 9e56ae068..d005b462b 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_tag.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_tag.py
@@ -12,7 +12,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_tag
-short_description: Tagging of ACI objects
+short_description: Tagging of ACI objects (tag:Annotation, tag:Inst, and tag:Tag)
description:
- Tagging a object on Cisco ACI fabric.
options:
@@ -50,7 +50,11 @@ notes:
- CAVEAT - Due to deprecation of the 'tagInst' object, creating a tag with tag_type 'instance' automatically generates a
'annotation' tag_type tag with an empty value. When deleting a tag_type 'instance', the 'tagAnnotation' object will
remain present and needs to be deleted separately.
+
seealso:
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC classes B(tag:Annotation), B(tag:Inst), and B(tag:Tag).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
- name: Cisco APIC System Management Configuration Guide
description: More information about the tagging can be found in the Cisco APIC System Management Configuration Guide.
link: https://www.cisco.com/c/en/us/support/cloud-systems-management/application-policy-infrastructure-controller-apic/tsd-products-support-series-home.html
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_tenant_action_rule_profile.py b/ansible_collections/cisco/aci/plugins/modules/aci_tenant_action_rule_profile.py
index 55b76f3d6..f51d28fcd 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_tenant_action_rule_profile.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_tenant_action_rule_profile.py
@@ -1,6 +1,9 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+# Copyright: (c) 2023, Dag Wieers (@dagwieers)
+# Copyright: (c) 2023, Tim Cragg (@timcragg) <tcragg@cisco.com>
+# Copyright: (c) 2023, Gaspard Micol (@gmicol) <gmicol@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
@@ -16,21 +19,105 @@ short_description: Manage action rule profiles (rtctrl:AttrP)
description:
- Manage action rule profiles on Cisco ACI fabrics.
options:
+ tenant:
+ description:
+ - The name of the tenant.
+ type: str
+ aliases: [ tenant_name ]
action_rule:
description:
- The name of the action rule profile.
type: str
- aliases: [ action_rule_name, name ]
+ aliases: [action_rule_name, name ]
+ set_community:
+ description:
+ - The set action rule based on communities.
+ - To delete this attribute, pass an empty dictionary.
+ type: dict
+ suboptions:
+ community:
+ description:
+ - The community value.
+ type: str
+ criteria:
+ description:
+ - The community criteria.
+ - The option to append or replace the community value.
+ type: str
+ choices: [ append, replace, none ]
+ set_dampening:
+ description:
+ - The set action rule based on dampening.
+ - To delete this attribute, pass an empty dictionary.
+ type: dict
+ suboptions:
+ half_life:
+ description:
+ - The half life value (minutes).
+ type: int
+ max_suppress_time:
+ description:
+ - The maximum suppress time value (minutes).
+ type: int
+ reuse:
+ description:
+ - The reuse limit value.
+ type: int
+ suppress:
+ description:
+ - The suppress limit value.
+ type: int
+ set_next_hop:
+ description:
+ - The set action rule based on the next hop address.
+ - To delete this attribute, pass an empty string.
+ type: str
+ next_hop_propagation:
+ description:
+ - The set action rule based on nexthop unchanged configuration.
+ - Can not be configured along with C(set_route_tag).
+ - Can not be configured for APIC version 4.2 and prior.
+ - The APIC defaults to C(false) when unset.
+ type: bool
+ multipath:
+ description:
+ - Set action rule based on set redistribute multipath configuration.
+ - Can not be configured along with C(set_route_tag).
+ - Can not be configured for APIC version 4.2 and prior.
+ - The APIC defaults to C(false) when unset.
+ type: bool
+ set_preference:
+ description:
+ - The set action rule based on preference.
+ - To delete this attribute, pass an empty string.
+ type: str
+ set_metric:
+ description:
+ - The set action rule based on metric.
+ - To delete this attribute, pass an empty string.
+ type: str
+ set_metric_type:
+ description:
+ - The set action rule based on a metric type.
+ - To delete this attribute, pass an empty string.
+ type: str
+ choices: [ ospf_type_1, ospf_type_2, "" ]
+ set_route_tag:
+ description:
+ - The set action rule based on route tag.
+ - Can not be configured along with C(next_hop_propagation) and C(multipath).
+ - To delete this attribute, pass an empty string.
+ type: str
+ set_weight:
+ description:
+ - The set action rule based on weight.
+ - To delete this attribute, pass an empty string.
+ type: str
description:
description:
- The description for the action rule profile.
type: str
aliases: [ descr ]
- tenant:
- description:
- - The name of the tenant.
- type: str
- aliases: [ tenant_name ]
state:
description:
- Use C(present) or C(absent) for adding or removing.
@@ -56,6 +143,8 @@ seealso:
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Dag Wieers (@dagwieers)
+- Tim Cragg (@timcragg)
+- Gaspard Micol (@gmicol)
"""
EXAMPLES = r"""
@@ -66,6 +155,40 @@ EXAMPLES = r"""
password: SomeSecretPassword
action_rule: my_action_rule
tenant: prod
+ set_preference: 100
+ set_weight: 100
+ set_metric: 100
+ set_metric_type: ospf_type_1
+ set_next_hop: 1.1.1.1
+ next_hop_propagation: true
+ multipath: true
+ set_community:
+ community: no-advertise
+ criteria: replace
+ set_dampening:
+ half_life: 10
+ reuse: 1
+ suppress: 10
+ max_suppress_time: 100
+ state: present
+ delegate_to: localhost
+
+- name: Delete action rule profile's children
+ cisco.aci.aci_tenant_action_rule_profile:
+ host: apic
+ username: admin
+ password: SomeSecretPassword
+ action_rule: my_action_rule
+ tenant: prod
+ set_preference: ""
+ set_weight: ""
+ set_metric: ""
+ set_metric_type: ""
+ set_next_hop: ""
+ next_hop_propagation: false
+ multipath: false
+ set_community: {}
+ set_dampening: {}
state: present
delegate_to: localhost
@@ -206,7 +329,14 @@ url:
"""
from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.cisco.aci.plugins.module_utils.aci import ACIModule, aci_argument_spec, aci_annotation_spec
+from ansible_collections.cisco.aci.plugins.module_utils.aci import (
+ ACIModule,
+ aci_argument_spec,
+ aci_annotation_spec,
+ action_rule_set_comm_spec,
+ action_rule_set_dampening_spec,
+)
+from ansible_collections.cisco.aci.plugins.module_utils.constants import MATCH_ACTION_RULE_SET_METRIC_TYPE_MAPPING
def main():
@@ -215,6 +345,16 @@ def main():
argument_spec.update(
action_rule=dict(type="str", aliases=["action_rule_name", "name"]), # Not required for querying all objects
tenant=dict(type="str", aliases=["tenant_name"]), # Not required for querying all objects
+ set_community=dict(type="dict", options=action_rule_set_comm_spec()),
+ set_dampening=dict(type="dict", options=action_rule_set_dampening_spec()),
+ set_next_hop=dict(type="str"),
+ next_hop_propagation=dict(type="bool"),
+ multipath=dict(type="bool"),
+ set_preference=dict(type="str"),
+ set_metric=dict(type="str"),
+ set_metric_type=dict(type="str", choices=["ospf_type_1", "ospf_type_2", ""]),
+ set_route_tag=dict(type="str"),
+ set_weight=dict(type="str"),
description=dict(type="str", aliases=["descr"]),
state=dict(type="str", default="present", choices=["absent", "present", "query"]),
name_alias=dict(type="str"),
@@ -236,6 +376,31 @@ def main():
name_alias = module.params.get("name_alias")
aci = ACIModule(module)
+
+ # This dict contains the name of the child classes as well as the corresping attribute input (and attribute name if the input is a string)
+ # this dict is deviating from normal child classes list structure in order to determine which child classes should be created, modified, deleted or ignored.
+ child_classes = dict(
+ rtctrlSetComm=dict(attribute_input=module.params.get("set_community")),
+ rtctrlSetDamp=dict(attribute_input=module.params.get("set_dampening")),
+ rtctrlSetNh=dict(attribute_input=module.params.get("set_next_hop"), attribute_name="addr"),
+ rtctrlSetPref=dict(attribute_input=module.params.get("set_preference"), attribute_name="localPref"),
+ rtctrlSetRtMetric=dict(attribute_input=module.params.get("set_metric"), attribute_name="metric"),
+ rtctrlSetRtMetricType=dict(
+ attribute_input=MATCH_ACTION_RULE_SET_METRIC_TYPE_MAPPING.get(module.params.get("set_metric_type")), attribute_name="metricType"
+ ),
+ rtctrlSetTag=dict(attribute_input=module.params.get("set_route_tag"), attribute_name="tag"),
+ rtctrlSetWeight=dict(attribute_input=module.params.get("set_weight"), attribute_name="weight"),
+ )
+
+ # This condition deal with child classes which do not exist in APIC version 4.2 and prior.
+ additional_child_classes = dict(
+ rtctrlSetNhUnchanged=dict(attribute_input=module.params.get("next_hop_propagation")),
+ rtctrlSetRedistMultipath=dict(attribute_input=module.params.get("multipath")),
+ )
+ for class_name, attribute in additional_child_classes.items():
+ if attribute.get("attribute_input") is not None:
+ child_classes[class_name] = attribute
+
aci.construct_url(
root_class=dict(
aci_class="fvTenant",
@@ -249,11 +414,63 @@ def main():
module_object=action_rule,
target_filter={"name": action_rule},
),
+ child_classes=list(child_classes.keys()),
)
aci.get_existing()
if state == "present":
+ child_configs = []
+ for class_name, attribute in child_classes.items():
+ attribute_input = attribute.get("attribute_input")
+ # This condition enables to user to keep its previous configurations if they are not passing anything in the payload.
+ if attribute_input is not None:
+ # This condition checks if the attribute input is a dict and checks if all of its values are None (stored as a boolean in only_none).
+ only_none = False
+ if isinstance(attribute_input, dict):
+ only_none = all(value is None for value in attribute_input.values())
+ # This condition checks if the child object needs to be deleted depending on the type of the corresponding attribute input (bool, str, dict).
+ if (attribute_input == "" or attribute_input is False or only_none) and isinstance(aci.existing, list) and len(aci.existing) > 0:
+ for child in aci.existing[0].get("rtctrlAttrP", {}).get("children", {}):
+ if child.get(class_name):
+ child_configs.append(
+ {
+ class_name: dict(
+ attributes=dict(status="deleted"),
+ ),
+ }
+ )
+ # This condition checks if the child object needs to be modified or created depending on the type of the corresponding attribute input.
+ elif attribute_input != "" or attribute_input is True or attribute_input != {}:
+ if class_name == "rtctrlSetComm" and isinstance(attribute_input, dict):
+ child_configs.append(
+ {
+ class_name: dict(
+ attributes=dict(
+ community=attribute_input.get("community"),
+ setCriteria=attribute_input.get("criteria"),
+ ),
+ )
+ }
+ )
+ elif class_name == "rtctrlSetDamp" and isinstance(attribute_input, dict):
+ child_configs.append(
+ {
+ class_name: dict(
+ attributes=dict(
+ halfLife=attribute_input.get("half_life"),
+ maxSuppressTime=attribute_input.get("max_suppress_time"),
+ reuse=attribute_input.get("reuse"),
+ suppress=attribute_input.get("suppress"),
+ ),
+ )
+ }
+ )
+ elif class_name in ["rtctrlSetNhUnchanged", "rtctrlSetRedistMultipath"]:
+ child_configs.append({class_name: dict(attributes=dict(descr=""))})
+ else:
+ child_configs.append({class_name: dict(attributes={attribute.get("attribute_name"): attribute_input})})
+
aci.payload(
aci_class="rtctrlAttrP",
class_config=dict(
@@ -261,6 +478,7 @@ def main():
descr=description,
nameAlias=name_alias,
),
+ child_configs=child_configs,
)
aci.get_diff(aci_class="rtctrlAttrP")
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_vmm_controller.py b/ansible_collections/cisco/aci/plugins/modules/aci_vmm_controller.py
index f8a51529c..eac547dc1 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_vmm_controller.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_vmm_controller.py
@@ -3,6 +3,7 @@
# Copyright: (c) 2021, Manuel Widmer <mawidmer@cisco.com>
# Copyright: (c) 2021, Anvitha Jain (@anvitha-jain) <anvjain@cisco.com>
+# Copyright: (c) 2023, Akini Ross (@akinross) <akinross@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
@@ -88,6 +89,8 @@ seealso:
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Manuel Widmer (@lumean)
+- Anvitha Jain (@anvitha-jain)
+- Akini Ross (@akinross)
"""
EXAMPLES = r"""
@@ -132,7 +135,6 @@ EXAMPLES = r"""
host: apic
username: admin
password: SomeSecretPassword
- vm_provider: vmware
state: query
delegate_to: localhost
register: query_result
@@ -310,6 +312,8 @@ def main():
aci = ACIModule(module)
+ child_classes = ["vmmRsMgmtEPg", "vmmRsAcc"]
+
aci.construct_url(
root_class=dict(
aci_class="vmmProvP",
@@ -327,11 +331,23 @@ def main():
aci_class="vmmCtrlrP",
aci_rn="ctrlr-{0}".format(name),
module_object=name,
- target_filter={"name": "name"},
+ target_filter={"name": name},
),
- child_classes=["vmmRsMgmtEPg", "vmmRsAcc"],
+ child_classes=child_classes,
)
+ # vmmProvP is not allowed to execute a query with rsp-subtree set in the filter_string
+ # due to complicated url construction logic which should be refactored creating a temporary fix inside module
+ # TODO refactor url construction logic if more occurences of rsp-subtree not supported problem appear
+ # check if the url is pointing towards the vmmProvP class and rsp-subtree is set in the filter_string
+ if aci.url.split("/")[-1].startswith("vmmp-") and "rsp-subtree" in aci.filter_string:
+ if name:
+ aci.url = "{0}/api/class/vmmCtrlrP.json".format(aci.base_url)
+ aci.filter_string = '?query-target-filter=eq(vmmCtrlrP.name,"{0}")&rsp-subtree=full&rsp-subtree-class={1}'.format(name, ",".join(child_classes))
+ else:
+ aci.url = "{0}/api/mo/uni/vmmp-{1}.json".format(aci.base_url, VM_PROVIDER_MAPPING.get(vm_provider))
+ aci.filter_string = ""
+
aci.get_existing()
if state == "present":
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_vmm_vswitch_policy.py b/ansible_collections/cisco/aci/plugins/modules/aci_vmm_vswitch_policy.py
index 79d8182ff..90525e11c 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_vmm_vswitch_policy.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_vmm_vswitch_policy.py
@@ -14,7 +14,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_vmm_vswitch_policy
-short_description: Manage vSwitch policy for VMware virtual domains profiles (vmm:DomP)
+short_description: Manage vSwitch policy for VMware virtual domains profiles (vmm:VSwitchPolicyCont)
description:
- Manage vSwitch policy for VMware VMM domains on Cisco ACI fabrics.
options:
@@ -139,7 +139,7 @@ extends_documentation_fragment:
seealso:
- module: cisco.aci.aci_domain
- name: APIC Management Information Model reference
- description: More information about the internal APIC classes B(vmm:DomP)
+ description: More information about the internal APIC classes B(vmm:VSwitchPolicyCont).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Manuel Widmer (@lumean)
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_vrf_multicast.py b/ansible_collections/cisco/aci/plugins/modules/aci_vrf_multicast.py
new file mode 100644
index 000000000..4d3809902
--- /dev/null
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_vrf_multicast.py
@@ -0,0 +1,702 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2023, Tim Cragg (@timcragg)
+# Copyright: (c) 2023, Akini Ross (@akinross)
+# 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_vrf_multicast
+short_description: Manage VRF Multicast objects (pim:CtxP)
+description:
+- Manage VRF Multicast objects on Cisco ACI fabrics.
+- Creating I(state=present) enables Protocol Independent Multicast (PIM) on a VRF
+- Deleting I(state=absent) disables Protocol Independent Multicast (PIM) on a VRF.
+options:
+ tenant:
+ description:
+ - The name of an existing tenant.
+ type: str
+ aliases: [ tenant_name ]
+ vrf:
+ description:
+ - The name of an existing VRF.
+ type: str
+ aliases: [ vrf_name ]
+ pim_setting:
+ description: Configuration container for Protocol Independent Multicast (PIM) settings.
+ type: dict
+ suboptions:
+ mtu:
+ description:
+ - The MTU size supported for multicast.
+ - The APIC defaults to C(1500) when unset during creation.
+ type: int
+ control_state:
+ description:
+ - The action(s) to take when a loop is detected.
+ - Specify C([]) to remove the control state configuration.
+ type: list
+ elements: str
+ aliases: [ control, ctrl ]
+ choices: [ fast, strict ]
+ resource_policy:
+ description: Configuration container for Protocol Independent Multicast (PIM) resource policy.
+ type: dict
+ suboptions:
+ maximum_limit:
+ description:
+ - The Max Multicast Entries.
+ - The APIC defaults to C(unlimited) when unset during creation.
+ - Specify C(0) to reset to C(unlimited).
+ type: int
+ aliases: [ max ]
+ reserved_multicast_entries:
+ description:
+ - The Reserved Multicast Entries.
+ - The APIC defaults to C(undefined) when unset during creation.
+ - Required when C(reserved_route_map) is provided.
+ type: int
+ aliases: [ rsvd ]
+ reserved_route_map:
+ description:
+ - The DN of the Route Map.
+ - Specify C("") to remove the Route Map configuration.
+ - Required when C(reserved_multicast_entries) is provided.
+ type: str
+ aliases: [ route_map, route_map_dn ]
+ any_source_multicast:
+ description: Configuration container for Protocol Independent Multicast (PIM) Any Source Multicast (ASM) settings.
+ type: dict
+ aliases: [ asm, any_source ]
+ suboptions:
+ shared_range_route_map:
+ description:
+ - The DN of the Route Map.
+ - Specify C("") to remove the Route Map configuration.
+ type: str
+ aliases: [ shared_range_policy ]
+ source_group_expiry_route_map:
+ description:
+ - The DN of the Route Map.
+ - Specify C("") to remove the Route Map configuration.
+ type: str
+ aliases: [ sg_expiry_route_map ]
+ expiry:
+ description:
+ - The expiry time in seconds.
+ - The APIC defaults to C(default-timeout) when unset during creation.
+ - Specify C(0) to reset to C(default-timeout).
+ type: int
+ aliases: [ expiry_seconds ]
+ max_rate:
+ description:
+ - The maximum rate per second.
+ - The APIC defaults to C(65535) when unset during creation.
+ type: int
+ aliases: [ max_rate_per_second ]
+ source_ip:
+ description:
+ - The source IP address.
+ type: str
+ aliases: [ source, source_ip_address ]
+ source_specific_multicast:
+ description: Configuration container for Protocol Independent Multicast (PIM) Source Specific Multicast (SSM) settings.
+ type: dict
+ aliases: [ ssm, specific_source ]
+ suboptions:
+ group_range_route_map:
+ description:
+ - The DN of the Route Map.
+ - Specify C("") to remove the Route Map configuration.
+ type: str
+ aliases: [ group_range_policy ]
+ bootstrap_router:
+ description: Configuration container for Protocol Independent Multicast (PIM) Bootstrap Router (BSR) settings.
+ type: dict
+ aliases: [ bsr, bootstrap ]
+ suboptions:
+ bsr_filter:
+ description:
+ - The DN of the Route Map.
+ - Specify C("") to remove the Route Map configuration.
+ type: str
+ aliases: [ filter, route_map, route_map_dn ]
+ rp_updates:
+ description:
+ - The control state of the Bootstrap Router (BSR) policy.
+ - Specify C([]) to remove the control state configuration.
+ type: list
+ elements: str
+ aliases: [ control, ctrl ]
+ choices: [ forward, listen ]
+ auto_rp:
+ description: Configuration container for Protocol Independent Multicast (PIM) Auto-Rendezvous Point (Auto-RP) settings.
+ type: dict
+ aliases: [ auto ]
+ suboptions:
+ ma_filter:
+ description:
+ - The DN of the Route Map.
+ - Specify C("") to remove the Route Map configuration.
+ type: str
+ aliases: [ filter, route_map, route_map_dn ]
+ rp_updates:
+ description:
+ - The control state of the Auto-Rendezvous Point (Auto-RP) policy.
+ - Specify C([]) to remove the control state configuration.
+ type: list
+ elements: str
+ aliases: [ control, ctrl ]
+ choices: [ forward, listen ]
+ 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
+extends_documentation_fragment:
+- cisco.aci.aci
+- cisco.aci.annotation
+- cisco.aci.owner
+
+notes:
+- The I(tenant) and I(vrf) must exist before using this module in your playbook.
+ The M(cisco.aci.aci_tenant) and M(cisco.aci.aci_vrf) modules can be used for this.
+seealso:
+- name: APIC Management Information Model reference
+ description: More information about the internal APIC class B(pim:CtxP).
+ link: https://developer.cisco.com/docs/apic-mim-ref/
+author:
+- Tim Cragg (@timcragg)
+- Akini Ross (@akinross)
+"""
+
+EXAMPLES = r"""
+- name: Enable Multicast on a VRF
+ cisco.aci.aci_vrf_multicast:
+ host: apic
+ username: admin
+ password: SomeSecretePassword
+ tenant: ansible_tenant
+ vrf: ansible_vrf
+ state: present
+ delegate_to: localhost
+
+- name: Change Multicast PIM Settings on a VRF
+ cisco.aci.aci_vrf_multicast:
+ host: apic
+ username: admin
+ password: SomeSecretePassword
+ tenant: ansible_tenant
+ vrf: ansible_vrf
+ pim_setting:
+ mtu: 2000
+ control_state: [ fast, strict ]
+ state: present
+ delegate_to: localhost
+
+- name: Change Multicast Resource Policy on a VRF
+ cisco.aci.aci_vrf_multicast:
+ host: apic
+ username: admin
+ password: SomeSecretePassword
+ tenant: ansible_tenant
+ vrf: ansible_vrf
+ resource_policy:
+ maximum_limit: 100
+ reserved_multicast_entries: 20
+ reserved_route_map: uni/tn-ansible_test/rtmap-ansible_test
+ state: present
+ delegate_to: localhost
+
+- name: Remove Route-Map from Multicast Resource Policy on a VRF
+ cisco.aci.aci_vrf_multicast:
+ host: apic
+ username: admin
+ password: SomeSecretePassword
+ tenant: ansible_tenant
+ vrf: ansible_vrf
+ resource_policy:
+ reserved_route_map: ""
+ state: present
+ delegate_to: localhost
+
+- name: Change Multicast Any Source Multicast (ASM) Settings on a VRF
+ cisco.aci.aci_vrf_multicast:
+ host: apic
+ username: admin
+ password: SomeSecretePassword
+ tenant: ansible_tenant
+ vrf: ansible_vrf
+ any_source_multicast:
+ shared_range_route_map: uni/tn-ansible_test/rtmap-ansible_test
+ source_group_expiry_route_map: uni/tn-ansible_test/rtmap-ansible_test
+ expiry: 500
+ max_rate: 64000
+ source_ip: 1.1.1.1
+ state: present
+ delegate_to: localhost
+
+- name: Change Multicast Source Specific Multicast (SSM) Settings on a VRF
+ cisco.aci.aci_vrf_multicast:
+ host: apic
+ username: admin
+ password: SomeSecretePassword
+ tenant: ansible_tenant
+ vrf: ansible_vrf
+ source_specific_multicast:
+ group_range_route_map: uni/tn-ansible_test/rtmap-ansible_test
+ state: present
+ delegate_to: localhost
+
+- name: Change Multicast Bootstrap Router (BSR) Settings on a VRF
+ cisco.aci.aci_vrf_multicast:
+ host: apic
+ username: admin
+ password: SomeSecretePassword
+ tenant: ansible_tenant
+ vrf: ansible_vrf
+ bootstrap_router:
+ bsr_filter: uni/tn-ansible_test/rtmap-ansible_test
+ rp_updates: [ forward, listen ]
+ state: present
+ delegate_to: localhost
+
+- name: Change Multicast Auto-Rendezvous Point (Auto-RP) Settings on a VRF
+ cisco.aci.aci_vrf_multicast:
+ host: apic
+ username: admin
+ password: SomeSecretePassword
+ tenant: ansible_tenant
+ vrf: ansible_vrf
+ auto_rp:
+ ma_filter: uni/tn-ansible_test/rtmap-ansible_test
+ rp_updates: [ forward, listen ]
+ state: present
+ delegate_to: localhost
+
+- name: Disable Multicast on a VRF
+ cisco.aci.aci_vrf_multicast:
+ host: apic
+ username: admin
+ password: SomeSecretePassword
+ tenant: ansible_tenant
+ vrf: ansible_vrf
+ state: absent
+ delegate_to: localhost
+
+- name: Query Multicast Settings for a VRF
+ cisco.aci.aci_vrf_multicast:
+ host: apic
+ username: admin
+ password: SomeSecretePassword
+ tenant: ansible_tenant
+ vrf: ansible_vrf
+ state: query
+ delegate_to: localhost
+ register: query_result
+
+- name: Query Multicast Settings for all VRFs
+ cisco.aci.aci_vrf_multicast:
+ host: apic
+ username: admin
+ password: SomeSecretePassword
+ state: query
+ delegate_to: localhost
+ register: query_result
+"""
+
+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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+ 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: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class "/></imdata>'
+ 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": "",
+ "ownerTag": ""
+ }
+ }
+ }
+ ]
+ 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
+from ansible_collections.cisco.aci.plugins.module_utils.constants import PIM_SETTING_CONTROL_STATE_MAPPING
+
+
+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"]),
+ vrf=dict(type="str", aliases=["vrf_name"]),
+ pim_setting=dict(
+ type="dict",
+ options=dict(
+ mtu=dict(type="int"),
+ control_state=dict(type="list", elements="str", choices=["fast", "strict"], aliases=["control", "ctrl"]),
+ ),
+ ),
+ resource_policy=dict(
+ type="dict",
+ options=dict(
+ maximum_limit=dict(type="int", aliases=["max"]),
+ reserved_multicast_entries=dict(type="int", aliases=["rsvd"]),
+ reserved_route_map=dict(type="str", aliases=["route_map", "route_map_dn"]),
+ ),
+ ),
+ any_source_multicast=dict(
+ type="dict",
+ options=dict(
+ shared_range_route_map=dict(type="str", aliases=["shared_range_policy"]),
+ source_group_expiry_route_map=dict(type="str", aliases=["sg_expiry_route_map"]),
+ expiry=(dict(type="int", aliases=["expiry_seconds"])),
+ max_rate=(dict(type="int", aliases=["max_rate_per_second"])),
+ source_ip=(dict(type="str", aliases=["source", "source_ip_address"])),
+ ),
+ aliases=["asm", "any_source"],
+ ),
+ source_specific_multicast=dict(
+ type="dict",
+ options=dict(
+ group_range_route_map=dict(type="str", aliases=["group_range_policy"]),
+ ),
+ aliases=["ssm", "specific_source"],
+ ),
+ bootstrap_router=dict(
+ type="dict",
+ options=dict(
+ bsr_filter=dict(type="str", aliases=["filter", "route_map", "route_map_dn"]),
+ rp_updates=dict(type="list", elements="str", choices=["forward", "listen"], aliases=["control", "ctrl"]),
+ ),
+ aliases=["bsr", "bootstrap"],
+ ),
+ auto_rp=dict(
+ type="dict",
+ options=dict(
+ ma_filter=dict(type="str", aliases=["filter", "route_map", "route_map_dn"]),
+ rp_updates=dict(type="list", elements="str", choices=["forward", "listen"], aliases=["control", "ctrl"]),
+ ),
+ aliases=["auto"],
+ ),
+ state=dict(type="str", default="present", choices=["absent", "present", "query"]),
+ )
+
+ module = AnsibleModule(
+ argument_spec=argument_spec,
+ supports_check_mode=True,
+ required_if=[
+ ["state", "absent", ["tenant", "vrf"]],
+ ["state", "present", ["tenant", "vrf"]],
+ ],
+ )
+
+ aci = ACIModule(module)
+
+ tenant = module.params.get("tenant")
+ vrf = module.params.get("vrf")
+ pim_setting = module.params.get("pim_setting")
+ resource_policy = module.params.get("resource_policy")
+ any_source_multicast = module.params.get("any_source_multicast")
+ source_specific_multicast = module.params.get("source_specific_multicast")
+ bootstrap_router = module.params.get("bootstrap_router")
+ auto_rp = module.params.get("auto_rp")
+ state = module.params.get("state")
+
+ if resource_policy and resource_policy.get("reserved_multicast_entries") and resource_policy.get("reserved_route_map") is None:
+ aci.fail_json(msg="parameters are mutually exclusive: reserved_route_map|reserved_multicast_entries")
+ elif resource_policy and resource_policy.get("reserved_route_map") and not resource_policy.get("reserved_multicast_entries"):
+ aci.fail_json(msg="C(reserved_multicast_entries) must be provided and greater than 0 when C(reserved_route_map) is provided")
+
+ 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="fvCtx",
+ aci_rn="ctx-{0}".format(vrf),
+ module_object=vrf,
+ target_filter={"name": vrf},
+ ),
+ subclass_2=dict(
+ aci_class="pimCtxP",
+ aci_rn="pimctxp",
+ target_filter={"name": ""},
+ ),
+ child_classes=["pimResPol", "pimASMPatPol", "pimSSMPatPol", "pimAutoRPPol", "pimBSRPPol"],
+ )
+
+ aci.get_existing()
+
+ if state == "present":
+ existing_config = aci.existing[0] if aci.existing else {}
+ child_configs = []
+
+ resource_policy_config = dict(pimResPol=dict(attributes=dict(name=""), children=[]))
+ if resource_policy:
+ max = "unlimited" if resource_policy.get("maximum_limit") == 0 else resource_policy.get("maximum_limit")
+ if max is not None:
+ resource_policy_config["pimResPol"]["attributes"]["max"] = str(max)
+
+ reserved_route_map = resource_policy.get("reserved_route_map")
+ if reserved_route_map is not None:
+ existing_rrm = get_child_from_existing_config(existing_config, ["pimCtxP", "pimResPol", "rtdmcRsFilterToRtMapPol"])
+ rsvd = resource_policy.get("reserved_multicast_entries")
+
+ if (existing_rrm or reserved_route_map != "") and rsvd:
+ resource_policy_config["pimResPol"]["attributes"]["rsvd"] = str(rsvd)
+ elif existing_rrm and reserved_route_map == "":
+ resource_policy_config["pimResPol"]["attributes"]["rsvd"] = "undefined"
+
+ set_route_map_config(
+ existing_config,
+ resource_policy_config["pimResPol"]["children"],
+ ["pimCtxP", "pimResPol", "rtdmcRsFilterToRtMapPol"],
+ reserved_route_map,
+ )
+
+ child_configs.append(resource_policy_config)
+
+ any_source_multicast_config = dict(
+ pimASMPatPol=dict(
+ attributes=dict(name=""),
+ children=[
+ dict(pimSharedRangePol=dict(attributes=dict(name=""), children=[])),
+ dict(pimSGRangeExpPol=dict(attributes=dict(name=""), children=[])),
+ dict(pimRegTrPol=dict(attributes=dict(name=""), children=[])),
+ ],
+ )
+ )
+ if any_source_multicast:
+ if any_source_multicast.get("shared_range_route_map") is not None:
+ set_route_map_config(
+ existing_config,
+ any_source_multicast_config["pimASMPatPol"]["children"][0]["pimSharedRangePol"]["children"],
+ ["pimCtxP", "pimASMPatPol", "pimSharedRangePol", "rtdmcRsFilterToRtMapPol"],
+ any_source_multicast.get("shared_range_route_map"),
+ )
+
+ if any_source_multicast.get("source_group_expiry_route_map") is not None:
+ set_route_map_config(
+ existing_config,
+ any_source_multicast_config["pimASMPatPol"]["children"][1]["pimSGRangeExpPol"]["children"],
+ ["pimCtxP", "pimASMPatPol", "pimSGRangeExpPol", "rtdmcRsFilterToRtMapPol"],
+ any_source_multicast.get("source_group_expiry_route_map"),
+ )
+
+ expiry = any_source_multicast.get("expiry")
+ if expiry is not None:
+ sg_expiry_config = "default-timeout" if any_source_multicast.get("expiry") == 0 else any_source_multicast.get("expiry")
+ any_source_multicast_config["pimASMPatPol"]["children"][1]["pimSGRangeExpPol"]["attributes"]["sgExpItvl"] = str(sg_expiry_config)
+
+ if any_source_multicast.get("max_rate") is not None:
+ any_source_multicast_config["pimASMPatPol"]["children"][2]["pimRegTrPol"]["attributes"]["maxRate"] = str(any_source_multicast.get("max_rate"))
+
+ if any_source_multicast.get("source_ip") is not None:
+ any_source_multicast_config["pimASMPatPol"]["children"][2]["pimRegTrPol"]["attributes"]["srcIp"] = any_source_multicast.get("source_ip")
+
+ child_configs.append(any_source_multicast_config)
+
+ source_specific_multicast_config = dict(
+ pimSSMPatPol=dict(
+ attributes=dict(name=""),
+ children=[
+ dict(pimSSMRangePol=dict(attributes=dict(name=""), children=[])),
+ ],
+ )
+ )
+ if source_specific_multicast and source_specific_multicast.get("group_range_route_map") is not None:
+ set_route_map_config(
+ existing_config,
+ source_specific_multicast_config["pimSSMPatPol"]["children"][0]["pimSSMRangePol"]["children"],
+ ["pimCtxP", "pimSSMPatPol", "pimSSMRangePol", "rtdmcRsFilterToRtMapPol"],
+ source_specific_multicast.get("group_range_route_map"),
+ )
+
+ child_configs.append(source_specific_multicast_config)
+
+ if bootstrap_router:
+ bsr_config = dict(pimBSRPPol=dict(attributes=dict(name=""), children=[dict(pimBSRFilterPol=dict(attributes=dict(name=""), children=[]))]))
+ if bootstrap_router.get("bsr_filter") is not None:
+ set_route_map_config(
+ existing_config,
+ bsr_config["pimBSRPPol"]["children"][0]["pimBSRFilterPol"]["children"],
+ ["pimCtxP", "pimBSRPPol", "pimBSRFilterPol", "rtdmcRsFilterToRtMapPol"],
+ bootstrap_router.get("bsr_filter"),
+ )
+
+ rp_updates = bootstrap_router.get("rp_updates")
+ if rp_updates is not None:
+ bsr_config["pimBSRPPol"]["attributes"]["ctrl"] = ",".join(sorted(rp_updates))
+
+ child_configs.append(bsr_config)
+
+ if auto_rp:
+ auto_rp_config = dict(pimAutoRPPol=dict(attributes=dict(name=""), children=[dict(pimMAFilterPol=dict(attributes=dict(name=""), children=[]))]))
+
+ if auto_rp.get("ma_filter") is not None:
+ set_route_map_config(
+ existing_config,
+ auto_rp_config["pimAutoRPPol"]["children"][0]["pimMAFilterPol"]["children"],
+ ["pimCtxP", "pimAutoRPPol", "pimMAFilterPol", "rtdmcRsFilterToRtMapPol"],
+ auto_rp.get("ma_filter"),
+ )
+
+ rp_updates = auto_rp.get("rp_updates")
+ if rp_updates is not None:
+ auto_rp_config["pimAutoRPPol"]["attributes"]["ctrl"] = ",".join(sorted(rp_updates))
+
+ child_configs.append(auto_rp_config)
+
+ mtu = None
+ control_state = None
+ if pim_setting:
+ mtu = pim_setting.get("mtu")
+ control_state = (
+ ",".join(sorted([PIM_SETTING_CONTROL_STATE_MAPPING.get(v) for v in pim_setting.get("control_state")]))
+ if pim_setting.get("control_state") is not None
+ else None
+ )
+
+ aci.payload(
+ aci_class="pimCtxP",
+ class_config=dict(mtu=mtu, ctrl=control_state),
+ child_configs=child_configs,
+ )
+
+ aci.get_diff(aci_class="pimCtxP")
+
+ aci.post_config()
+
+ elif state == "absent":
+ aci.delete_config()
+
+ aci.exit_json()
+
+
+def get_child_from_existing_config(config, class_names):
+ parent = class_names[0]
+ class_names.remove(parent)
+
+ for child in config.get(parent, {}).get("children", []):
+ if len(class_names) == 1 and class_names[0] in child.keys():
+ return child
+ elif child.get(class_names[0], {}).get("children"):
+ return get_child_from_existing_config(child, class_names)
+
+
+def set_route_map_config(existing_config, new_config, class_names, route_map):
+ existing_route_map = get_child_from_existing_config(existing_config, class_names)
+ if route_map == "" and existing_route_map:
+ new_config.append(dict(rtdmcRsFilterToRtMapPol=dict(attributes=dict(tDn=route_map, status="deleted"))))
+ elif route_map:
+ new_config.append(dict(rtdmcRsFilterToRtMapPol=dict(attributes=dict(tDn=route_map))))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ansible_collections/cisco/aci/plugins/modules/aci_vzany_to_contract.py b/ansible_collections/cisco/aci/plugins/modules/aci_vzany_to_contract.py
index f2632307c..411f63936 100644
--- a/ansible_collections/cisco/aci/plugins/modules/aci_vzany_to_contract.py
+++ b/ansible_collections/cisco/aci/plugins/modules/aci_vzany_to_contract.py
@@ -12,7 +12,7 @@ ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported
DOCUMENTATION = r"""
---
module: aci_vzany_to_contract
-short_description: Attach contracts to vzAny (vz:RsAnyToProv, vz:RsAnyToCons, vz:RsAnyToConsIf)
+short_description: Attach contracts to vzAny (vz:RsAnyToProv, vz:RsAnyToCons, and vz:RsAnyToConsIf)
description:
- Bind contracts to vzAny on Cisco ACI fabrics.
options:
@@ -54,7 +54,7 @@ seealso:
- module: cisco.aci.aci_vrf
- module: cisco.aci.aci_contract
- name: APIC Management Information Model reference
- description: More information about the internal APIC classes B(fv:RsCons) and B(fv:RsProv).
+ description: More information about the internal APIC classes B(vz:RsAnyToProv), B(vz:RsAnyToCons), and B(vz:RsAnyToConsIf).
link: https://developer.cisco.com/docs/apic-mim-ref/
author:
- Marcel Zehnder (@maercu)