Skip to content

Commit 8a4d9d1

Browse files
timcraggshrsr
authored andcommitted
[ignore] Addition of concrete device modules and their test files
1 parent 355bd72 commit 8a4d9d1

File tree

13 files changed

+1627
-7
lines changed

13 files changed

+1627
-7
lines changed

plugins/modules/aci_l4l7_concrete_device.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#!/usr/bin/python
22
# -*- coding: utf-8 -*-
33

4+
# Copyright: (c) 2025, Tim Cragg (@timcragg)
45
# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
56

67
from __future__ import absolute_import, division, print_function
Lines changed: 353 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,353 @@
1+
#!/usr/bin/python
2+
# -*- coding: utf-8 -*-
3+
4+
# Copyright: (c) 2025, Tim Cragg (@timcragg)
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": "community"}
12+
13+
DOCUMENTATION = r"""
14+
---
15+
module: aci_l4l7_concrete_interface
16+
short_description: Manage L4-L7 Concrete Interfaces (vns:CIf)
17+
description:
18+
- Manage Layer 4-7 (L4-L7) Concrete Interfaces.
19+
options:
20+
tenant:
21+
description:
22+
- The name of an existing tenant.
23+
type: str
24+
aliases: [ tenant_name ]
25+
device:
26+
description:
27+
- The name of an existing logical device.
28+
type: str
29+
concrete_device:
30+
description:
31+
- The name of an existing concrete device.
32+
type: str
33+
name:
34+
description:
35+
- The name of the concrete interface.
36+
type: str
37+
aliases: [ concrete_interface ]
38+
pod_id:
39+
description:
40+
- The unique identifier for the pod where the concrete interface is located.
41+
type: int
42+
node_id:
43+
description:
44+
- The unique identifier for the node where the concrete interface is located.
45+
- For Ports and Port-channels, this is represented as a single node ID.
46+
- For virtual Port Channels (vPCs), this is represented as a hyphen-separated pair of node IDs, such as "201-202".
47+
type: str
48+
path_ep:
49+
description:
50+
- The path to the physical interface.
51+
- For single ports, this is the port name, e.g. "eth1/15".
52+
- For Port-channels and vPCs, this is the Interface Policy Group name.
53+
type: str
54+
vnic_name:
55+
description:
56+
- The concrete interface vNIC name.
57+
type: str
58+
state:
59+
description:
60+
- Use C(present) or C(absent) for adding or removing.
61+
- Use C(query) for listing an object or multiple objects.
62+
type: str
63+
choices: [ absent, present, query ]
64+
default: present
65+
extends_documentation_fragment:
66+
- cisco.aci.aci
67+
- cisco.aci.annotation
68+
notes:
69+
- The I(tenant), I(device) and I(concrete_device) must exist before using this module in your playbook.
70+
The M(cisco.aci.aci_tenant), M(cisco.aci.aci_l4l7_device) and M(cisco.aci.aci_l4l7_concrete_device) modules can be used for this.
71+
seealso:
72+
- module: aci_l4l7_device
73+
- module: aci_l4l7_concrete_device
74+
- name: APIC Management Information Model reference
75+
description: More information about the internal APIC class B(vns:CIf)
76+
link: https://developer.cisco.com/docs/apic-mim-ref/
77+
author:
78+
- Tim Cragg (@timcragg)
79+
"""
80+
81+
EXAMPLES = r"""
82+
- name: Add a new concrete interface on a single port
83+
cisco.aci.aci_l4l7_concrete_interface:
84+
host: apic
85+
username: admin
86+
password: SomeSecretPassword
87+
tenant: my_tenant
88+
device: my_device
89+
concrete_device: my_concrete_device
90+
name: my_concrete_interface
91+
pod_id: 1
92+
node_id: 201
93+
path_ep: eth1/16
94+
state: present
95+
delegate_to: localhost
96+
97+
- name: Add a new concrete interface on a vPC
98+
cisco.aci.aci_l4l7_concrete_interface:
99+
host: apic
100+
username: admin
101+
password: SomeSecretPassword
102+
tenant: my_tenant
103+
device: my_device
104+
concrete_device: my_concrete_device
105+
name: my_concrete_interface
106+
pod_id: 1
107+
node_id: 201-202
108+
path_ep: my_vpc_ipg
109+
state: present
110+
delegate_to: localhost
111+
112+
- name: Query a concrete interface
113+
cisco.aci.aci_l4l7_service_graph_template:
114+
host: apic
115+
username: admin
116+
password: SomeSecretPassword
117+
tenant: my_tenant
118+
device: my_device
119+
concrete_device: my_concrete_device
120+
name: my_concrete_interface
121+
pod_id: 1
122+
node_id: 201-202
123+
path_ep: my_vpc_ipg
124+
state: query
125+
delegate_to: localhost
126+
register: query_result
127+
128+
- name: Query all concrete interfaces
129+
cisco.aci.aci_l4l7_service_graph_template:
130+
host: apic
131+
username: admin
132+
password: SomeSecretPassword
133+
state: query
134+
delegate_to: localhost
135+
register: query_result
136+
137+
- name: Delete a concrete interface
138+
cisco.aci.aci_l4l7_concrete_interface:
139+
host: apic
140+
username: admin
141+
password: SomeSecretPassword
142+
tenant: my_tenant
143+
device: my_device
144+
concrete_device: my_concrete_device
145+
name: my_concrete_interface
146+
state: absent
147+
delegate_to: localhost
148+
"""
149+
150+
RETURN = r"""
151+
current:
152+
description: The existing configuration from the APIC after the module has finished
153+
returned: success
154+
type: list
155+
sample:
156+
[
157+
{
158+
"fvTenant": {
159+
"attributes": {
160+
"descr": "Production environment",
161+
"dn": "uni/tn-production",
162+
"name": "production",
163+
"nameAlias": "",
164+
"ownerKey": "",
165+
"ownerTag": ""
166+
}
167+
}
168+
}
169+
]
170+
error:
171+
description: The error information as returned from the APIC
172+
returned: failure
173+
type: dict
174+
sample:
175+
{
176+
"code": "122",
177+
"text": "unknown managed object class foo"
178+
}
179+
raw:
180+
description: The raw output returned by the APIC REST API (xml or json)
181+
returned: parse error
182+
type: str
183+
sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
184+
sent:
185+
description: The actual/minimal configuration pushed to the APIC
186+
returned: info
187+
type: list
188+
sample:
189+
{
190+
"fvTenant": {
191+
"attributes": {
192+
"descr": "Production environment"
193+
}
194+
}
195+
}
196+
previous:
197+
description: The original configuration from the APIC before the module has started
198+
returned: info
199+
type: list
200+
sample:
201+
[
202+
{
203+
"fvTenant": {
204+
"attributes": {
205+
"descr": "Production",
206+
"dn": "uni/tn-production",
207+
"name": "production",
208+
"nameAlias": "",
209+
"ownerKey": "",
210+
"ownerTag": ""
211+
}
212+
}
213+
}
214+
]
215+
proposed:
216+
description: The assembled configuration from the user-provided parameters
217+
returned: info
218+
type: dict
219+
sample:
220+
{
221+
"fvTenant": {
222+
"attributes": {
223+
"descr": "Production environment",
224+
"name": "production"
225+
}
226+
}
227+
}
228+
filter_string:
229+
description: The filter string used for the request
230+
returned: failure or debug
231+
type: str
232+
sample: ?rsp-prop-include=config-only
233+
method:
234+
description: The HTTP method used for the request to the APIC
235+
returned: failure or debug
236+
type: str
237+
sample: POST
238+
response:
239+
description: The HTTP response from the APIC
240+
returned: failure or debug
241+
type: str
242+
sample: OK (30 bytes)
243+
status:
244+
description: The HTTP status from the APIC
245+
returned: failure or debug
246+
type: int
247+
sample: 200
248+
url:
249+
description: The HTTP url used for the request to the APIC
250+
returned: failure or debug
251+
type: str
252+
sample: https://10.11.12.13/api/mo/uni/tn-production.json
253+
"""
254+
255+
256+
from ansible.module_utils.basic import AnsibleModule
257+
from ansible_collections.cisco.aci.plugins.module_utils.aci import ACIModule, aci_argument_spec, aci_annotation_spec
258+
259+
260+
def main():
261+
argument_spec = aci_argument_spec()
262+
argument_spec.update(aci_annotation_spec())
263+
argument_spec.update(
264+
tenant=dict(type="str", aliases=["tenant_name"]),
265+
device=dict(type="str"),
266+
concrete_device=dict(type="str"),
267+
state=dict(type="str", default="present", choices=["absent", "present", "query"]),
268+
name=dict(type="str", aliases=["concrete_interface"]),
269+
pod_id=dict(type="int"),
270+
node_id=dict(type="str"),
271+
path_ep=dict(type="str"),
272+
vnic_name=dict(type="str"),
273+
)
274+
275+
module = AnsibleModule(
276+
argument_spec=argument_spec,
277+
supports_check_mode=True,
278+
required_if=[
279+
["state", "absent", ["tenant", "device", "concrete_device", "name"]],
280+
["state", "present", ["tenant", "device", "concrete_device", "name", "pod_id", "node_id", "path_ep"]],
281+
],
282+
)
283+
284+
tenant = module.params.get("tenant")
285+
state = module.params.get("state")
286+
device = module.params.get("device")
287+
concrete_device = module.params.get("concrete_device")
288+
name = module.params.get("name")
289+
pod_id = module.params.get("pod_id")
290+
node_id = module.params.get("node_id")
291+
path_ep = module.params.get("path_ep")
292+
vnic_name = module.params.get("vnic_name")
293+
294+
aci = ACIModule(module)
295+
296+
aci.construct_url(
297+
root_class=dict(
298+
aci_class="fvTenant",
299+
aci_rn="tn-{0}".format(tenant),
300+
module_object=tenant,
301+
target_filter={"name": tenant},
302+
),
303+
subclass_1=dict(
304+
aci_class="vnsLDevVip",
305+
aci_rn="lDevVip-{0}".format(device),
306+
module_object=device,
307+
target_filter={"name": device},
308+
),
309+
subclass_2=dict(
310+
aci_class="vnsCDev",
311+
aci_rn="cDev-{0}".format(concrete_device),
312+
module_object=concrete_device,
313+
target_filter={"name": concrete_device},
314+
),
315+
subclass_3=dict(
316+
aci_class="vnsCIf",
317+
aci_rn="cIf-[{0}]".format(name),
318+
module_object=name,
319+
target_filter={"name": name},
320+
),
321+
child_classes=["vnsRsCIfPathAtt"],
322+
)
323+
324+
aci.get_existing()
325+
326+
if state == "present":
327+
path_dn = "topology/pod-{0}/{1}-{2}/pathep-[{3}]".format(pod_id, "protpaths" if "-" in node_id else "paths", node_id, path_ep)
328+
aci.payload(
329+
aci_class="vnsCIf",
330+
class_config=dict(
331+
name=name,
332+
vnicName=vnic_name,
333+
),
334+
child_configs=[
335+
dict(
336+
vnsRsCIfPathAtt=dict(
337+
attributes=dict(tDn=path_dn),
338+
),
339+
),
340+
],
341+
)
342+
aci.get_diff(aci_class="vnsCIf")
343+
344+
aci.post_config()
345+
346+
elif state == "absent":
347+
aci.delete_config()
348+
349+
aci.exit_json()
350+
351+
352+
if __name__ == "__main__":
353+
main()

0 commit comments

Comments
 (0)