├── README.md └── vsphere_guest /README.md: -------------------------------------------------------------------------------- 1 | Ansible module that allows you to define and create a VMWare vsphere guest OS instance which can then be booted to start an automated install. 2 | 3 | Here is an example of defining the guest: 4 | 5 | - hosts: 127.0.0.1 6 | connection: local 7 | user: username 8 | sudo: false 9 | gather_facts: false 10 | serial: 1 11 | 12 | tasks: 13 | 14 | - vsphere_guest: > 15 | vcenter_hostname='vcenter.host.edu' user='username' password='password' 16 | datacenter="Dev_Datacenter" datastore="hit04_sata_datastore04" esxi_hostname="esx15.mgt.host.edu" 17 | vm_name="romeotestvm" vm_memory_mb=2048 vm_num_cpus=2 vm_notes="woohoo" guestosid="rhel6_64Guest" 18 | power_on=yes 19 | args: 20 | vm_cdrom: 21 | type: "iso" 22 | iso_path: "hit04_iso_datastore/path/to/kickstart_boot.iso" 23 | vm_extra_config: 24 | vcpu.hotadd: 'TRUE' 25 | mem.hotadd: 'TRUE' 26 | vm_disk: 27 | disk1: 28 | size_gb: 1 29 | datastore: "hit04_sata_datastore04" 30 | type: "thin" 31 | disk2: 32 | size_gb: 2 33 | datastore: "hit04_sata_datastore05" 34 | type: "thin" 35 | vm_nic: 36 | nic1: 37 | type: "vmxnet3" 38 | network: "dv_172_16_4_0_24" 39 | network_type: "dvs" 40 | nic2: 41 | type: "vmxnet3" 42 | network: "dv_128_171_16_0_24" 43 | network_type: "dvs" 44 | -------------------------------------------------------------------------------- /vsphere_guest: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # -*- coding: utf-8 -*- 4 | 5 | # (c) 2013, Romeo Theriault 6 | # 7 | # This file is part of Ansible 8 | # 9 | # Ansible is free software: you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation, either version 3 of the License, or# (at your option) any later version. 12 | # 13 | # Ansible is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with Ansible. If not, see .# 20 | # see examples/playbooks/vsphere_client.yml 21 | 22 | # TODO: 23 | # Ability to set CPU/Memory reservations 24 | 25 | try: 26 | import json 27 | except ImportError: 28 | import simplejson as json 29 | 30 | DOCUMENTATION = ''' 31 | --- 32 | module: vsphere_client 33 | short_description: Creates a virtual guest on vsphere. 34 | description: 35 | - Communicates with vsphere, creating a new virtual guest OS based on 36 | the specifications you specify to the module. 37 | version_added: "1.1" 38 | options: 39 | vcenter_hostname: 40 | description: 41 | - The hostname of the vcenter server the module will connect to, to create the guest. 42 | required: true 43 | default: null 44 | aliases: [] 45 | user: 46 | description: 47 | - username of the user to connect to vcenter as. 48 | required: true 49 | default: null 50 | password: 51 | description: 52 | - password of the user to connect to vcenter as. 53 | required: true 54 | default: null 55 | resource_pool: 56 | description: 57 | - The name of the resource_pool to create the VM in. 58 | required: false 59 | default: None 60 | cluster: 61 | description: 62 | - The name of the cluster to create the VM in. By default this is derived from the host you tell the module to build the guest on. 63 | required: false 64 | default: None 65 | datacenter: 66 | description: 67 | - The name of the datacenter to create the VM in. 68 | required: true 69 | default: null 70 | datastore: 71 | description: 72 | - The datastore to store the VMs config files in. (Hard-disk locations are specified separately.) 73 | required: true 74 | default: null 75 | esxi_hostname: 76 | description: 77 | - The hostname of the esxi host you want the VM to be created on. 78 | required: true 79 | default: null 80 | power_on: 81 | description: 82 | - Whether or not to power on the VM after creation. 83 | required: false 84 | default: no 85 | choices: [yes, no] 86 | vm_name: 87 | description: 88 | - The name you want to call the VM. 89 | required: true 90 | default: null 91 | vm_memory_mb: 92 | description: 93 | - How much memory in MB to give the VM. 94 | required: false 95 | default: 1024 96 | vm_num_cpus: 97 | description: 98 | - How many vCPUs to give the VM. 99 | required: false 100 | default: 1 101 | vm_scsi: 102 | description: 103 | - The type of scsi controller to add to the VM. 104 | required: false 105 | default: "paravirtual" 106 | choices: [paravirtual, lsi, lsi_sas, bus_logic] 107 | vm_disk: 108 | description: 109 | - A key, value list of disks and their sizes and which datastore to keep it in. 110 | required: false 111 | default: null 112 | vm_nic: 113 | description: 114 | - A key, value list of nics, their types and what network to put them on. 115 | required: false 116 | default: null 117 | choices: [vmxnet3, vmxnet2, vmxnet, e1000, e1000e, pcnet32] 118 | vm_notes: 119 | description: 120 | - Any notes that you want to show up in the VMs Annotations field. 121 | required: false 122 | default: null 123 | vm_cdrom: 124 | description: 125 | - A path, including datastore, to an ISO you want the CDROM device on the VM to have. 126 | required: false 127 | default: null 128 | vm_extra_config: 129 | description: 130 | - A key, value pair of any extra values you want set or changed in the vmx file of the VM. Useful to set advanced options on the VM. 131 | required: false 132 | default: null 133 | guestosid: 134 | description: 135 | - A vmware guest needs to have a specific OS identifier set on it during creation. You can find your os guestosid at the following URL: 136 | http://www.vmware.com/support/developer/vc-sdk/visdk41pubs/ApiReference/vim.vm.GuestOsDescriptor.GuestOsIdentifier.html 137 | required: true 138 | default: null 139 | # informational: requirements for nodes 140 | requirements: [ pysphere ] 141 | author: Romeo Theriault 142 | ''' 143 | 144 | HAS_PYSPHERE = True 145 | try: 146 | from pysphere import VIServer, VIProperty, MORTypes 147 | from pysphere.resources import VimService_services as VI 148 | from pysphere.vi_task import VITask 149 | from pysphere import VIException, VIApiException, FaultTypes 150 | except ImportError: 151 | HAS_PYSPHERE = False 152 | 153 | 154 | def add_scsi_controller(module, s, config, devices, type="paravirtual", bus_num=0, disk_ctrl_key=1): 155 | ### add a scsi controller 156 | scsi_ctrl_spec = config.new_deviceChange() 157 | scsi_ctrl_spec.set_element_operation('add') 158 | 159 | if type == "lsi": 160 | # For RHEL5 161 | scsi_ctrl = VI.ns0.VirtualLsiLogicController_Def("scsi_ctrl").pyclass() 162 | elif type == "paravirtual": 163 | # For RHEL6 164 | scsi_ctrl = VI.ns0.ParaVirtualSCSIController_Def("scsi_ctrl").pyclass() 165 | elif type == "lsi_sas": 166 | scsi_ctrl = VI.ns0.VirtualLsiLogicSASController_Def("scsi_ctrl").pyclass() 167 | elif type == "bus_logic": 168 | scsi_ctrl = VI.ns0.VirtualBusLogicController_Def("scsi_ctrl").pyclass() 169 | else: 170 | s.disconnect() 171 | module.fail_json(msg="Error adding scsi controller to vm spec. No scsi controller type of: %s" % (type)) 172 | 173 | scsi_ctrl.set_element_busNumber(bus_num) 174 | scsi_ctrl.set_element_key(disk_ctrl_key) 175 | scsi_ctrl.set_element_sharedBus("noSharing") 176 | scsi_ctrl_spec.set_element_device(scsi_ctrl) 177 | # Add the scsi controller to the VM spec. 178 | devices.append(scsi_ctrl_spec) 179 | return disk_ctrl_key 180 | 181 | 182 | def add_disk(module, s, config_target, config, devices, datastore, type="thin", size=200000, disk_ctrl_key=1, disk_number=0, key=0): 183 | ### add a vmdk disk 184 | # Verify the datastore exists 185 | datastore_name, ds = find_datastore(module, s, datastore, config_target) 186 | # create a new disk - file based - for the vm 187 | disk_spec = config.new_deviceChange() 188 | disk_spec.set_element_fileOperation("create") 189 | disk_spec.set_element_operation("add") 190 | disk_ctlr = VI.ns0.VirtualDisk_Def("disk_ctlr").pyclass() 191 | disk_backing = VI.ns0.VirtualDiskFlatVer2BackingInfo_Def("disk_backing").pyclass() 192 | disk_backing.set_element_fileName(datastore_name) 193 | disk_backing.set_element_diskMode("persistent") 194 | if type != "thick": 195 | disk_backing.set_element_thinProvisioned(1) 196 | disk_ctlr.set_element_key(key) 197 | disk_ctlr.set_element_controllerKey(disk_ctrl_key) 198 | disk_ctlr.set_element_unitNumber(disk_number) 199 | disk_ctlr.set_element_backing(disk_backing) 200 | disk_ctlr.set_element_capacityInKB(size) 201 | disk_spec.set_element_device(disk_ctlr) 202 | devices.append(disk_spec) 203 | 204 | 205 | def add_cdrom(module, s, config_target, config, devices, default_devs, type="client", vm_cd_iso_path=None): 206 | ### Add a cd-rom 207 | # Make sure the datastore exists. 208 | if vm_cd_iso_path: 209 | iso_location = vm_cd_iso_path.split('/', 1) 210 | datastore, ds = find_datastore(module, s, iso_location[0], config_target) 211 | iso_path = iso_location[1] 212 | 213 | # find ide controller 214 | ide_ctlr = None 215 | for dev in default_devs: 216 | if dev.typecode.type[1] == "VirtualIDEController": 217 | ide_ctlr = dev 218 | 219 | # add a cdrom based on a physical device 220 | if ide_ctlr: 221 | cd_spec = config.new_deviceChange() 222 | cd_spec.set_element_operation('add') 223 | cd_ctrl = VI.ns0.VirtualCdrom_Def("cd_ctrl").pyclass() 224 | 225 | if type == "iso": 226 | iso = VI.ns0.VirtualCdromIsoBackingInfo_Def("iso").pyclass() 227 | ds_ref = iso.new_datastore(ds) 228 | ds_ref.set_attribute_type(ds.get_attribute_type()) 229 | iso.set_element_datastore(ds_ref) 230 | iso.set_element_fileName("%s %s" % (datastore, iso_path)) 231 | cd_ctrl.set_element_backing(iso) 232 | cd_ctrl.set_element_key(20) 233 | cd_ctrl.set_element_controllerKey(ide_ctlr.get_element_key()) 234 | cd_ctrl.set_element_unitNumber(0) 235 | cd_spec.set_element_device(cd_ctrl) 236 | elif type == "client": 237 | client = VI.ns0.VirtualCdromRemoteAtapiBackingInfo_Def("client").pyclass() 238 | client.set_element_deviceName("") 239 | cd_ctrl.set_element_backing(client) 240 | cd_ctrl.set_element_key(20) 241 | cd_ctrl.set_element_controllerKey(ide_ctlr.get_element_key()) 242 | cd_ctrl.set_element_unitNumber(0) 243 | cd_spec.set_element_device(cd_ctrl) 244 | else: 245 | s.disconnect() 246 | module.fail_json(msg="Error adding cdrom of type %s to vm spec. cdrom type can either be iso or client" % (type)) 247 | 248 | devices.append(cd_spec) 249 | 250 | 251 | def add_nic(module, s, nfmor, config, devices, nic_type="vmxnet3", network_name="VM Network", network_type="standard"): 252 | ### add a NIC 253 | # Different network card types are: "VirtualE1000", "VirtualE1000e","VirtualPCNet32", "VirtualVmxnet", "VirtualNmxnet2", "VirtualVmxnet3" 254 | nic_spec = config.new_deviceChange() 255 | nic_spec.set_element_operation("add") 256 | 257 | if nic_type == "e1000": 258 | nic_ctlr = VI.ns0.VirtualE1000_Def("nic_ctlr").pyclass() 259 | elif nic_type == "e1000e": 260 | nic_ctlr = VI.ns0.VirtualE1000e_Def("nic_ctlr").pyclass() 261 | elif nic_type == "pcnet32": 262 | nic_ctlr = VI.ns0.VirtualPCNet32_Def("nic_ctlr").pyclass() 263 | elif nic_type == "vmxnet": 264 | nic_ctlr = VI.ns0.VirtualVmxnet_Def("nic_ctlr").pyclass() 265 | elif nic_type == "vmxnet2": 266 | nic_ctlr = VI.ns0.VirtualVmxnet2_Def("nic_ctlr").pyclass() 267 | elif nic_type == "vmxnet3": 268 | nic_ctlr = VI.ns0.VirtualVmxnet3_Def("nic_ctlr").pyclass() 269 | else: 270 | s.disconnect() 271 | module.fail_json(msg="Error adding nic to vm spec. No nic type of: %s" % (nic_type)) 272 | 273 | if network_type == "standard": 274 | nic_backing = VI.ns0.VirtualEthernetCardNetworkBackingInfo_Def("nic_backing").pyclass() 275 | nic_backing.set_element_deviceName(network_name) 276 | elif network_type == "dvs": 277 | # Get the portgroup key 278 | portgroupKey = find_portgroup_key(module, s, nfmor, network_name) 279 | # Get the dvswitch uuid 280 | dvswitch_uuid = find_dvswitch_uuid(module, s, nfmor, portgroupKey) 281 | 282 | nic_backing_port = VI.ns0.DistributedVirtualSwitchPortConnection_Def("nic_backing_port").pyclass() 283 | nic_backing_port.set_element_switchUuid(dvswitch_uuid) 284 | nic_backing_port.set_element_portgroupKey(portgroupKey) 285 | 286 | nic_backing = VI.ns0.VirtualEthernetCardDistributedVirtualPortBackingInfo_Def("nic_backing").pyclass() 287 | nic_backing.set_element_port(nic_backing_port) 288 | else: 289 | s.disconnect() 290 | module.fail_json(msg="Error adding nic backing to vm spec. No network type of: %s" % (network_type)) 291 | 292 | 293 | nic_ctlr.set_element_addressType("generated") 294 | nic_ctlr.set_element_backing(nic_backing) 295 | nic_ctlr.set_element_key(4) 296 | nic_spec.set_element_device(nic_ctlr) 297 | devices.append(nic_spec) 298 | 299 | 300 | def find_datastore(module, s, datastore, config_target): 301 | # Verify the datastore exists and put it in brackets if it does. 302 | ds = None 303 | for d in config_target.Datastore: 304 | if (d.Datastore.Accessible and 305 | (datastore and d.Datastore.Name == datastore) 306 | or (not datastore)): 307 | ds = d.Datastore.Datastore 308 | datastore = d.Datastore.Name 309 | break 310 | if not ds: 311 | s.disconnect() 312 | module.fail_json(msg="Datastore: %s does not appear to exist" % (datastore)) 313 | 314 | datastore_name = "[%s]" % datastore 315 | return datastore_name, ds 316 | 317 | 318 | def find_portgroup_key(module, s, nfmor, network_name): 319 | # Find a portgroups key given the portgroup name. 320 | 321 | # Grab all the distributed virtual portgroup's names and key's. 322 | dvpg_mors = s._retrieve_properties_traversal(property_names=['name','key'], 323 | from_node=nfmor, obj_type='DistributedVirtualPortgroup') 324 | 325 | # Get the correct portgroup managed object. 326 | dvpg_mor = None 327 | for dvpg in dvpg_mors: 328 | if dvpg_mor: 329 | break 330 | for p in dvpg.PropSet: 331 | if p.Name == "name" and p.Val == network_name: 332 | dvpg_mor = dvpg 333 | if dvpg_mor: 334 | break 335 | 336 | # If dvpg_mor is empty we didn't find the named portgroup. 337 | if dvpg_mor == None: 338 | s.disconnect() 339 | module.fail_json(msg="Could not find the distributed virtual portgroup named %s" % network_name) 340 | 341 | # Get the portgroup key 342 | portgroupKey = None 343 | for p in dvpg_mor.PropSet: 344 | if p.Name == "key": 345 | portgroupKey = p.Val 346 | 347 | return portgroupKey 348 | 349 | def find_dvswitch_uuid(module, s, nfmor, portgroupKey): 350 | # Find a dvswitch's uuid given a portgroup key. 351 | # Function searches all dvswitches in the datacenter to find the switch that has the portgroup key. 352 | 353 | # Grab the dvswitch uuid and portgroup properties 354 | dvswitch_mors = s._retrieve_properties_traversal(property_names=['uuid','portgroup'], 355 | from_node=nfmor, obj_type='DistributedVirtualSwitch') 356 | 357 | dvswitch_mor = None 358 | # Get the dvswitches managed object 359 | for dvswitch in dvswitch_mors: 360 | if dvswitch_mor: 361 | break 362 | for p in dvswitch.PropSet: 363 | if p.Name == "portgroup": 364 | pg_mors = p.Val.ManagedObjectReference 365 | for pg_mor in pg_mors: 366 | if dvswitch_mor: 367 | break 368 | key_mor = s._get_object_properties(pg_mor, property_names=['key']) 369 | for key in key_mor.PropSet: 370 | if key.Val == portgroupKey: 371 | dvswitch_mor = dvswitch 372 | 373 | # Get the switches uuid 374 | dvswitch_uuid = None 375 | for p in dvswitch_mor.PropSet: 376 | if p.Name == "uuid": 377 | dvswitch_uuid = p.Val 378 | 379 | return dvswitch_uuid 380 | 381 | 382 | 383 | def main(): 384 | module = AnsibleModule( 385 | argument_spec = dict( 386 | vcenter_hostname = dict(required=True, type='str'), 387 | user = dict(required=True, type='str'), 388 | password = dict(required=True, type='str'), 389 | resource_pool = dict(required=False, default=None, type='str'), 390 | cluster = dict(required=False, default=None, type='str'), 391 | datacenter = dict(required=True, type='str'), 392 | datastore = dict(required=True, type='str'), 393 | esxi_hostname = dict(required=True, type='str'), 394 | power_on = dict(required=False, default='no', type='bool'), 395 | vm_name = dict(required=True, type='str'), 396 | vm_memory_mb = dict(required=False, default=1024), 397 | vm_num_cpus = dict(required=False, default=1), 398 | vm_scsi = dict(required=False, default="paravirtual", type='str'), 399 | vm_disk = dict(required=False, default=None, type='dict'), 400 | vm_nic = dict(required=False, default=None, type='dict'), 401 | vm_notes = dict(required=False, default=None, type='str'), 402 | vm_cdrom = dict(required=False, default=None, type='dict'), 403 | vm_extra_config = dict(required=False, default=None, type='dict'), 404 | guestosid = dict(required=True, type='str'), 405 | ), 406 | supports_check_mode = False, 407 | required_together = [ ['resource_pool','cluster'] ], 408 | ) 409 | 410 | if not HAS_PYSPHERE: 411 | module.fail_json(msg="pysphere is not installed") 412 | 413 | vcenter_hostname = module.params['vcenter_hostname'] 414 | user = module.params['user'] 415 | password = module.params['password'] 416 | resource_pool = module.params['resource_pool'] 417 | cluster_name = module.params['cluster'] 418 | datacenter = module.params['datacenter'] 419 | datastore = module.params['datastore'] 420 | esxi_hostname = module.params['esxi_hostname'] 421 | power_on = module.params['power_on'] 422 | vm_name = module.params['vm_name'] 423 | vm_memory_mb = int(module.params['vm_memory_mb']) 424 | vm_num_cpus = int(module.params['vm_num_cpus']) 425 | vm_scsi = module.params['vm_scsi'] 426 | vm_disk = module.params['vm_disk'] 427 | vm_nic = module.params['vm_nic'] 428 | vm_notes = module.params['vm_notes'] 429 | vm_cdrom = module.params['vm_cdrom'] 430 | vm_extra_config = module.params['vm_extra_config'] 431 | guestosid = module.params['guestosid'] 432 | 433 | 434 | # CONNECT TO THE SERVER 435 | s = VIServer() 436 | try: 437 | s.connect(vcenter_hostname, user, password) 438 | except VIApiException, err: 439 | module.fail_json(msg="Cannot connect to %s: %s" % (vcenter_hostname, err)) 440 | 441 | 442 | # Check if the VM exists before continuing 443 | try: 444 | vm = None 445 | vm = s.get_vm_by_name(vm_name) 446 | except: 447 | # VM doesn't exist, lets continue and create it. 448 | pass 449 | 450 | if vm: 451 | # If the vm already exists, lets get some info from it, pass back the vm's facts and then exit. 452 | s.disconnect() 453 | module.exit_json(changed=False, vcenter=vcenter_hostname, datacenter=datacenter, datastore=datastore, esxi_hostname=esxi_hostname, vm_name=vm_name, vm_memory_mb=vm_memory_mb, vm_num_cpus=vm_num_cpus, guestosid=guestosid, vm_disk=vm_disk, vm_nic=vm_nic) 454 | 455 | # GET INITIAL PROPERTIES AND OBJECTS 456 | 457 | # Datacenter managed object reference 458 | dcmor = [k for k,v in s.get_datacenters().items() if v==datacenter][0] 459 | 460 | if dcmor == None: 461 | s.disconnect() 462 | module.fail_json(msg="Cannot find datacenter named: %s" % datacenter) 463 | 464 | dcprops = VIProperty(s, dcmor) 465 | 466 | # hostFolder managed reference 467 | hfmor = dcprops.hostFolder._obj 468 | 469 | # virtualmachineFolder managed object reference 470 | vmfmor = dcprops.vmFolder._obj 471 | 472 | # networkFolder managed object reference 473 | nfmor = dcprops.networkFolder._obj 474 | 475 | # Grab the computerResource name and host properties 476 | crmors = s._retrieve_properties_traversal(property_names=['name','host'], 477 | from_node=hfmor, obj_type='ComputeResource') 478 | 479 | # Grab the host managed object reference of the esxi_hostname 480 | try: 481 | hostmor = [k for k,v in s.get_hosts().items() if v==esxi_hostname][0] 482 | except IndexError, e: 483 | s.disconnect() 484 | module.fail_json(msg="Cannot find esx host named: %s" % esxi_hostname) 485 | 486 | 487 | # Grab the computerResource managed object reference of the host we are creating the VM on. 488 | crmor = None 489 | for cr in crmors: 490 | if crmor: 491 | break 492 | for p in cr.PropSet: 493 | if p.Name == "host": 494 | for h in p.Val.get_element_ManagedObjectReference(): 495 | if h == hostmor: 496 | crmor = cr.Obj 497 | break 498 | if crmor: 499 | break 500 | crprops = VIProperty(s, crmor) 501 | 502 | # Get resource pool managed reference 503 | # Requires that a cluster name be specified. 504 | if resource_pool: 505 | try: 506 | cluster = [k for k,v in s.get_clusters().items() if v==cluster_name][0] 507 | except IndexError, e: 508 | s.disconnect() 509 | module.fail_json(msg="Cannot find Cluster named: %s" % cluster_name) 510 | 511 | try: 512 | rpmor = [k for k,v in s.get_resource_pools(from_mor=cluster).items() 513 | if v == resource_pool][0] 514 | except IndexError, e: 515 | s.disconnect() 516 | module.fail_json(msg="Cannot find Resource Pool named: %s" % resource_pool) 517 | 518 | else: 519 | rpmor = crprops.resourcePool._obj 520 | 521 | # CREATE VM CONFIGURATION 522 | # get config target 523 | request = VI.QueryConfigTargetRequestMsg() 524 | _this = request.new__this(crprops.environmentBrowser._obj) 525 | _this.set_attribute_type(crprops.environmentBrowser._obj.get_attribute_type ()) 526 | request.set_element__this(_this) 527 | h = request.new_host(hostmor) 528 | h.set_attribute_type(hostmor.get_attribute_type()) 529 | request.set_element_host(h) 530 | config_target = s._proxy.QueryConfigTarget(request)._returnval 531 | 532 | # get default devices 533 | request = VI.QueryConfigOptionRequestMsg() 534 | _this = request.new__this(crprops.environmentBrowser._obj) 535 | _this.set_attribute_type(crprops.environmentBrowser._obj.get_attribute_type ()) 536 | request.set_element__this(_this) 537 | h = request.new_host(hostmor) 538 | h.set_attribute_type(hostmor.get_attribute_type()) 539 | request.set_element_host(h) 540 | config_option = s._proxy.QueryConfigOption(request)._returnval 541 | default_devs = config_option.DefaultDevice 542 | 543 | # add parameters to the create vm task 544 | create_vm_request = VI.CreateVM_TaskRequestMsg() 545 | config = create_vm_request.new_config() 546 | vmfiles = config.new_files() 547 | datastore_name, ds = find_datastore(module, s, datastore, config_target) 548 | vmfiles.set_element_vmPathName(datastore_name) 549 | config.set_element_files(vmfiles) 550 | config.set_element_name(vm_name) 551 | if vm_notes != None: 552 | config.set_element_annotation(vm_notes) 553 | config.set_element_memoryMB(vm_memory_mb) 554 | config.set_element_numCPUs(vm_num_cpus) 555 | config.set_element_guestId(guestosid) 556 | devices = [] 557 | 558 | # Attach all the hardware we want to the VM spec. 559 | # Add a scsi controller to the VM spec. 560 | disk_ctrl_key = add_scsi_controller(module, s, config, devices, vm_scsi) 561 | if vm_disk: 562 | disk_num = 0 563 | disk_key = 0 564 | for disk in sorted(vm_disk.iterkeys()): 565 | try: 566 | datastore = vm_disk[disk]['datastore'] 567 | except KeyError: 568 | s.disconnect() 569 | module.fail_json(msg="Error on %s definition. datastore needs to be specified." % disk) 570 | try: 571 | disksize = vm_disk[disk]['size_gb'] 572 | # Convert the disk size to kiloboytes 573 | disksize = disksize * 1024 * 1024 574 | except KeyError: 575 | s.disconnect() 576 | module.fail_json(msg="Error on %s definition. size needs to be specified." % disk) 577 | try: 578 | disktype = vm_disk[disk]['type'] 579 | except KeyError: 580 | s.disconnect() 581 | module.fail_json(msg="Error on %s definition. type needs to be specified." % disk) 582 | # Add the disk to the VM spec. 583 | add_disk(module, s, config_target, config, devices, datastore, disktype, disksize, disk_ctrl_key, disk_num, disk_key) 584 | disk_num = disk_num + 1 585 | disk_key = disk_key + 1 586 | if vm_cdrom: 587 | cdrom_iso_path = None 588 | cdrom_type = None 589 | try: 590 | cdrom_type = vm_cdrom['type'] 591 | except KeyError: 592 | s.disconnect() 593 | module.fail_json(msg="Error on %s definition. cdrom type needs to be specified." % vm_cdrom) 594 | if cdrom_type == 'iso': 595 | try: 596 | cdrom_iso_path = vm_cdrom['iso_path'] 597 | except KeyError: 598 | s.disconnect() 599 | module.fail_json(msg="Error on %s definition. cdrom iso_path needs to be specified." % vm_cdrom) 600 | # Add a CD-ROM device to the VM. 601 | add_cdrom(module, s, config_target, config, devices, default_devs, cdrom_type, cdrom_iso_path) 602 | if vm_nic: 603 | dvswitch = None 604 | for nic in sorted(vm_nic.iterkeys()): 605 | try: 606 | nictype = vm_nic[nic]['type'] 607 | except KeyError: 608 | s.disconnect() 609 | module.fail_json(msg="Error on %s definition. type needs to be specified." % nic) 610 | try: 611 | network = vm_nic[nic]['network'] 612 | except KeyError: 613 | s.disconnect() 614 | module.fail_json(msg="Error on %s definition. network needs to be specified." % nic) 615 | try: 616 | network_type = vm_nic[nic]['network_type'] 617 | except KeyError: 618 | s.disconnect() 619 | module.fail_json(msg="Error on %s definition. network_type needs to be specified." % nic) 620 | # Add the nic to the VM spec. 621 | add_nic(module, s, nfmor, config, devices, nictype, network, network_type) 622 | 623 | 624 | config.set_element_deviceChange(devices) 625 | create_vm_request.set_element_config(config) 626 | folder_mor = create_vm_request.new__this(vmfmor) 627 | folder_mor.set_attribute_type(vmfmor.get_attribute_type()) 628 | create_vm_request.set_element__this(folder_mor) 629 | rp_mor = create_vm_request.new_pool(rpmor) 630 | rp_mor.set_attribute_type(rpmor.get_attribute_type()) 631 | create_vm_request.set_element_pool(rp_mor) 632 | host_mor = create_vm_request.new_host(hostmor) 633 | host_mor.set_attribute_type(hostmor.get_attribute_type()) 634 | create_vm_request.set_element_host(host_mor) 635 | 636 | # CREATE THE VM 637 | taskmor = s._proxy.CreateVM_Task(create_vm_request)._returnval 638 | task = VITask(taskmor, s) 639 | task.wait_for_state([task.STATE_SUCCESS, task.STATE_ERROR]) 640 | if task.get_state() == task.STATE_ERROR: 641 | s.disconnect() 642 | module.fail_json(msg="Error creating vm: %s" % task.get_error_message()) 643 | else: 644 | vm = None 645 | if vm_extra_config or power_on: 646 | vm = s.get_vm_by_name(vm_name) 647 | 648 | # VM was created. If there is any extra config options specified, set them here , disconnect from vcenter, then exit. 649 | if vm_extra_config: 650 | vm.set_extra_config(vm_extra_config) 651 | # Power on the VM if it was requested 652 | if power_on: 653 | vm.power_on(sync_run=False) 654 | 655 | s.disconnect() 656 | module.exit_json(changed=True, vcenter=vcenter_hostname, datacenter=datacenter, datastore=datastore, esxi_hostname=esxi_hostname, vm_name=vm_name, vm_memory_mb=vm_memory_mb, vm_num_cpus=vm_num_cpus, guestosid=guestosid, vm_disk=vm_disk, vm_nic=vm_nic) 657 | 658 | # this is magic, see lib/ansible/module_common.py 659 | #<> 660 | main() 661 | --------------------------------------------------------------------------------