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)  

mso_schema_template_contract_filter.py
Go to the documentation of this file.
1#!/usr/bin/python
2# -*- coding: utf-8 -*-
3
4# Copyright: (c) 2018, Dag Wieers (@dagwieers) <dag@wieers.com>
5# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
6
7from __future__ import absolute_import, division, print_function
8__metaclass__ = type
9
10ANSIBLE_METADATA = {'metadata_version': '1.1',
11 'status': ['preview'],
12 'supported_by': 'community'}
13
14DOCUMENTATION = r'''
15---
16module: mso_schema_template_contract_filter
17short_description: Manage contract filters in schema templates
18description:
19- Manage contract filters in schema templates on Cisco ACI Multi-Site.
20author:
21- Dag Wieers (@dagwieers)
22version_added: '2.8'
23options:
24 schema:
25 description:
26 - The name of the schema.
27 type: str
28 required: yes
29 template:
30 description:
31 - The name of the template.
32 type: str
33 required: yes
34 contract:
35 description:
36 - The name of the contract to manage.
37 type: str
38 required: yes
39 contract_display_name:
40 description:
41 - The name as displayed on the MSO web interface.
42 - This defaults to the contract name when unset on creation.
43 type: str
44 contract_filter_type:
45 description:
46 - The type of filters defined in this contract.
47 - This defaults to C(both-way) when unset on creation.
48 type: str
49 choices: [ both-way, one-way ]
50 contract_scope:
51 description:
52 - The scope of the contract.
53 - This defaults to C(vrf) when unset on creation.
54 type: str
55 choices: [ application-profile, global, tenant, vrf ]
56 filter:
57 description:
58 - The filter to associate with this contract.
59 type: str
60 aliases: [ name ]
61 filter_template:
62 description:
63 - The template name in which the filter is located.
64 type: str
65 filter_schema:
66 description:
67 - The schema name in which the filter is located.
68 type: str
69 filter_type:
70 description:
71 - The type of filter to manage.
72 type: str
73 choices: [ both-way, consumer-to-provider, provider-to-consumer ]
74 default: both-way
75 aliases: [ type ]
76 filter_directives:
77 description:
78 - A list of filter directives.
79 type: list
80 choices: [ log, none ]
81 state:
82 description:
83 - Use C(present) or C(absent) for adding or removing.
84 - Use C(query) for listing an object or multiple objects.
85 type: str
86 choices: [ absent, present, query ]
87 default: present
88seealso:
89- module: mso_schema_template_filter_entry
90notes:
91- Due to restrictions of the MSO REST API this module creates contracts when needed, and removes them when the last filter has been removed.
92- Due to restrictions of the MSO REST API concurrent modifications to contract filters can be dangerous and corrupt data.
93extends_documentation_fragment: mso
94'''
95
96EXAMPLES = r'''
97- name: Add a new contract filter
98 mso_schema_template_contract_filter:
99 host: mso_host
100 username: admin
101 password: SomeSecretPassword
102 schema: Schema 1
103 template: Template 1
104 contract: Contract 1
105 contract_scope: global
106 filter: Filter 1
107 state: present
108 delegate_to: localhost
109
110- name: Remove a contract filter
111 mso_schema_template_contract_filter:
112 host: mso_host
113 username: admin
114 password: SomeSecretPassword
115 schema: Schema 1
116 template: Template 1
117 contract: Contract 1
118 filter: Filter 1
119 state: absent
120 delegate_to: localhost
121
122- name: Query a specific contract filter
123 mso_schema_template_contract_filter:
124 host: mso_host
125 username: admin
126 password: SomeSecretPassword
127 schema: Schema 1
128 template: Template 1
129 contract: Contract 1
130 filter: Filter 1
131 state: query
132 delegate_to: localhost
133 register: query_result
134
135- name: Query all contract filters
136 mso_schema_template_contract_filter:
137 host: mso_host
138 username: admin
139 password: SomeSecretPassword
140 schema: Schema 1
141 template: Template 1
142 contract: Contract 1
143 state: query
144 delegate_to: localhost
145 register: query_result
146'''
147
148RETURN = r'''
149'''
150
151from ansible.module_utils.basic import AnsibleModule
152from ansible.module_utils.network.aci.mso import MSOModule, mso_argument_spec, mso_reference_spec, issubset
153
154FILTER_KEYS = {
155 'both-way': 'filterRelationships',
156 'consumer-to-provider': 'filterRelationshipsConsumerToProvider',
157 'provider-to-consumer': 'filterRelationshipsProviderToConsumer',
158}
159
160
161def main():
162 argument_spec = mso_argument_spec()
163 argument_spec.update(
164 schema=dict(type='str', required=True),
165 template=dict(type='str', required=True),
166 contract=dict(type='str', required=True),
167 contract_display_name=dict(type='str'),
168 contract_scope=dict(type='str', choices=['application-profile', 'global', 'tenant', 'vrf']),
169 contract_filter_type=dict(type='str', choices=['both-way', 'one-way']),
170 filter=dict(type='str', aliases=['name']), # This parameter is not required for querying all objects
171 filter_directives=dict(type='list', choices=['log', 'none']),
172 filter_template=dict(type='str'),
173 filter_schema=dict(type='str'),
174 filter_type=dict(type='str', default='both-way', choices=FILTER_KEYS.keys(), aliases=['type']),
175 state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
176 )
177
178 module = AnsibleModule(
179 argument_spec=argument_spec,
180 supports_check_mode=True,
181 required_if=[
182 ['state', 'absent', ['filter']],
183 ['state', 'present', ['filter']],
184 ],
185 )
186
187 schema = module.params['schema']
188 template = module.params['template']
189 contract = module.params['contract']
190 contract_display_name = module.params['contract_display_name']
191 contract_filter_type = module.params['contract_filter_type']
192 contract_scope = module.params['contract_scope']
193 filter_name = module.params['filter']
194 filter_directives = module.params['filter_directives']
195 filter_template = module.params['filter_template']
196 filter_schema = module.params['filter_schema']
197 filter_type = module.params['filter_type']
198 state = module.params['state']
199
200 contract_ftype = 'bothWay' if contract_filter_type == 'both-way' else 'oneWay'
201
202 if contract_filter_type == 'both-way' and filter_type != 'both-way':
203 module.warn("You are adding 'one-way' filters to a 'both-way' contract")
204 elif contract_filter_type != 'both-way' and filter_type == 'both-way':
205 module.warn("You are adding 'both-way' filters to a 'one-way' contract")
206
207 if filter_template is None:
208 filter_template = template
209
210 if filter_schema is None:
211 filter_schema = schema
212
213 filter_key = FILTER_KEYS[filter_type]
214
215 mso = MSOModule(module)
216
217 filter_schema_id = mso.lookup_schema(filter_schema)
218
219 # Get schema object
220 schema_obj = mso.get_obj('schemas', displayName=schema)
221 if schema_obj:
222 schema_id = schema_obj['id']
223 else:
224 mso.fail_json(msg="Provided schema '{0}' does not exist".format(schema))
225
226 schema_path = 'schemas/{id}'.format(**schema_obj)
227
228 # Get template
229 templates = [t['name'] for t in schema_obj['templates']]
230 if template not in templates:
231 mso.fail_json(msg="Provided template '{0}' does not exist. Existing templates: {1}".format(template, ', '.join(templates)))
232 template_idx = templates.index(template)
233
234 # Get contracts
235 mso.existing = {}
236 contract_idx = None
237 filter_idx = None
238 contracts = [c['name'] for c in schema_obj['templates'][template_idx]['contracts']]
239
240 if contract in contracts:
241 contract_idx = contracts.index(contract)
242
243 filters = [f['filterRef'] for f in schema_obj['templates'][template_idx]['contracts'][contract_idx][filter_key]]
244 filter_ref = mso.filter_ref(schema_id=filter_schema_id, template=filter_template, filter=filter_name)
245 if filter_ref in filters:
246 filter_idx = filters.index(filter_ref)
247 filter_path = '/templates/{0}/contracts/{1}/{2}/{3}'.format(template, contract, filter_key, filter_name)
248 mso.existing = schema_obj['templates'][template_idx]['contracts'][contract_idx][filter_key][filter_idx]
249
250 if state == 'query':
251 if contract_idx is None:
252 mso.fail_json(msg="Provided contract '{0}' does not exist. Existing contracts: {1}".format(contract, ', '.join(contracts)))
253
254 if filter_name is None:
255 mso.existing = schema_obj['templates'][template_idx]['contracts'][contract_idx][filter_key]
256 elif not mso.existing:
257 mso.fail_json(msg="FilterRef '{filter_ref}' not found".format(filter_ref=filter_ref))
258 mso.exit_json()
259
260 ops = []
261 contract_path = '/templates/{0}/contracts/{1}'.format(template, contract)
262 filters_path = '/templates/{0}/contracts/{1}/{2}'.format(template, contract, filter_key)
263
264 mso.previous = mso.existing
265 if state == 'absent':
266 mso.proposed = mso.sent = {}
267
268 if contract_idx is None:
269 # There was no contract to begin with
270 pass
271 elif filter_idx is None:
272 # There was no filter to begin with
273 pass
274 elif len(filters) == 1:
275 # There is only one filter, remove contract
276 mso.existing = {}
277 ops.append(dict(op='remove', path=contract_path))
278 else:
279 # Remove filter
280 mso.existing = {}
281 ops.append(dict(op='remove', path=filter_path))
282
283 elif state == 'present':
284 if filter_directives is None:
285 filter_directives = ['none']
286
287 payload = dict(
288 filterRef=dict(
289 filterName=filter_name,
290 templateName=filter_template,
291 schemaId=filter_schema_id,
292 ),
293 directives=filter_directives,
294 )
295
296 mso.sanitize(payload, collate=True)
297 mso.existing = mso.sent
298
299 if contract_idx is None:
300 # Contract does not exist, so we have to create it
301 if contract_display_name is None:
302 contract_display_name = contract
303 if contract_filter_type is None:
304 contract_ftype = 'bothWay'
305 if contract_scope is None:
306 contract_scope = 'context'
307
308 payload = {
309 'name': contract,
310 'displayName': contract_display_name,
311 'filterType': contract_ftype,
312 'scope': contract_scope,
313 }
314
315 ops.append(dict(op='add', path='/templates/{0}/contracts/-'.format(template), value=payload))
316 else:
317 # Contract exists, but may require an update
318 if contract_display_name is not None:
319 ops.append(dict(op='replace', path=contract_path + '/displayName', value=contract_display_name))
320 if contract_filter_type is not None:
321 ops.append(dict(op='replace', path=contract_path + '/filterType', value=contract_ftype))
322 if contract_scope is not None:
323 ops.append(dict(op='replace', path=contract_path + '/scope', value=contract_scope))
324
325 if filter_idx is None:
326 # Filter does not exist, so we have to add it
327 ops.append(dict(op='add', path=filters_path + '/-', value=mso.sent))
328
329 else:
330 # Filter exists, we have to update it
331 ops.append(dict(op='replace', path=filter_path, value=mso.sent))
332
333 if not module.check_mode:
334 mso.request(schema_path, method='PATCH', data=ops)
335
336 mso.exit_json()
337
338
339if __name__ == "__main__":
340 main()