1#!/usr/local/bin/python3.8 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': 'community'} 12 13DOCUMENTATION = r''' 14--- 15module: ucs_service_profile_template 16short_description: Configures Service Profile Templates on Cisco UCS Manager 17description: 18- Configures Service Profile Templates on Cisco UCS Manager. 19extends_documentation_fragment: cisco.ucs.ucs 20options: 21 state: 22 description: 23 - If C(present), will verify Service Profile Templates are present and will create if needed. 24 - If C(absent), will verify Service Profile Templates are absent and will delete if needed. 25 choices: [present, absent] 26 default: present 27 name: 28 description: 29 - The name of the service profile template. 30 - This name can be between 2 and 32 alphanumeric characters. 31 - "You cannot use spaces or any special characters other than - (hyphen), \"_\" (underscore), : (colon), and . (period)." 32 - This name must be unique across all service profiles and service profile templates within the same organization. 33 required: yes 34 template_type: 35 description: 36 - "The template type field which can be one of the following:" 37 - "initial-template — Any service profiles created from this template are not updated if the template changes." 38 - "updating-template — Any service profiles created from this template are updated if the template changes." 39 choices: [initial-template, updating-template] 40 default: initial-template 41 uuid_pool: 42 description: 43 - Specifies how the UUID will be set on a server associated with a service profile created from this template. 44 - "The uuid_pool option can be the name of the UUID pool to use or '' (the empty string)." 45 - An empty string will use the UUID assigned to the server by the manufacturer, and the 46 - UUID remains unassigned until a service profile created from this template is associated with a server. At that point, 47 - the UUID is set to the UUID value assigned to the server by the manufacturer. If the service profile is later moved to 48 - a different server, the UUID is changed to match the new server." 49 default: default 50 description: 51 description: 52 - A user-defined description of the service profile template. 53 - Enter up to 256 characters. 54 - "You can use any characters or spaces except the following:" 55 - "` (accent mark), \ (backslash), ^ (carat), \" (double quote), = (equal sign), > (greater than), < (less than), or ' (single quote)." 56 aliases: [ descr ] 57 storage_profile: 58 description: 59 - The name of the storage profile you want to associate with service profiles created from this template 60 local_disk_policy: 61 description: 62 - The name of the local disk policy you want to associate with service profiles created from this template. 63 lan_connectivity_policy: 64 description: 65 - The name of the LAN connectivity policy you want to associate with service profiles created from this template. 66 iqn_pool: 67 description: 68 - The name of the IQN pool (initiator) you want to apply to all iSCSI vNICs for service profiles created from this template. 69 san_connectivity_policy: 70 description: 71 - The name of the SAN connectivity policy you want to associate with service profiles created from this template. 72 vmedia_policy: 73 description: 74 - The name of the vMedia policy you want to associate with service profiles created from this template. 75 boot_policy: 76 description: 77 - The name of the boot order policy you want to associate with service profiles created from this template. 78 default: default 79 maintenance_policy: 80 description: 81 - The name of the maintenance policy you want to associate with service profiles created from this template. 82 server_pool: 83 description: 84 - The name of the server pool you want to associate with this service profile template. 85 server_pool_qualification: 86 description: 87 - The name of the server pool policy qualificaiton you want to use for this service profile template. 88 power_state: 89 description: 90 - The power state to be applied when a service profile created from this template is associated with a server. 91 choices: [up, down] 92 default: up 93 host_firmware_package: 94 description: 95 - The name of the host firmware package you want to associate with service profiles created from this template. 96 bios_policy: 97 description: 98 - The name of the BIOS policy you want to associate with service profiles created from this template. 99 ipmi_access_profile: 100 description: 101 - The name of the IPMI access profile you want to associate with service profiles created from this template. 102 sol_policy: 103 description: 104 - The name of the Serial over LAN (SoL) policy you want to associate with service profiles created from this template. 105 mgmt_ip_state: 106 description: 107 - The state for the Outband Management IP pool you want to use with service profiles created from this template. 108 choices: [none, pooled] 109 default: pooled 110 mgmt_ip_pool: 111 description: 112 - The name of the Outband Management IP pool you want to use with service profiles created from this template. 113 default: ext-mgmt 114 power_control_policy: 115 description: 116 - The name of the power control policy you want to associate with service profiles created from this template. 117 default: default 118 power_sync_policy: 119 description: 120 - The name of the power sync policy you want to associate with service profiles created from this template. 121 scrub_policy: 122 description: 123 - The name of the scrub policy you want to associate with service profiles created from this template. 124 kvm_mgmt_policy: 125 description: 126 - The name of the KVM management policy you want to associate with service profiles created from this template. 127 graphics_card_policy: 128 description: 129 - The name of the graphics card policy you want to associate with service profiles created from this template. 130 threshold_policy: 131 description: 132 - The name of the threshold policy you want to associate with service profiles created from this template. 133 default: default 134 user_label: 135 description: 136 - The User Label you want to assign to service profiles created from this template. 137 mgmt_interface_mode: 138 description: 139 - The Management Interface you want to assign to service profiles created from this template. 140 choices: ['', in-band] 141 mgmt_vnet_name: 142 description: 143 - A VLAN selected from the associated VLAN group. 144 mgmt_inband_pool_name: 145 description: 146 - How the inband management IPv4 address is derived for the server associated with this service profile. 147 org_dn: 148 description: 149 - Org dn (distinguished name) 150 default: org-root 151requirements: 152- ucsmsdk 153author: 154- David Soper (@dsoper2) 155- CiscoUcs (@CiscoUcs) 156version_added: '2.8' 157''' 158 159EXAMPLES = r''' 160- name: Configure Service Profile Template with LAN/SAN Connectivity and all other options defaulted 161 cisco.ucs.ucs_service_profile_template: 162 hostname: 172.16.143.150 163 username: admin 164 password: password 165 name: DEE-Ctrl 166 template_type: updating-template 167 uuid_pool: UUID-Pool 168 storage_profile: DEE-StgProf 169 lan_connectivity_policy: Cntr-FC-Boot 170 iqn_pool: iSCSI-Boot-A 171 san_connectivity_policy: Cntr-FC-Boot 172 boot_policy: DEE-vMedia 173 maintenance_policy: default 174 server_pool: Container-Pool 175 host_firmware_package: 3.1.2b 176 bios_policy: Docker 177 178- name: Remove Service Profile Template 179 cisco.ucs.ucs_service_profile_template: 180 hostname: 172.16.143.150 181 username: admin 182 password: password 183 name: DEE-Ctrl 184 state: absent 185''' 186 187RETURN = r''' 188# 189''' 190 191from ansible.module_utils.basic import AnsibleModule 192from ansible_collections.cisco.ucs.plugins.module_utils.ucs import UCSModule, ucs_argument_spec 193 194 195def configure_service_profile_template(ucs, module): 196 from ucsmsdk.mometa.ls.LsServer import LsServer 197 from ucsmsdk.mometa.vnic.VnicConnDef import VnicConnDef 198 from ucsmsdk.mometa.vnic.VnicIScsiNode import VnicIScsiNode 199 from ucsmsdk.mometa.ls.LsRequirement import LsRequirement 200 from ucsmsdk.mometa.ls.LsPower import LsPower 201 from ucsmsdk.mometa.lstorage.LstorageProfileBinding import LstorageProfileBinding 202 from ucsmsdk.mometa.mgmt.MgmtInterface import MgmtInterface 203 from ucsmsdk.mometa.mgmt.MgmtVnet import MgmtVnet 204 from ucsmsdk.mometa.vnic.VnicIpV4MgmtPooledAddr import VnicIpV4MgmtPooledAddr 205 206 if not module.check_mode: 207 try: 208 # create if mo does not already exist 209 mo = LsServer( 210 parent_mo_or_dn=module.params['org_dn'], 211 bios_profile_name=module.params['bios_policy'], 212 boot_policy_name=module.params['boot_policy'], 213 descr=module.params['description'], 214 ext_ip_state=module.params['mgmt_ip_state'], 215 ext_ip_pool_name=module.params['mgmt_ip_pool'], 216 # graphics_card_policy_name=module.params['graphics_card_policy'], 217 host_fw_policy_name=module.params['host_firmware_package'], 218 ident_pool_name=module.params['uuid_pool'], 219 kvm_mgmt_policy_name=module.params['kvm_mgmt_policy'], 220 local_disk_policy_name=module.params['local_disk_policy'], 221 maint_policy_name=module.params['maintenance_policy'], 222 mgmt_access_policy_name=module.params['ipmi_access_profile'], 223 name=module.params['name'], 224 power_policy_name=module.params['power_control_policy'], 225 power_sync_policy_name=module.params['power_sync_policy'], 226 scrub_policy_name=module.params['scrub_policy'], 227 sol_policy_name=module.params['sol_policy'], 228 stats_policy_name=module.params['threshold_policy'], 229 type=module.params['template_type'], 230 usr_lbl=module.params['user_label'], 231 vmedia_policy_name=module.params['vmedia_policy'], 232 ) 233 234 if module.params['storage_profile']: 235 # Storage profile 236 mo_1 = LstorageProfileBinding( 237 parent_mo_or_dn=mo, 238 storage_profile_name=module.params['storage_profile'], 239 ) 240 241 if module.params['mgmt_interface_mode']: 242 # Management Interface 243 mo_1 = MgmtInterface( 244 parent_mo_or_dn=mo, 245 mode=module.params['mgmt_interface_mode'], 246 ip_v4_state='pooled', 247 ) 248 mo_2 = MgmtVnet( 249 parent_mo_or_dn=mo_1, 250 id='1', 251 name=module.params['mgmt_vnet_name'], 252 ) 253 VnicIpV4MgmtPooledAddr( 254 parent_mo_or_dn=mo_2, 255 name=module.params['mgmt_inband_pool_name'], 256 ) 257 258 # LAN/SAN connectivity policy 259 mo_1 = VnicConnDef( 260 parent_mo_or_dn=mo, 261 lan_conn_policy_name=module.params['lan_connectivity_policy'], 262 san_conn_policy_name=module.params['san_connectivity_policy'], 263 ) 264 265 if module.params['iqn_pool']: 266 # IQN pool 267 mo_1 = VnicIScsiNode( 268 parent_mo_or_dn=mo, 269 iqn_ident_pool_name=module.params['iqn_pool'] 270 ) 271 272 # power state 273 admin_state = 'admin-' + module.params['power_state'] 274 mo_1 = LsPower( 275 parent_mo_or_dn=mo, 276 state=admin_state, 277 ) 278 279 if module.params['server_pool']: 280 # server pool 281 mo_1 = LsRequirement( 282 parent_mo_or_dn=mo, 283 name=module.params['server_pool'], 284 qualifier=module.params['server_pool_qualification'], 285 ) 286 287 ucs.login_handle.add_mo(mo, True) 288 ucs.login_handle.commit() 289 except Exception as e: # generic Exception handling because SDK can throw a variety of exceptions 290 ucs.result['msg'] = "setup error: %s " % str(e) 291 module.fail_json(**ucs.result) 292 293 ucs.result['changed'] = True 294 295 296def check_storage_profile_props(ucs, module, dn): 297 props_match = False 298 299 child_dn = dn + '/profile-binding' 300 mo_1 = ucs.login_handle.query_dn(child_dn) 301 if mo_1: 302 kwargs = dict(storage_profile_name=module.params['storage_profile']) 303 if mo_1.check_prop_match(**kwargs): 304 props_match = True 305 elif not module.params['storage_profile']: 306 # no stroage profile mo or desired state 307 props_match = True 308 309 return props_match 310 311 312def check_connectivity_policy_props(ucs, module, dn): 313 props_match = False 314 315 child_dn = dn + '/conn-def' 316 mo_1 = ucs.login_handle.query_dn(child_dn) 317 if mo_1: 318 kwargs = dict(lan_conn_policy_name=module.params['lan_connectivity_policy']) 319 kwargs['san_conn_policy_name'] = module.params['san_connectivity_policy'] 320 if mo_1.check_prop_match(**kwargs): 321 props_match = True 322 elif not module.params['lan_connectivity_policy'] and not module.params['san_connectivity_policy']: 323 # no mo and no desired state 324 props_match = True 325 326 return props_match 327 328 329def check_iqn_pool_props(ucs, module, dn): 330 props_match = False 331 332 child_dn = dn + '/iscsi-node' 333 mo_1 = ucs.login_handle.query_dn(child_dn) 334 if mo_1: 335 kwargs = dict(iqn_ident_pool_name=module.params['iqn_pool']) 336 if mo_1.check_prop_match(**kwargs): 337 props_match = True 338 elif not module.params['iqn_pool']: 339 # no mo and no desired state 340 props_match = True 341 342 return props_match 343 344 345def check_inband_management_props(ucs, module, dn): 346 props_match = False 347 348 child_dn = dn + '/iface-in-band' 349 mo_1 = ucs.login_handle.query_dn(child_dn) 350 if mo_1: 351 kwargs = dict(mode=module.params['mgmt_interface_mode']) 352 if mo_1.check_prop_match(**kwargs): 353 child_dn = child_dn + '/network' 354 mo_2 = ucs.login_handle.query_dn(child_dn) 355 if mo_2: 356 kwargs = dict(name=module.params['mgmt_vnet_name']) 357 if mo_2.check_prop_match(**kwargs): 358 child_dn = child_dn + '/ipv4-pooled-addr' 359 mo_3 = ucs.login_handle.query_dn(child_dn) 360 if mo_3: 361 kwargs = dict(name=module.params['mgmt_inband_pool_name']) 362 if mo_3.check_prop_match(**kwargs): 363 props_match = True 364 elif not module.params['mgmt_interface_mode']: 365 # no mo and no desired state 366 props_match = True 367 368 return props_match 369 370 371def check_power_props(ucs, module, dn): 372 props_match = False 373 374 child_dn = dn + '/power' 375 mo_1 = ucs.login_handle.query_dn(child_dn) 376 if mo_1: 377 kwargs = dict(state=module.params['power_state']) 378 if mo_1.check_prop_match(**kwargs): 379 props_match = True 380 elif not module.params['power_state']: 381 # no mo and no desired state 382 props_match = True 383 384 return props_match 385 386 387def check_server_pool(ucs, module, dn): 388 props_match = False 389 390 child_dn = dn + '/pn-req' 391 mo_1 = ucs.login_handle.query_dn(child_dn) 392 if mo_1: 393 kwargs = dict(name=module.params['server_pool']) 394 kwargs['qualifier'] = module.params['server_pool_qualification'] 395 if mo_1.check_prop_match(**kwargs): 396 props_match = True 397 elif not module.params['server_pool']: 398 # no pn-req object and no server pool name provided 399 props_match = True 400 401 return props_match 402 403 404def check_serivce_profile_templates_props(ucs, module, mo, dn): 405 props_match = False 406 407 # check top-level mo props 408 kwargs = dict(bios_profile_name=module.params['bios_policy']) 409 kwargs['boot_policy_name'] = module.params['boot_policy'] 410 kwargs['descr'] = module.params['description'] 411 kwargs['ext_ip_state'] = module.params['mgmt_ip_state'] 412 kwargs['ext_ip_pool_name'] = module.params['mgmt_ip_pool'] 413 # kwargs['graphics_card_policy_name'] = module.params['graphics_card_policy'] 414 kwargs['host_fw_policy_name'] = module.params['host_firmware_package'] 415 kwargs['ident_pool_name'] = module.params['uuid_pool'] 416 kwargs['kvm_mgmt_policy_name'] = module.params['kvm_mgmt_policy'] 417 kwargs['local_disk_policy_name'] = module.params['local_disk_policy'] 418 kwargs['maint_policy_name'] = module.params['maintenance_policy'] 419 kwargs['mgmt_access_policy_name'] = module.params['ipmi_access_profile'] 420 kwargs['power_policy_name'] = module.params['power_control_policy'] 421 kwargs['power_sync_policy_name'] = module.params['power_sync_policy'] 422 kwargs['scrub_policy_name'] = module.params['scrub_policy'] 423 kwargs['sol_policy_name'] = module.params['sol_policy'] 424 kwargs['stats_policy_name'] = module.params['threshold_policy'] 425 kwargs['type'] = module.params['template_type'] 426 kwargs['usr_lbl'] = module.params['user_label'] 427 kwargs['vmedia_policy_name'] = module.params['vmedia_policy'] 428 429 if mo.check_prop_match(**kwargs): 430 # top-level props match, check next level mo/props 431 # code below should discontinue checks once any mismatch is found 432 433 # check storage profile 1st 434 props_match = check_storage_profile_props(ucs, module, dn) 435 436 if props_match: 437 props_match = check_connectivity_policy_props(ucs, module, dn) 438 439 if props_match: 440 props_match = check_iqn_pool_props(ucs, module, dn) 441 442 if props_match: 443 props_match = check_inband_management_props(ucs, module, dn) 444 445 if props_match: 446 props_match = check_power_props(ucs, module, dn) 447 448 if props_match: 449 props_match = check_server_pool(ucs, module, dn) 450 451 return props_match 452 453 454def main(): 455 argument_spec = ucs_argument_spec 456 argument_spec.update( 457 org_dn=dict(type='str', default='org-root'), 458 name=dict(type='str', required=True), 459 bios_policy=dict(type='str', default=''), 460 boot_policy=dict(type='str', default='default'), 461 description=dict(type='str', aliases=['descr'], default=''), 462 mgmt_ip_state=dict(type='str', default='pooled'), 463 mgmt_ip_pool=dict(type='str', default='ext-mgmt'), 464 graphics_card_policy=dict(type='str', default=''), 465 host_firmware_package=dict(type='str', default=''), 466 uuid_pool=dict(type='str', default='default'), 467 kvm_mgmt_policy=dict(type='str', default=''), 468 local_disk_policy=dict(type='str', default=''), 469 maintenance_policy=dict(type='str', default=''), 470 ipmi_access_profile=dict(type='str', default=''), 471 power_control_policy=dict(type='str', default='default'), 472 power_sync_policy=dict(type='str', default=''), 473 scrub_policy=dict(type='str', default=''), 474 sol_policy=dict(type='str', default=''), 475 threshold_policy=dict(type='str', default='default'), 476 template_type=dict(type='str', default='initial-template', choices=['initial-template', 'updating-template']), 477 user_label=dict(type='str', default=''), 478 vmedia_policy=dict(type='str', default=''), 479 storage_profile=dict(type='str', default=''), 480 lan_connectivity_policy=dict(type='str', default=''), 481 iqn_pool=dict(type='str', default=''), 482 san_connectivity_policy=dict(type='str', default=''), 483 server_pool=dict(type='str', default=''), 484 server_pool_qualification=dict(type='str', default=''), 485 power_state=dict(type='str', default='up', choices=['up', 'down']), 486 mgmt_interface_mode=dict(type='str', default='', choices=['', 'in-band']), 487 mgmt_vnet_name=dict(type='str', default=''), 488 mgmt_inband_pool_name=dict(type='str', default=''), 489 state=dict(type='str', default='present', choices=['present', 'absent']), 490 ) 491 492 module = AnsibleModule( 493 argument_spec, 494 supports_check_mode=True, 495 ) 496 ucs = UCSModule(module) 497 # UCSModule creation above verifies ucsmsdk is present and exits on failure. 498 # Additional imports are done below or in called functions. 499 500 ucs.result['changed'] = False 501 props_match = False 502 # dn is <org_dn>/ls-<name> 503 dn = module.params['org_dn'] + '/ls-' + module.params['name'] 504 505 mo = ucs.login_handle.query_dn(dn) 506 if mo: 507 if module.params['state'] == 'absent': 508 # mo must exist but all properties do not have to match 509 if not module.check_mode: 510 ucs.login_handle.remove_mo(mo) 511 ucs.login_handle.commit() 512 ucs.result['changed'] = True 513 else: # state == 'present' 514 props_match = check_serivce_profile_templates_props(ucs, module, mo, dn) 515 516 if module.params['state'] == 'present' and not props_match: 517 configure_service_profile_template(ucs, module) 518 519 module.exit_json(**ucs.result) 520 521 522if __name__ == '__main__': 523 main() 524