1#!/usr/local/bin/python3.8 2# -*- coding: utf-8 -*- 3 4# Copyright: (c) 2020, Sudhakar Shet Kudtarkar (@kudtarkar1) 5# Copyright: (c) 2020, Lionel Hercot <lhercot@cisco.com> 6# Copyright: (c) 2020, Shreyas Srish <ssrish@cisco.com> 7# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) 8 9from __future__ import absolute_import, division, print_function 10__metaclass__ = type 11 12DOCUMENTATION = r''' 13--- 14module: aci_static_node_mgmt_address 15short_description: In band or Out of band management IP address 16description: 17- Cisco ACI Fabric Node IP address 18options: 19 epg: 20 description: 21 - The name of the end point group 22 type: str 23 pod_id: 24 description: 25 - The pod number of the leaf, spine or APIC 26 type: int 27 node_id: 28 description: 29 - ACI Fabric's node id of a leaf, spine or APIC 30 type: int 31 ipv4_address: 32 description: 33 - ipv4 address of in band/out of band mgmt 34 type: str 35 aliases: [ ip ] 36 ipv4_gw: 37 description: 38 - Gateway address of in band / out of band mgmt network 39 type: str 40 aliases: [ gw ] 41 ipv6_address: 42 description: 43 - ipv6 address of in band/out of band mgmt 44 type: str 45 aliases: [ ipv6 ] 46 ipv6_gw: 47 description: 48 - GW address of in band/out of band mgmt 49 type: str 50 type: 51 description: 52 - type of management interface 53 type: str 54 choices: [ in_band, out_of_band ] 55 required: true 56 state: 57 description: 58 - Use C(present) or C(absent) for adding or removing. 59 - Use C(query) for listing an object or multiple objects. 60 type: str 61 choices: [ absent, present, query ] 62 default: present 63extends_documentation_fragment: 64- cisco.aci.aci 65 66author: 67- Sudhakar Shet Kudtarkar (@kudtarkar1) 68- Lionel Hercot (@lhercot) 69- Shreyas Srish (@shrsr) 70''' 71 72EXAMPLES = r''' 73- name: Add ipv4 address to in band mgmt interface 74 cisco.aci.aci_static_node_mgmt_address: 75 host: "Host IP" 76 username: admin 77 password: SomeSecretePassword 78 epg: default 79 pod_id: 1 80 type: in_band 81 node_id: 1102 82 ipv4_address: "3.1.1.2/24" 83 ipv4_gw: "3.1.1.1" 84 state: present 85 delegate_to: localhost 86 87- name: Add ipv4 address to out of band mgmt interface 88 cisco.aci.aci_static_node_mgmt_address: 89 host: "Host IP" 90 username: admin 91 password: SomeSecretePassword 92 epg: default 93 pod_id: 1 94 band_type: out_of_band 95 node_id: 1102 96 ipv4_address: "3.1.1.2/24" 97 ipv4_gw: "3.1.1.1" 98 state: present 99 delegate_to: localhost 100 101- name: Remove ipv4 address to in band mgmt interface 102 cisco.aci.aci_static_node_mgmt_address: 103 host: "Host IP" 104 username: admin 105 password: SomeSecretePassword 106 epg: default 107 pod_id: 1 108 type: in_band 109 node_id: 1102 110 ipv4_address: "3.1.1.2/24" 111 ipv4_gw: "3.1.1.1" 112 state: absent 113 delegate_to: localhost 114 115- name: Query the in band mgmt ipv4 address 116 cisco.aci.aci_static_node_mgmt_address: 117 host: "Host IP" 118 username: admin 119 password: SomeSecretePassword 120 epg: default 121 pod_id: 1 122 type: in_band 123 node_id: 1102 124 ipv4_address: "3.1.1.2/24" 125 ipv4_gw: "3.1.1.1" 126 state: query 127 delegate_to: localhost 128 129- name: Query all addresses in epg out of band25wf 130 cisco.aci.aci_static_node_mgmt_address: 131 host: "Host IP" 132 username: admin 133 password: SomeSecretePassword 134 epg: default 135 type: out_of_band 136 state: query 137 delegate_to: localhost 138 139- name: Query all in band addresses 140 cisco.aci.aci_static_node_mgmt_address: 141 host: "Host IP" 142 username: admin 143 password: SomeSecretePassword 144 type: in_band 145 state: query 146 delegate_to: localhost 147''' 148 149RETURN = r''' 150 current: 151 description: The existing configuration from the APIC after the module has finished 152 returned: success 153 type: list 154 sample: 155 [ 156 { 157 "fvTenant": { 158 "attributes": { 159 "descr": "Production environment", 160 "dn": "uni/tn-production", 161 "name": "production", 162 "nameAlias": "", 163 "ownerKey": "", 164 "ownerTag": "" 165 } 166 } 167 } 168 ] 169 error: 170 description: The error information as returned from the APIC 171 returned: failure 172 type: dict 173 sample: 174 { 175 "code": "122", 176 "text": "unknown managed object class foo" 177 } 178 raw: 179 description: The raw output returned by the APIC REST API (xml or json) 180 returned: parse error 181 type: str 182 sample: '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="unknown managed object class "/></imdata>' 183 sent: 184 description: The actual/minimal configuration pushed to the APIC 185 returned: info 186 type: list 187 sample: 188 { 189 "fvTenant": { 190 "attributes": { 191 "descr": "Production environment" 192 } 193 } 194 } 195 previous: 196 description: The original configuration from the APIC before the module has started 197 returned: info 198 type: list 199 sample: 200 [ 201 { 202 "fvTenant": { 203 "attributes": { 204 "descr": "Production", 205 "dn": "uni/tn-production", 206 "name": "production", 207 "nameAlias": "", 208 "ownerKey": "", 209 "ownerTag": "" 210 } 211 } 212 } 213 ] 214 proposed: 215 description: The assembled configuration from the user-provided parameters 216 returned: info 217 type: dict 218 sample: 219 { 220 "fvTenant": { 221 "attributes": { 222 "descr": "Production environment", 223 "name": "production" 224 } 225 } 226 } 227 filter_string: 228 description: The filter string used for the request 229 returned: failure or debug 230 type: str 231 sample: ?rsp-prop-include=config-only 232 method: 233 description: The HTTP method used for the request to the APIC 234 returned: failure or debug 235 type: str 236 sample: POST 237 response: 238 description: The HTTP response from the APIC 239 returned: failure or debug 240 type: str 241 sample: class_map (30 bytes) 242 status: 243 description: The HTTP status from the APIC 244 returned: failure or debug 245 type: int 246 sample: 200 247 url: 248 description: The HTTP url used for the request to the APIC 249 returned: failure or debug 250 type: str 251 sample: https://10.11.12.13/api/mo/uni/tn-production.json 252 ''' 253 254from ansible.module_utils.basic import AnsibleModule 255from ansible_collections.cisco.aci.plugins.module_utils.aci import ACIModule, aci_argument_spec 256 257 258def main(): 259 argument_spec = aci_argument_spec() 260 argument_spec.update( 261 node_id=dict(type='int'), 262 pod_id=dict(type='int'), 263 type=dict(type='str', choices=['in_band', 'out_of_band'], required=True), 264 epg=dict(type='str'), 265 ipv4_address=dict(type='str', aliases=['ip']), 266 ipv4_gw=dict(type='str', aliases=['gw']), 267 ipv6_address=dict(type='str', aliases=['ipv6']), 268 ipv6_gw=dict(type='str'), 269 state=dict(type='str', default='present', choices=['absent', 'present', 'query']), 270 ) 271 272 module = AnsibleModule( 273 argument_spec=argument_spec, 274 supports_check_mode=True, 275 required_if=[ 276 ['state', 'absent', ['node_id', 'epg']], 277 ['state', 'present', ['node_id', 'epg', 'ipv4_address', 'ipv4_gw']] 278 ] 279 ) 280 281 pod_id = module.params.get('pod_id') 282 node_id = module.params.get('node_id') 283 type = module.params.get('type') 284 epg = module.params.get('epg') 285 ipv4_address = module.params.get('ipv4_address') 286 ipv4_gw = module.params.get('ipv4_gw') 287 ipv6_address = module.params.get('ipv6_address') 288 ipv6_gw = module.params.get('ipv6_gw') 289 state = module.params.get('state') 290 291 class_map = dict( 292 in_band=list([ 293 dict(aci_class='mgmtInb', aci_rn='inb-{0}'), 294 dict(aci_class='mgmtRsInBStNode', aci_rn='rsinBStNode-[{0}]') 295 ]), 296 out_of_band=list([ 297 dict(aci_class='mgmtOob', aci_rn='oob-{0}'), 298 dict(aci_class='mgmtRsOoBStNode', aci_rn='rsooBStNode-[{0}]') 299 ]), 300 ) 301 302 static_path = None 303 if pod_id is not None and node_id is not None: 304 static_path = 'topology/pod-{0}/node-{1}'.format(pod_id, node_id) 305 306 aci = ACIModule(module) 307 aci.construct_url( 308 root_class=dict( 309 aci_class='fvTenant', 310 aci_rn='tn-mgmt', 311 module_object='mgmt', 312 target_filter={'name': 'mgmt'}, 313 ), 314 subclass_1=dict( 315 aci_class='mgmtMgmtP', 316 aci_rn='mgmtp-default', 317 module_object='default', 318 target_filter={'name': 'default'}, 319 ), 320 subclass_2=dict( 321 aci_class=class_map.get(type)[0]['aci_class'], 322 aci_rn=class_map.get(type)[0]['aci_rn'].format(epg), 323 module_object=epg, 324 target_filter={'name': epg}, 325 ), 326 subclass_3=dict( 327 aci_class=class_map.get(type)[1]['aci_class'], 328 aci_rn=class_map.get(type)[1]['aci_rn'].format(static_path), 329 module_object=static_path, 330 target_filter={'name': static_path}, 331 ), 332 ) 333 334 aci.get_existing() 335 336 if state == 'present': 337 aci.payload( 338 aci_class=class_map.get(type)[1]['aci_class'], 339 class_config=dict( 340 addr=ipv4_address, 341 gw=ipv4_gw, 342 v6Addr=ipv6_address, 343 v6Gw=ipv6_gw 344 ), 345 ) 346 aci.get_diff(aci_class=class_map.get(type)[1]['aci_class']) 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