def test_error(self, fake_time): """``consume_task`` - raises RuntimeError if the task complete with an error""" fake_task = MagicMock() fake_task.info.error.msg = 'someError' fake_task.info.result = 'woot' with self.assertRaises(RuntimeError): task_lib.consume_task(fake_task, timeout=2)
def test_timeout(self, fake_time): """``consume_task`` raises RuntimeError if the task does not complete within the timeout""" fake_task = MagicMock() fake_task.info.completeTime = None fake_task.info.error = None fake_task.info.result = 'woot' with self.assertRaises(RuntimeError): task_lib.consume_task(fake_task, timeout=2)
def adjust_cpu(the_vm, cpu_count): """Set the number of CPUs for a VM **IMPORTANT** Make sure your VM is powered off before calling this function, otherwise it'll fail. :param the_vm: The virtual machine to adjust CPU count on :type the_vm: vim.VirtualMachine :param cpu_count: The number of CPU cores to allocate to the VM :type cpu_count: Integer """ config_spec = vim.vm.ConfigSpec() config_spec.numCPUs = cpu_count consume_task(the_vm.Reconfigure(config_spec))
def test_happy_path(self, fake_time): """``consume_task`` - Works as expected when there are no issues""" fake_task = MagicMock() fake_task.info.error = None fake_task.info.result = 'woot' result = task_lib.consume_task(fake_task, timeout=2) expected = 'woot' self.assertEqual(result, expected)
def test_blocks(self, fake_time): """``consume_task`` - Blocks until the task is complete""" fake_task = MagicMock() fake_task.info.error = None fake_task.info.result = 'woot' fake_task.info.completeTime.side_effect = [None, 'someTimestamp'] result = task_lib.consume_task(fake_task, timeout=5) expected = 'woot' self.assertEqual(result, expected)
def adjust_ram(the_vm, mb_of_ram): """Set the amount of RAM for a VM **IMPORTANT** Most VMs are required to be powered off in order to adjust RAM. Unless you know that your guest OS supports hot-swap RAM, power your VM off before changing how much RAM it has. :Returns: None :param the_vm: The virtual machine to adjust RAM on :type the_vm: vim.VirtualMachine :param mb_of_ram: The number of MB of RAM/memory to give the virtual machine :type mb_of_ram: Integer """ config_spec = vim.vm.ConfigSpec() config_spec.memoryMB = mb_of_ram consume_task(the_vm.Reconfigure(config_spec))
def configure_network(the_vm, ip_config): """Set a static IP and related network settings for a Linux VM with VMware Tools installed. The ``ip_config`` dictionary MUST have the following keys: - static-ip - netmask - default-gateway - dns - domain :Returns: None :param the_vm: The pyVmomi Virtual machine object :type the_vm: vim.VirtualMachine :param ip_config: The dictionary containing the static network information. :type ip_config: Dictionary """ # Boilerplate... adaptermap = vim.vm.customization.AdapterMapping() globalip = vim.vm.customization.GlobalIPSettings() adaptermap.adapter = vim.vm.customization.IPSettings() # Configure IP & DNS adaptermap.adapter.ip = vim.vm.customization.FixedIp() adaptermap.adapter.ip.ipAddress = ip_config['static-ip'] adaptermap.adapter.subnetMask = ip_config['netmask'] adaptermap.adapter.gateway = ip_config['default-gateway'] globalip.dnsServerList = ip_config['dns'] adaptermap.adapter.dnsDomain = ip_config['domain'] ident = vim.vm.customization.LinuxPrep() ident.domain = ip_config['domain'] ident.hostName = vim.vm.customization.FixedName() ident.hostName.name = the_vm.name # Create the configuration spec spec = vim.vm.customization.Specification() spec.nicSettingMap = [adaptermap] spec.globalIPSettings = globalip spec.identity = ident task = the_vm.Customize(spec=spec) consume_task(task)
def change_network(the_vm, network, adapter_label='Network adapter 1'): """Update the VM; replace existing network with the supplied network. :Returns: None :param the_vm: The virtual machine to update :type the_vm: vim.VirtualMachine :param network: The new network the VM should be connected to :type network: vim.Network :param adapter_label: The name of the virtual NIC to connect to a new device :type adapter_label: String """ devices = [ x for x in the_vm.config.hardware.device if x.deviceInfo.label == adapter_label ] if not devices: error = "VM has no network adapter named {}".format(adapter_label) raise RuntimeError(error) else: device = devices[0] nicspec = vim.vm.device.VirtualDeviceSpec() nicspec.operation = vim.vm.device.VirtualDeviceSpec.Operation.edit nicspec.device = device nicspec.device.wakeOnLanEnabled = True dvs_port_connection = vim.dvs.PortConnection() dvs_port_connection.portgroupKey = network.key dvs_port_connection.switchUuid = network.config.distributedVirtualSwitch.uuid nicspec.device.backing = vim.vm.device.VirtualEthernetCard.DistributedVirtualPortBackingInfo( ) nicspec.device.backing.port = dvs_port_connection nicspec.device.connectable = vim.vm.device.VirtualDevice.ConnectInfo() nicspec.device.connectable.startConnected = True nicspec.device.connectable.allowGuestControl = True nicspec.device.connectable.connected = True config_spec = vim.vm.ConfigSpec(deviceChange=[nicspec]) consume_task(the_vm.ReconfigVM_Task(config_spec))
def power(the_vm, state, timeout=600): """Turn on/off/restart a given virtual machine. Turning off and restarting do **not** perform graceful shutdowns; it's like pulling the power cable. This method blocks until the VM is in the requested power state. :Returns: Boolean :param the_vm: The pyVmomi Virtual machine object :type the_vm: vim.VirtualMachine :param state: The power state to put the VM into. Valid values are "on" "off" and "restart" :type state: Enum/String :param timeout: Optional - How long (in milliseconds) to block waiting on a given power state :type timeout: Integer """ valid_states = {'on', 'off', 'restart'} if state not in valid_states: error = 'state must be one of {}, supplied {}'.format( valid_states, state) raise ValueError(error) vm_power_state = the_vm.runtime.powerState.lower().replace('powered', '') if vm_power_state == state: return True elif (state == 'on') or (vm_power_state == 'off' and state == 'restart'): task = the_vm.PowerOn() elif state == 'off': task = the_vm.PowerOff() elif state == 'restart': task = the_vm.ResetVM_Task() try: consume_task(task, timeout=timeout) except RuntimeError: # task failed or timed out return False return True
def add_vmdk(the_vm, disk_size): """Add a new VMDK to an existing Virtual Machine. :Returns: None :Rasies: RuntimeError :param the_vm: The pyVmomi Virtual machine object :type the_vm: vim.VirtualMachine :param disk_size: The number of GB to make the disk :type disk_size: Integer """ spec = vim.vm.ConfigSpec() unit_number = 0 for dev in the_vm.config.hardware.device: if hasattr(dev.backing, 'fileName'): unit_number = int(dev.unitNumber) + 1 # unitNumber 7 is reserved for the SCSI controller if unit_number == 7: unit_number += 1 if unit_number >= 16: raise RuntimeError('VMs cannot have more than 16 VMDKs') if unit_number == 0: raise RuntimeError('Unable to find any VMDKs for VM') dev_changes = [] disk_spec = vim.vm.device.VirtualDeviceSpec() disk_spec.fileOperation = "create" disk_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.add disk_spec.device = vim.vm.device.VirtualDisk() disk_spec.device.backing = vim.vm.device.VirtualDisk.FlatVer2BackingInfo() disk_spec.device.backing.thinProvisioned = True disk_spec.device.backing.diskMode = 'persistent' disk_spec.device.unitNumber = unit_number disk_spec.device.capacityInKB = int(disk_size) * 1024 * 1024 disk_spec.device.controllerKey = 1000 dev_changes.append(disk_spec) spec.deviceChange = dev_changes consume_task(the_vm.ReconfigVM_Task(spec=spec))
def set_meta(the_vm, meta_data): """Truncate and replace the meta data associated with a given virtual machine. :Returns: None :Raises: ValueError - when invalid meta data supplied :param the_vm: The virtual machine to assign the meta data to :type the_vm: vim.VirtualMachine :param meta_data: The extra information to associate to the virtual machine :type meta_data: Dictionary """ expected = {'component', 'created', 'version', 'generation', 'configured'} provided = set(meta_data.keys()) if not expected.issubset(provided): error = "Invalid meta data schema. Supplied: {}, Required: {}".format( provided, expected) raise ValueError(error) spec = vim.vm.ConfigSpec() spec_info = ujson.dumps(meta_data) spec.annotation = spec_info task = the_vm.ReconfigVM_Task(spec) consume_task(task)