From 3dca5d510a195304e7e4b1d362575c8206e08a73 Mon Sep 17 00:00:00 2001 From: Richard Hoop Date: Mon, 21 Apr 2014 16:38:31 -0400 Subject: [PATCH] Large cleanups. Reintegrating all modules together for a guest --- cloud/vsphere_guest | 328 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 328 insertions(+) create mode 100644 cloud/vsphere_guest diff --git a/cloud/vsphere_guest b/cloud/vsphere_guest new file mode 100644 index 00000000000..cf75e3946e3 --- /dev/null +++ b/cloud/vsphere_guest @@ -0,0 +1,328 @@ +#!/usr/bin/python2 + +# -*- coding: utf-8 -*- + +# TODO: +# Ability to set CPU/Memory reservations + +try: + import json +except ImportError: + import simplejson as json + +DOCUMENTATION = ''' +--- +module: vsphere_client +short_description: Creates a virtual guest on vsphere. +description: + - Communicates with vsphere, creating a new virtual guest OS based on + the specifications you specify to the module. +version_added: "1.1" +options: + vcenter_hostname: + description: + - The hostname of the vcenter server the module will connect to, to create the guest. + required: true + default: null + aliases: [] + user: + description: + - username of the user to connect to vcenter as. + required: true + default: null + password: + description: + - password of the user to connect to vcenter as. + required: true + default: null + resource_pool: + description: + - The name of the resource_pool to create the VM in. + required: false + default: None + cluster: + description: + - 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. + required: false + default: None + datacenter: + description: + - The name of the datacenter to create the VM in. + required: true + default: null + datastore: + description: + - The datastore to store the VMs config files in. (Hard-disk locations are specified separately.) + required: true + default: null + esxi_hostname: + description: + - The hostname of the esxi host you want the VM to be created on. + required: true + default: null + power_on: + description: + - Whether or not to power on the VM after creation. + required: false + default: no + choices: [yes, no] + vm_name: + description: + - The name you want to call the VM. + required: true + default: null + vm_memory_mb: + description: + - How much memory in MB to give the VM. + required: false + default: 1024 + vm_num_cpus: + description: + - How many vCPUs to give the VM. + required: false + default: 1 + vm_scsi: + description: + - The type of scsi controller to add to the VM. + required: false + default: "paravirtual" + choices: [paravirtual, lsi, lsi_sas, bus_logic] + vm_disk: + description: + - A key, value list of disks and their sizes and which datastore to keep it in. + required: false + default: null + vm_nic: + description: + - A key, value list of nics, their types and what network to put them on. + required: false + default: null + choices: [vmxnet3, vmxnet2, vmxnet, e1000, e1000e, pcnet32] + vm_notes: + description: + - Any notes that you want to show up in the VMs Annotations field. + required: false + default: null + vm_cdrom: + description: + - A path, including datastore, to an ISO you want the CDROM device on the VM to have. + required: false + default: null + vm_extra_config: + description: + - 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. + required: false + default: null + guestosid: + description: + - "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: + http://www.vmware.com/support/developer/vc-sdk/visdk41pubs/ApiReference/vim.vm.GuestOsDescriptor.GuestOsIdentifier.html" + required: true + default: null +# informational: requirements for nodes +requirements: [ pysphere ] +author: Romeo Theriault +''' + + +def power_state(vm, state, force): + + power_status = vm.get_status() + + check_status = ' '.join(state.split("_")).upper() + + # Need Force + if not force and power_status in [ + 'SUSPENDED', 'POWERING ON', + 'RESETTING', 'BLOCKED ON MSG' + ]: + + return "VM is in %s power state. Force is required!" % power_status + + # State is already true + if power_status == check_status: + return False + + else: + try: + if state == 'powered_off': + vm.power_off(sync_run=True) + + elif state == 'powered_on': + vm.power_on(sync_run=True) + + elif state == 'restarted': + if power_status in ('POWERED ON', 'POWERING ON', 'RESETTING'): + vm.reset(sync_run=False) + else: + return "Cannot restart VM in the current state %s" \ + % power_status + return True + + except Exception, e: + return e + + return False + + +def gather_facts(vm): + """ + Gather facts for VM directly from vsphere. + """ + vm.get_properties() + facts = { + 'module_hw': True, + 'hw_name': vm.properties.name, + 'hw_guest_full_name': vm.properties.config.guestFullName, + 'hw_guest_id': vm.properties.config.guestId, + 'hw_product_uuid': vm.properties.config.uuid, + 'hw_processor_count': vm.properties.config.hardware.numCPU, + 'hw_memtotal_mb': vm.properties.config.hardware.memoryMB, + } + + ifidx = 0 + for entry in vm.properties.config.hardware.device: + + if not hasattr(entry, 'macAddress'): + continue + + factname = 'hw_eth' + str(ifidx) + facts[factname] = { + 'addresstype': entry.addressType, + 'label': entry.deviceInfo.label, + 'macaddress': entry.macAddress, + 'macaddress_dash': entry.macAddress.replace(':', '-'), + 'summary': entry.deviceInfo.summary, + } + + ifidx += 1 + + return facts + + +def main(): + + vm = None + + module = AnsibleModule( + argument_spec=dict( + vcenter_hostname=dict(required=True, type='str'), + username=dict(required=True, type='str'), + password=dict(required=True, type='str'), + state=dict( + required=False, + choices=[ + 'powered_on', + 'powered_off', + 'present', + 'absent', + 'restarted', + 'reconfigured' + ], + default='present'), + vmware_guest_facts=dict(required=False, choices=BOOLEANS), + guest=dict(required=True, type='str'), + guest_config=dict(required=False, type='dict', default={}), + force=dict(required=False, choices=BOOLEANS, default=False), + + ), + supports_check_mode=False, + mutually_exclusive=[['state', 'vmware_guest_facts']], + required_together=[ + ['state', 'force'], + ['state', 'guest_config'] + ], + ) + + try: + from pysphere import VIServer, VIProperty, MORTypes + from pysphere.resources import VimService_services as VI + from pysphere.vi_task import VITask + from pysphere import VIException, VIApiException, FaultTypes + except ImportError, e: + module.fail_json(msg='pysphere module required') + + vcenter_hostname = module.params['vcenter_hostname'] + username = module.params['username'] + password = module.params['password'] + vmware_guest_facts = module.params['vmware_guest_facts'] + state = module.params['state'] + guest = module.params['guest'] + force = module.params['force'] + guest_config = module.params['guest_config'] + + # CONNECT TO THE SERVER + viserver = VIServer() + try: + viserver.connect(vcenter_hostname, username, password) + except VIApiException, err: + module.fail_json(msg="Cannot connect to %s: %s" % + (vcenter_hostname, err)) + + # Check if the VM exists before continuing + try: + vm = viserver.get_vm_by_name(guest) + + # Run for facts only + if vmware_guest_facts: + try: + module.exit_json(ansible_facts=gather_facts(vm)) + except Exception, e: + module.fail_json( + msg="Fact gather failed with exception %s" % e) + + # Power Changes + elif state in ['powered_on', 'powered_off', 'restarted']: + state_result = power_state(vm, state, force) + + # Failure + if isinstance(state_result, basestring): + module.fail_json(msg=state_result) + else: + module.exit_json(changed=state_result) + + # Just check if there + elif state == 'present' and not len(guest_config): + module.exit_json(changed=False) + + # Fail on reconfig without params + elif state == 'reconfigured': + if not len(guest_config): + module.fail_json( + msg="guest_config is required to reconfigure a VM") + # do it + else: + pass + + # VM doesn't exist + except Exception: + + # Fail for fact gather task + if vmware_guest_facts: + module.fail_json( + msg="No such VM %s. Fact gathering requires an existing vm" + % guest) + if state not in ['absent', 'present']: + module.fail_json( + msg="No such VM %s. States [powered_on, powered_off, " + "restarted, reconfigured] required an existing VM" % guest) + elif state == 'absent': + module.exit_json(changed=False, msg="vm %s not present" % guest) + + # Create the VM + elif state == 'present': + pass + + if vm: + # If the vm already exists, lets get some info from it, pass back the + # vm's vmware_guest_facts and then exit. + viserver.disconnect() + module.exit_json( + changed=False, + vcenter=vcenter_hostname) + + +# this is magic, see lib/ansible/module_common.py +#<> +main()