ansible  2.9.27
About: Ansible is an IT Configuration Management, Deployment \
About: Ansible (2.x) is an IT Configuration Management, Deployment & Orchestration tool.
ansible download page.
  Fossies Dox: ansible-2.9.27.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

aci_filter_entry.py
Go to the documentation of this file.
1#!/usr/bin/python
2# -*- coding: utf-8 -*-
3
4# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
5
6from __future__ import absolute_import, division, print_function
7__metaclass__ = type
8
9ANSIBLE_METADATA = {'metadata_version': '1.1',
10 'status': ['preview'],
11 'supported_by': 'certified'}
12
13DOCUMENTATION = r'''
14---
15module: aci_filter_entry
16short_description: Manage filter entries (vz:Entry)
17description:
18- Manage filter entries for a filter on Cisco ACI fabrics.
19version_added: '2.4'
20options:
21 arp_flag:
22 description:
23 - The arp flag to use when the ether_type is arp.
24 - The APIC defaults to C(unspecified) when unset during creation.
25 type: str
26 choices: [ arp_reply, arp_request, unspecified ]
27 description:
28 description:
29 - Description for the Filter Entry.
30 type: str
31 aliases: [ descr ]
32 dst_port:
33 description:
34 - Used to set both destination start and end ports to the same value when ip_protocol is tcp or udp.
35 - Accepted values are any valid TCP/UDP port range.
36 - The APIC defaults to C(unspecified) when unset during creation.
37 type: str
38 dst_port_end:
39 description:
40 - Used to set the destination end port when ip_protocol is tcp or udp.
41 - Accepted values are any valid TCP/UDP port range.
42 - The APIC defaults to C(unspecified) when unset during creation.
43 type: str
44 dst_port_start:
45 description:
46 - Used to set the destination start port when ip_protocol is tcp or udp.
47 - Accepted values are any valid TCP/UDP port range.
48 - The APIC defaults to C(unspecified) when unset during creation.
49 type: str
50 entry:
51 description:
52 - Then name of the Filter Entry.
53 type: str
54 aliases: [ entry_name, filter_entry, name ]
55 ether_type:
56 description:
57 - The Ethernet type.
58 - The APIC defaults to C(unspecified) when unset during creation.
59 type: str
60 choices: [ arp, fcoe, ip, mac_security, mpls_ucast, trill, unspecified ]
61 filter:
62 description:
63 - The name of Filter that the entry should belong to.
64 type: str
65 aliases: [ filter_name ]
66 icmp_msg_type:
67 description:
68 - ICMPv4 message type; used when ip_protocol is icmp.
69 - The APIC defaults to C(unspecified) when unset during creation.
70 type: str
71 choices: [ dst_unreachable, echo, echo_reply, src_quench, time_exceeded, unspecified ]
72 icmp6_msg_type:
73 description:
74 - ICMPv6 message type; used when ip_protocol is icmpv6.
75 - The APIC defaults to C(unspecified) when unset during creation.
76 type: str
77 choices: [ dst_unreachable, echo_request, echo_reply, neighbor_advertisement, neighbor_solicitation, redirect, time_exceeded, unspecified ]
78 ip_protocol:
79 description:
80 - The IP Protocol type when ether_type is ip.
81 - The APIC defaults to C(unspecified) when unset during creation.
82 type: str
83 choices: [ eigrp, egp, icmp, icmpv6, igmp, igp, l2tp, ospfigp, pim, tcp, udp, unspecified ]
84 state:
85 description:
86 - present, absent, query
87 type: str
88 default: present
89 choices: [ absent, present, query ]
90 stateful:
91 description:
92 - Determines the statefulness of the filter entry.
93 type: bool
94 tenant:
95 description:
96 - The name of the tenant.
97 type: str
98 aliases: [ tenant_name ]
99extends_documentation_fragment: aci
100notes:
101- The C(tenant) and C(filter) used must exist before using this module in your playbook.
102 The M(aci_tenant) and M(aci_filter) modules can be used for this.
103seealso:
104- module: aci_tenant
105- module: aci_filter
106- name: APIC Management Information Model reference
107 description: More information about the internal APIC class B(vz:Entry).
108 link: https://developer.cisco.com/docs/apic-mim-ref/
109author:
110- Jacob McGill (@jmcgill298)
111'''
112
113EXAMPLES = r'''
114- aci_filter_entry:
115 host: "{{ inventory_hostname }}"
116 username: "{{ user }}"
117 password: "{{ pass }}"
118 state: "{{ state }}"
119 entry: "{{ entry }}"
120 tenant: "{{ tenant }}"
121 ether_name: "{{ ether_name }}"
122 icmp_msg_type: "{{ icmp_msg_type }}"
123 filter: "{{ filter }}"
124 descr: "{{ descr }}"
125 delegate_to: localhost
126'''
127
128RETURN = r'''
129current:
130 description: The existing configuration from the APIC after the module has finished
131 returned: success
132 type: list
133 sample:
134 [
135 {
136 "fvTenant": {
137 "attributes": {
138 "descr": "Production environment",
139 "dn": "uni/tn-production",
140 "name": "production",
141 "nameAlias": "",
142 "ownerKey": "",
143 "ownerTag": ""
144 }
145 }
146 }
147 ]
148error:
149 description: The error information as returned from the APIC
150 returned: failure
151 type: dict
152 sample:
153 {
154 "code": "122",
155 "text": "unknown managed object class foo"
156 }
157raw:
158 description: The raw output returned by the APIC REST API (xml or json)
159 returned: parse error
160 type: str
161 sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>'
162sent:
163 description: The actual/minimal configuration pushed to the APIC
164 returned: info
165 type: list
166 sample:
167 {
168 "fvTenant": {
169 "attributes": {
170 "descr": "Production environment"
171 }
172 }
173 }
174previous:
175 description: The original configuration from the APIC before the module has started
176 returned: info
177 type: list
178 sample:
179 [
180 {
181 "fvTenant": {
182 "attributes": {
183 "descr": "Production",
184 "dn": "uni/tn-production",
185 "name": "production",
186 "nameAlias": "",
187 "ownerKey": "",
188 "ownerTag": ""
189 }
190 }
191 }
192 ]
193proposed:
194 description: The assembled configuration from the user-provided parameters
195 returned: info
196 type: dict
197 sample:
198 {
199 "fvTenant": {
200 "attributes": {
201 "descr": "Production environment",
202 "name": "production"
203 }
204 }
205 }
206filter_string:
207 description: The filter string used for the request
208 returned: failure or debug
209 type: str
210 sample: ?rsp-prop-include=config-only
211method:
212 description: The HTTP method used for the request to the APIC
213 returned: failure or debug
214 type: str
215 sample: POST
216response:
217 description: The HTTP response from the APIC
218 returned: failure or debug
219 type: str
220 sample: OK (30 bytes)
221status:
222 description: The HTTP status from the APIC
223 returned: failure or debug
224 type: int
225 sample: 200
226url:
227 description: The HTTP url used for the request to the APIC
228 returned: failure or debug
229 type: str
230 sample: https://10.11.12.13/api/mo/uni/tn-production.json
231'''
232
233from ansible.module_utils.basic import AnsibleModule
234from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec
235
236VALID_ARP_FLAGS = ['arp_reply', 'arp_request', 'unspecified']
237VALID_ETHER_TYPES = ['arp', 'fcoe', 'ip', 'mac_security', 'mpls_ucast', 'trill', 'unspecified']
238VALID_ICMP_TYPES = ['dst_unreachable', 'echo', 'echo_reply', 'src_quench', 'time_exceeded', 'unspecified']
239VALID_ICMP6_TYPES = ['dst_unreachable', 'echo_request', 'echo_reply', 'neighbor_advertisement',
240 'neighbor_solicitation', 'redirect', 'time_exceeded', 'unspecified']
241VALID_IP_PROTOCOLS = ['eigrp', 'egp', 'icmp', 'icmpv6', 'igmp', 'igp', 'l2tp', 'ospfigp', 'pim', 'tcp', 'udp', 'unspecified']
242
243# mapping dicts are used to normalize the proposed data to what the APIC expects, which will keep diffs accurate
244ARP_FLAG_MAPPING = dict(arp_reply='reply', arp_request='req', unspecified=None)
245FILTER_PORT_MAPPING = {'443': 'https', '25': 'smtp', '80': 'http', '20': 'ftpData', '53': 'dns', '110': 'pop3', '554': 'rtsp'}
246ICMP_MAPPING = {'dst_unreachable': 'dst-unreach', 'echo': 'echo', 'echo_reply': 'echo-rep', 'src_quench': 'src-quench',
247 'time_exceeded': 'time-exceeded', 'unspecified': 'unspecified', 'echo-rep': 'echo-rep', 'dst-unreach': 'dst-unreach'}
248ICMP6_MAPPING = dict(dst_unreachable='dst-unreach', echo_request='echo-req', echo_reply='echo-rep', neighbor_advertisement='nbr-advert',
249 neighbor_solicitation='nbr-solicit', redirect='redirect', time_exceeded='time-exceeded', unspecified='unspecified')
250
251
252def main():
253 argument_spec = aci_argument_spec()
254 argument_spec.update(
255 arp_flag=dict(type='str', choices=VALID_ARP_FLAGS),
256 description=dict(type='str', aliases=['descr']),
257 dst_port=dict(type='str'),
258 dst_port_end=dict(type='str'),
259 dst_port_start=dict(type='str'),
260 entry=dict(type='str', aliases=['entry_name', 'filter_entry', 'name']), # Not required for querying all objects
261 ether_type=dict(choices=VALID_ETHER_TYPES, type='str'),
262 filter=dict(type='str', aliases=['filter_name']), # Not required for querying all objects
263 icmp_msg_type=dict(type='str', choices=VALID_ICMP_TYPES),
264 icmp6_msg_type=dict(type='str', choices=VALID_ICMP6_TYPES),
265 ip_protocol=dict(choices=VALID_IP_PROTOCOLS, type='str'),
266 state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
267 stateful=dict(type='bool'),
268 tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects
269 )
270
271 module = AnsibleModule(
272 argument_spec=argument_spec,
273 supports_check_mode=True,
274 required_if=[
275 ['state', 'absent', ['entry', 'filter', 'tenant']],
276 ['state', 'present', ['entry', 'filter', 'tenant']],
277 ],
278 )
279
280 aci = ACIModule(module)
281
282 arp_flag = module.params['arp_flag']
283 if arp_flag is not None:
284 arp_flag = ARP_FLAG_MAPPING[arp_flag]
285 description = module.params['description']
286 dst_port = module.params['dst_port']
287 if dst_port in FILTER_PORT_MAPPING.keys():
288 dst_port = FILTER_PORT_MAPPING[dst_port]
289 dst_end = module.params['dst_port_end']
290 if dst_end in FILTER_PORT_MAPPING.keys():
291 dst_end = FILTER_PORT_MAPPING[dst_end]
292 dst_start = module.params['dst_port_start']
293 if dst_start in FILTER_PORT_MAPPING.keys():
294 dst_start = FILTER_PORT_MAPPING[dst_start]
295 entry = module.params['entry']
296 ether_type = module.params['ether_type']
297 filter_name = module.params['filter']
298 icmp_msg_type = module.params['icmp_msg_type']
299 if icmp_msg_type is not None:
300 icmp_msg_type = ICMP_MAPPING[icmp_msg_type]
301 icmp6_msg_type = module.params['icmp6_msg_type']
302 if icmp6_msg_type is not None:
303 icmp6_msg_type = ICMP6_MAPPING[icmp6_msg_type]
304 ip_protocol = module.params['ip_protocol']
305 state = module.params['state']
306 stateful = aci.boolean(module.params['stateful'])
307 tenant = module.params['tenant']
308
309 # validate that dst_port is not passed with dst_start or dst_end
310 if dst_port is not None and (dst_end is not None or dst_start is not None):
311 module.fail_json(msg="Parameter 'dst_port' cannot be used with 'dst_end' and 'dst_start'")
312 elif dst_port is not None:
313 dst_end = dst_port
314 dst_start = dst_port
315
316 aci.construct_url(
317 root_class=dict(
318 aci_class='fvTenant',
319 aci_rn='tn-{0}'.format(tenant),
320 module_object=tenant,
321 target_filter={'name': tenant},
322 ),
323 subclass_1=dict(
324 aci_class='vzFilter',
325 aci_rn='flt-{0}'.format(filter_name),
326 module_object=filter_name,
327 target_filter={'name': filter_name},
328 ),
329 subclass_2=dict(
330 aci_class='vzEntry',
331 aci_rn='e-{0}'.format(entry),
332 module_object=entry,
333 target_filter={'name': entry},
334 ),
335 )
336
337 aci.get_existing()
338
339 if state == 'present':
340 aci.payload(
341 aci_class='vzEntry',
342 class_config=dict(
343 arpOpc=arp_flag,
344 descr=description,
345 dFromPort=dst_start,
346 dToPort=dst_end,
347 etherT=ether_type,
348 icmpv4T=icmp_msg_type,
349 icmpv6T=icmp6_msg_type,
350 name=entry,
351 prot=ip_protocol,
352 stateful=stateful,
353 ),
354 )
355
356 aci.get_diff(aci_class='vzEntry')
357
358 aci.post_config()
359
360 elif state == 'absent':
361 aci.delete_config()
362
363 aci.exit_json()
364
365
366if __name__ == "__main__":
367 main()
def main()