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_contract_subject 16short_description: Manage initial Contract Subjects (vz:Subj) 17description: 18- Manage initial Contract Subjects on Cisco ACI fabrics. 19version_added: '2.4' 20options: 21 tenant: 22 description: 23 - The name of the tenant. 24 type: str 25 aliases: [ tenant_name ] 26 subject: 27 description: 28 - The contract subject name. 29 type: str 30 aliases: [ contract_subject, name, subject_name ] 31 contract: 32 description: 33 - The name of the Contract. 34 type: str 35 aliases: [ contract_name ] 36 reverse_filter: 37 description: 38 - Determines if the APIC should reverse the src and dst ports to allow the 39 return traffic back, since ACI is stateless filter. 40 - The APIC defaults to C(yes) when unset during creation. 41 type: bool 42 priority: 43 description: 44 - The QoS class. 45 - The APIC defaults to C(unspecified) when unset during creation. 46 type: str 47 choices: [ level1, level2, level3, unspecified ] 48 dscp: 49 description: 50 - The target DSCP. 51 - The APIC defaults to C(unspecified) when unset during creation. 52 type: str 53 choices: [ AF11, AF12, AF13, AF21, AF22, AF23, AF31, AF32, AF33, AF41, AF42, AF43, 54 CS0, CS1, CS2, CS3, CS4, CS5, CS6, CS7, EF, VA, unspecified ] 55 aliases: [ target ] 56 description: 57 description: 58 - Description for the contract subject. 59 type: str 60 aliases: [ descr ] 61 consumer_match: 62 description: 63 - The match criteria across consumers. 64 - The APIC defaults to C(at_least_one) when unset during creation. 65 type: str 66 choices: [ all, at_least_one, at_most_one, none ] 67 provider_match: 68 description: 69 - The match criteria across providers. 70 - The APIC defaults to C(at_least_one) when unset during creation. 71 type: str 72 choices: [ all, at_least_one, at_most_one, none ] 73 state: 74 description: 75 - Use C(present) or C(absent) for adding or removing. 76 - Use C(query) for listing an object or multiple objects. 77 type: str 78 choices: [ absent, present, query ] 79 default: present 80extends_documentation_fragment: aci 81notes: 82- The C(tenant) and C(contract) used must exist before using this module in your playbook. 83 The M(aci_tenant) and M(aci_contract) modules can be used for this. 84seealso: 85- module: aci_contract 86- module: aci_tenant 87- name: APIC Management Information Model reference 88 description: More information about the internal APIC class B(vz:Subj). 89 link: https://developer.cisco.com/docs/apic-mim-ref/ 90author: 91- Swetha Chunduri (@schunduri) 92''' 93 94EXAMPLES = r''' 95- name: Add a new contract subject 96 aci_contract_subject: 97 host: apic 98 username: admin 99 password: SomeSecretPassword 100 tenant: production 101 contract: web_to_db 102 subject: default 103 description: test 104 reverse_filter: yes 105 priority: level1 106 dscp: unspecified 107 state: present 108 register: query_result 109 110- name: Remove a contract subject 111 aci_contract_subject: 112 host: apic 113 username: admin 114 password: SomeSecretPassword 115 tenant: production 116 contract: web_to_db 117 subject: default 118 state: absent 119 delegate_to: localhost 120 121- name: Query a contract subject 122 aci_contract_subject: 123 host: apic 124 username: admin 125 password: SomeSecretPassword 126 tenant: production 127 contract: web_to_db 128 subject: default 129 state: query 130 delegate_to: localhost 131 register: query_result 132 133- name: Query all contract subjects 134 aci_contract_subject: 135 host: apic 136 username: admin 137 password: SomeSecretPassword 138 state: query 139 delegate_to: localhost 140 register: query_result 141''' 142 143RETURN = r''' 144current: 145 description: The existing configuration from the APIC after the module has finished 146 returned: success 147 type: list 148 sample: 149 [ 150 { 151 "fvTenant": { 152 "attributes": { 153 "descr": "Production environment", 154 "dn": "uni/tn-production", 155 "name": "production", 156 "nameAlias": "", 157 "ownerKey": "", 158 "ownerTag": "" 159 } 160 } 161 } 162 ] 163error: 164 description: The error information as returned from the APIC 165 returned: failure 166 type: dict 167 sample: 168 { 169 "code": "122", 170 "text": "unknown managed object class foo" 171 } 172raw: 173 description: The raw output returned by the APIC REST API (xml or json) 174 returned: parse error 175 type: str 176 sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class foo"/></imdata>' 177sent: 178 description: The actual/minimal configuration pushed to the APIC 179 returned: info 180 type: list 181 sample: 182 { 183 "fvTenant": { 184 "attributes": { 185 "descr": "Production environment" 186 } 187 } 188 } 189previous: 190 description: The original configuration from the APIC before the module has started 191 returned: info 192 type: list 193 sample: 194 [ 195 { 196 "fvTenant": { 197 "attributes": { 198 "descr": "Production", 199 "dn": "uni/tn-production", 200 "name": "production", 201 "nameAlias": "", 202 "ownerKey": "", 203 "ownerTag": "" 204 } 205 } 206 } 207 ] 208proposed: 209 description: The assembled configuration from the user-provided parameters 210 returned: info 211 type: dict 212 sample: 213 { 214 "fvTenant": { 215 "attributes": { 216 "descr": "Production environment", 217 "name": "production" 218 } 219 } 220 } 221filter_string: 222 description: The filter string used for the request 223 returned: failure or debug 224 type: str 225 sample: ?rsp-prop-include=config-only 226method: 227 description: The HTTP method used for the request to the APIC 228 returned: failure or debug 229 type: str 230 sample: POST 231response: 232 description: The HTTP response from the APIC 233 returned: failure or debug 234 type: str 235 sample: OK (30 bytes) 236status: 237 description: The HTTP status from the APIC 238 returned: failure or debug 239 type: int 240 sample: 200 241url: 242 description: The HTTP url used for the request to the APIC 243 returned: failure or debug 244 type: str 245 sample: https://10.11.12.13/api/mo/uni/tn-production.json 246''' 247 248from ansible.module_utils.basic import AnsibleModule 249from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec 250 251MATCH_MAPPING = dict( 252 all='All', 253 at_least_one='AtleastOne', 254 at_most_one='AtmostOne', 255 none='None', 256) 257 258 259def main(): 260 argument_spec = aci_argument_spec() 261 argument_spec.update( 262 contract=dict(type='str', aliases=['contract_name']), # Not required for querying all objects 263 subject=dict(type='str', aliases=['contract_subject', 'name', 'subject_name']), # Not required for querying all objects 264 tenant=dict(type='str', aliases=['tenant_name']), # Not required for querying all objects 265 priority=dict(type='str', choices=['unspecified', 'level1', 'level2', 'level3']), 266 reverse_filter=dict(type='bool'), 267 dscp=dict(type='str', aliases=['target'], 268 choices=['AF11', 'AF12', 'AF13', 'AF21', 'AF22', 'AF23', 'AF31', 'AF32', 'AF33', 'AF41', 'AF42', 'AF43', 269 'CS0', 'CS1', 'CS2', 'CS3', 'CS4', 'CS5', 'CS6', 'CS7', 'EF', 'VA', 'unspecified']), 270 description=dict(type='str', aliases=['descr']), 271 consumer_match=dict(type='str', choices=['all', 'at_least_one', 'at_most_one', 'none']), 272 provider_match=dict(type='str', choices=['all', 'at_least_one', 'at_most_one', 'none']), 273 state=dict(type='str', default='present', choices=['absent', 'present', 'query']), 274 directive=dict(type='str', removed_in_version='2.4'), # Deprecated starting from v2.4 275 filter=dict(type='str', aliases=['filter_name'], removed_in_version='2.4'), # Deprecated starting from v2.4 276 ) 277 278 module = AnsibleModule( 279 argument_spec=argument_spec, 280 supports_check_mode=True, 281 required_if=[ 282 ['state', 'absent', ['contract', 'subject', 'tenant']], 283 ['state', 'present', ['contract', 'subject', 'tenant']], 284 ], 285 ) 286 287 aci = ACIModule(module) 288 289 subject = module.params['subject'] 290 priority = module.params['priority'] 291 reverse_filter = aci.boolean(module.params['reverse_filter']) 292 contract = module.params['contract'] 293 dscp = module.params['dscp'] 294 description = module.params['description'] 295 filter_name = module.params['filter'] 296 directive = module.params['directive'] 297 consumer_match = module.params['consumer_match'] 298 if consumer_match is not None: 299 consumer_match = MATCH_MAPPING[consumer_match] 300 provider_match = module.params['provider_match'] 301 if provider_match is not None: 302 provider_match = MATCH_MAPPING[provider_match] 303 state = module.params['state'] 304 tenant = module.params['tenant'] 305 306 if directive is not None or filter_name is not None: 307 module.fail_json(msg="Managing Contract Subjects to Filter bindings has been moved to module 'aci_subject_bind_filter'") 308 309 aci.construct_url( 310 root_class=dict( 311 aci_class='fvTenant', 312 aci_rn='tn-{0}'.format(tenant), 313 module_object=tenant, 314 target_filter={'name': tenant}, 315 ), 316 subclass_1=dict( 317 aci_class='vzBrCP', 318 aci_rn='brc-{0}'.format(contract), 319 module_object=contract, 320 target_filter={'name': contract}, 321 ), 322 subclass_2=dict( 323 aci_class='vzSubj', 324 aci_rn='subj-{0}'.format(subject), 325 module_object=subject, 326 target_filter={'name': subject}, 327 ), 328 ) 329 330 aci.get_existing() 331 332 if state == 'present': 333 aci.payload( 334 aci_class='vzSubj', 335 class_config=dict( 336 name=subject, 337 prio=priority, 338 revFltPorts=reverse_filter, 339 targetDscp=dscp, 340 consMatchT=consumer_match, 341 provMatchT=provider_match, 342 descr=description, 343 ), 344 ) 345 346 aci.get_diff(aci_class='vzSubj') 347 348 aci.post_config() 349 350 elif state == 'absent': 351 aci.delete_config() 352 353 aci.exit_json() 354 355 356if __name__ == "__main__": 357 main() 358