Skip to content

Commit 98d1311

Browse files
sajaganalhercot
authored andcommitted
[minor_change] Added modules to manage Endpoint IP and MAC Tags
1 parent 2eced4f commit 98d1311

File tree

6 files changed

+1461
-0
lines changed

6 files changed

+1461
-0
lines changed
Lines changed: 300 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,300 @@
1+
#!/usr/bin/python
2+
# -*- coding: utf-8 -*-
3+
4+
# Copyright: (c) 2025, Sabari Jaganathan <sajagana@cisco.com>
5+
# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
6+
7+
from __future__ import absolute_import, division, print_function
8+
9+
__metaclass__ = type
10+
11+
ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported_by": "certified"}
12+
13+
DOCUMENTATION = r"""
14+
---
15+
module: aci_endpoint_ip_tag
16+
short_description: Manage Endpoint IP Tag (fv:EpIpTag)
17+
description:
18+
- Manage Endpoint IP Tag on Cisco ACI fabrics.
19+
options:
20+
tenant:
21+
description:
22+
- The name of the Tenant.
23+
type: str
24+
name:
25+
description:
26+
- The name of the Endpoint IP Tag.
27+
type: str
28+
endpoint_ip_address:
29+
description:
30+
- The IPv4 or IPv6 address of the Endpoint IP Tag.
31+
type: str
32+
aliases: [ ip_addr ]
33+
vrf:
34+
description:
35+
- The name of the VRF.
36+
type: str
37+
aliases: [ vrf_name ]
38+
name_alias:
39+
description:
40+
- The alias for the current object. This relates to the nameAlias field in ACI.
41+
type: str
42+
state:
43+
description:
44+
- Use C(present) or C(absent) for adding or removing.
45+
- Use C(query) for listing an object or multiple objects.
46+
type: str
47+
choices: [ absent, present, query ]
48+
default: present
49+
extends_documentation_fragment:
50+
- cisco.aci.aci
51+
- cisco.aci.annotation
52+
- cisco.aci.owner
53+
54+
seealso:
55+
- name: APIC Management Information Model reference
56+
description: More information about the internal APIC class B(fv:EpIpTag).
57+
link: https://developer.cisco.com/docs/apic-mim-ref/
58+
author:
59+
- Sabari Jaganathan (@sajagana)
60+
"""
61+
62+
EXAMPLES = r"""
63+
- name: Add an IP Tag
64+
cisco.aci.aci_endpoint_ip_tag:
65+
host: apic
66+
username: admin
67+
password: SomeSecretPassword
68+
tenant: endpoint_tenant
69+
endpoint_ip_address: "1.1.1.1"
70+
vrf: endpoint_vrf
71+
name: "1.1.1.1"
72+
name_alias: endpoint_ip_tag
73+
state: present
74+
75+
- name: Update an IP Tag
76+
cisco.aci.aci_endpoint_ip_tag:
77+
host: apic
78+
username: admin
79+
password: SomeSecretPassword
80+
tenant: endpoint_tenant
81+
endpoint_ip_address: "1.1.1.1"
82+
vrf: endpoint_vrf
83+
name: "1.1.1.1"
84+
name_alias: endpoint_ip_tag_updated
85+
state: present
86+
87+
- name: Query an IP Tag with specific IP and VRF
88+
cisco.aci.aci_endpoint_ip_tag:
89+
host: apic
90+
username: admin
91+
password: SomeSecretPassword
92+
endpoint_ip_address: "1.1.1.1"
93+
vrf: endpoint_vrf
94+
state: query
95+
register: query_one
96+
97+
- name: Query all IP Tags
98+
cisco.aci.aci_endpoint_ip_tag:
99+
host: apic
100+
username: admin
101+
password: SomeSecretPassword
102+
state: query
103+
register: query_all
104+
105+
- name: Delete an IP Tag
106+
cisco.aci.aci_endpoint_ip_tag:
107+
host: apic
108+
username: admin
109+
password: SomeSecretPassword
110+
tenant: endpoint_tenant
111+
endpoint_ip_address: "1.1.1.1"
112+
vrf: endpoint_vrf
113+
state: present
114+
"""
115+
116+
RETURN = r"""
117+
current:
118+
description: The existing configuration from the APIC after the module has finished
119+
returned: success
120+
type: list
121+
sample:
122+
[
123+
{
124+
"fvTenant": {
125+
"attributes": {
126+
"descr": "Production environment",
127+
"dn": "uni/tn-production",
128+
"name": "production",
129+
"nameAlias": "",
130+
"ownerKey": "",
131+
"ownerTag": ""
132+
}
133+
}
134+
}
135+
]
136+
error:
137+
description: The error information as returned from the APIC
138+
returned: failure
139+
type: dict
140+
sample:
141+
{
142+
"code": "122",
143+
"text": "unknown managed object class foo"
144+
}
145+
raw:
146+
description: The raw output returned by the APIC REST API (xml or json)
147+
returned: parse error
148+
type: str
149+
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
150+
sent:
151+
description: The actual/minimal configuration pushed to the APIC
152+
returned: info
153+
type: list
154+
sample:
155+
{
156+
"fvTenant": {
157+
"attributes": {
158+
"descr": "Production environment"
159+
}
160+
}
161+
}
162+
previous:
163+
description: The original configuration from the APIC before the module has started
164+
returned: info
165+
type: list
166+
sample:
167+
[
168+
{
169+
"fvTenant": {
170+
"attributes": {
171+
"descr": "Production",
172+
"dn": "uni/tn-production",
173+
"name": "production",
174+
"nameAlias": "",
175+
"ownerKey": "",
176+
"ownerTag": ""
177+
}
178+
}
179+
}
180+
]
181+
proposed:
182+
description: The assembled configuration from the user-provided parameters
183+
returned: info
184+
type: dict
185+
sample:
186+
{
187+
"fvTenant": {
188+
"attributes": {
189+
"descr": "Production environment",
190+
"name": "production"
191+
}
192+
}
193+
}
194+
filter_string:
195+
description: The filter string used for the request
196+
returned: failure or debug
197+
type: str
198+
sample: ?rsp-prop-include=config-only
199+
method:
200+
description: The HTTP method used for the request to the APIC
201+
returned: failure or debug
202+
type: str
203+
sample: POST
204+
response:
205+
description: The HTTP response from the APIC
206+
returned: failure or debug
207+
type: str
208+
sample: OK (30 bytes)
209+
status:
210+
description: The HTTP status from the APIC
211+
returned: failure or debug
212+
type: int
213+
sample: 200
214+
url:
215+
description: The HTTP url used for the request to the APIC
216+
returned: failure or debug
217+
type: str
218+
sample: https://10.11.12.13/api/mo/uni/tn-production.json
219+
"""
220+
221+
from ansible.module_utils.basic import AnsibleModule
222+
from ansible_collections.cisco.aci.plugins.module_utils.aci import ACIModule, aci_argument_spec, aci_annotation_spec, aci_owner_spec
223+
224+
225+
def main():
226+
argument_spec = aci_argument_spec()
227+
argument_spec.update(aci_annotation_spec())
228+
argument_spec.update(aci_owner_spec())
229+
argument_spec.update(
230+
tenant=dict(type="str"),
231+
name=dict(type="str"),
232+
endpoint_ip_address=dict(type="str", aliases=["ip_addr"]),
233+
vrf=dict(type="str", aliases=["vrf_name"]),
234+
name_alias=dict(type="str"),
235+
state=dict(type="str", default="present", choices=["absent", "present", "query"]),
236+
)
237+
238+
module = AnsibleModule(
239+
argument_spec=argument_spec,
240+
supports_check_mode=True,
241+
required_if=[
242+
["state", "absent", ["tenant", "vrf", "endpoint_ip_address"]],
243+
["state", "present", ["tenant", "vrf", "endpoint_ip_address"]],
244+
],
245+
)
246+
247+
aci = ACIModule(module)
248+
249+
tenant = module.params.get("tenant")
250+
endpoint_ip_address = module.params.get("endpoint_ip_address")
251+
vrf = module.params.get("vrf")
252+
name = module.params.get("name")
253+
name_alias = module.params.get("name_alias")
254+
annotation = module.params.get("annotation")
255+
state = module.params.get("state")
256+
257+
aci = ACIModule(module)
258+
259+
aci.construct_url(
260+
root_class=dict(
261+
aci_class="fvTenant",
262+
aci_rn="tn-{0}".format(tenant),
263+
),
264+
subclass_1=dict(
265+
aci_class="fvEpTags",
266+
aci_rn="eptags",
267+
),
268+
subclass_2=dict(
269+
aci_class="fvEpIpTag",
270+
aci_rn="epiptag-[{0}]-{1}".format(endpoint_ip_address, vrf),
271+
target_filter=dict(ip=endpoint_ip_address, ctxName=vrf),
272+
),
273+
)
274+
275+
aci.get_existing()
276+
277+
if state == "present":
278+
aci.payload(
279+
aci_class="fvEpIpTag",
280+
class_config=dict(
281+
annotation=annotation,
282+
ctxName=vrf,
283+
ip=endpoint_ip_address,
284+
name=name,
285+
nameAlias=name_alias,
286+
),
287+
)
288+
289+
aci.get_diff(aci_class="fvEpIpTag")
290+
291+
aci.post_config()
292+
293+
elif state == "absent":
294+
aci.delete_config()
295+
296+
aci.exit_json()
297+
298+
299+
if __name__ == "__main__":
300+
main()

0 commit comments

Comments
 (0)