task = vm.ReconfigVM_Task(config_spec) self.wait_for_tasks([task]) return raise VmCLIException('Unable to find ethernet device on a specified target!') @args('--vHWversion', help='VM hardware version number to assign to the VM or \'latest\'', metavar='VER') def change_vHWversion(self, name, vHWversion=None): """Changes VM HW version. If version is None, then VM is set to the latest version.""" vm = self.get_vm_obj(name, fail_missing=True) if vHWversion == 'latest': version = None # None will default to latest so we don't need to search for it else: try: version = 'vmx-{:02d}'.format(vHWversion) except ValueError: raise VmCLIException('VM version must be integer or \'latest\'! Aborting...') if vm.runtime.powerState != 'poweredOff': raise VmCLIException('VM hardware version change cannot be performed on running VM! Aborting...') self.logger.info('Updating VM hardware version...') try: task = vm.UpgradeVM_Task(version=version) self.wait_for_tasks([task]) except vim.fault.AlreadyUpgraded: pass BaseCommands.register('modify', ModifyCommands)
return self.get_snapshot_by_name(snap.childSnapshotList, name) @args('--desc', help='snapshot description (required when action==create)') @args('--memory', help='snapshot VM memory (default is False)', action='store_true', default=False) @args('--quiesce', help='quiesce VM filesystem (default is True)', action='store_true', default=True) def create_snapshot(self, vm, snapshot, desc, memory, quiesce): """Creates new snapshot on the VM.""" if desc is None: raise VmCLIException('Argument --desc is required with "create" operation!') self.logger.info('Creating snapshot of the virtual machine...') task = vm.CreateSnapshot_Task(name=snapshot, description=desc, memory=memory, quiesce=quiesce) self.wait_for_tasks([task]) def delete_snapshot(self, vm, snapshot): """Deletes specific snapshot on the VM.""" snap = self.get_snapshot_by_name(vm.snapshot.rootSnapshotList, snapshot) self.logger.info('Deleting snapshot from the virtual machine...') task = snap.snapshot.RemoveSnapshot_Task(removeChildren=False) self.wait_for_tasks([task]) def revert_snapshot(self, vm, snapshot): """Reverts VM to a specific snapshot.""" snap = self.get_snapshot_by_name(vm.snapshot.rootSnapshotList, snapshot) self.logger.info('Reverting VM to specified snapshot...') task = snap.snapshot.RevertToSnapshot_Task() self.wait_for_tasks([task]) BaseCommands.register('snapshot', SnapshotCommands)
vm = self.get_vm_obj(name, fail_missing=True) controller = None cdrom_device_key = 3000 # 300x reserved for cd/dvd drives in vmware # Find last IDE controller and free device key for device in vm.config.hardware.device: if isinstance(device, vim.vm.device.VirtualIDEController): controller = device if isinstance(device, vim.vm.device.VirtualCdrom): cdrom_device_key = int(device.key) + 1 cdspec = vim.vm.device.VirtualDeviceSpec() cdspec.operation = vim.vm.device.VirtualDeviceSpec.Operation.add cdspec.device = vim.vm.device.VirtualCdrom(deviceInfo=vim.Description( label='CD/DVD drive 1', summary='Remote device')) cdspec.device.key = cdrom_device_key cdspec.device.controllerKey = controller.key cdspec.device.backing = vim.vm.device.VirtualCdrom.RemotePassthroughBackingInfo( deviceName='', useAutoDetect=False, exclusive=False) cdspec.device.connectable = vim.vm.device.VirtualDevice.ConnectInfo( startConnected=False, allowGuestControl=True, connected=False, status='untried') config_spec = vim.vm.ConfigSpec(deviceChange=[cdspec]) self.logger.info('Attaching device to the virtual machine...') task = vm.ReconfigVM_Task(config_spec) self.wait_for_tasks([task]) BaseCommands.register('attach', AttachCommands)
self.logger.info('Running cloning operation...') if ds_type == 'cluster': storagespec = vim.storageDrs.StoragePlacementSpec( cloneName=name, vm=template, resourcePool=resource_pool, folder=folder, type='clone') storagespec.cloneSpec = vim.vm.CloneSpec(location=vim.vm.RelocateSpec(pool=resource_pool), powerOn=poweron) storagespec.cloneSpec.config = vim.vm.ConfigSpec(name=name, memoryMB=mem, numCPUs=cpu, annotation=name) storagespec.podSelectionSpec = vim.storageDrs.PodSelectionSpec(storagePod=datastore) storagePlacementResult = self.content.storageResourceManager.RecommendDatastores(storageSpec=storagespec) try: # Pick first recommendation as vSphere Client does drs_key = storagePlacementResult.recommendations[0].key if not drs_key: raise ValueError except ValueError: self.exit('No storage DRS recommentation provided for cluster {}, exiting...'.format(datastore.name)) task = self.content.storageResourceManager.ApplyStorageDrsRecommendation_Task(drs_key) self.wait_for_tasks([task]) elif ds_type == 'specific': relocspec = vim.vm.RelocateSpec(datastore=datastore, pool=resource_pool) configspec = vim.vm.ConfigSpec(name=name, memoryMB=mem, numCPUs=cpu, annotation=name) clonespec = vim.vm.CloneSpec(config=configspec, location=relocspec, powerOn=poweron) task = template.Clone(folder=folder, name=name, spec=clonespec) self.wait_for_tasks([task]) BaseCommands.register('clone', CloneCommands)
return (datacenter, folder, root_obj) def get_vm_datastore_name(self, vm_ds_node, root_obj): """Retrieves name of main datastore, where VM is placed. If possible, name of datastore cluster is returned.""" datastore = 'N/A' for dshost in root_obj.datastoreFolder.childEntity: if isinstance(dshost, vim.StoragePod): for ds in dshost.childEntity: if ds.name == vm_ds_node: return dshost.name elif dshost.name == vm_ds_node: return dshost.name return datastore def get_vm_cluster_name(self, vm_cl_node, root_obj): """Retrieves Compute Cluster or Node name by iterating over Compute nodes.""" cluster = 'N/A' for clhost in root_obj.hostFolder.childEntity: if isinstance(clhost, vim.ClusterComputeResource): for cl in clhost.host: if cl.name == vm_cl_node: return clhost.name elif clhost.name == vm_cl_node: return clhost.name return cluster BaseCommands.register('list', ListCommands)
try: # Pick first recommendation as vSphere Client does drs_key = storagePlacementResult.recommendations[0].key if not drs_key: raise ValueError except ValueError: self.exit( 'No storage DRS recommentation provided for cluster {}, exiting...' .format(datastore.name)) task = self.content.storageResourceManager.ApplyStorageDrsRecommendation_Task( drs_key) self.wait_for_tasks([task]) elif ds_type == 'specific': relocspec = vim.vm.RelocateSpec(datastore=datastore, pool=resource_pool) configspec = vim.vm.ConfigSpec(name=name, memoryMB=mem, numCPUs=cpu, annotation=name) clonespec = vim.vm.CloneSpec(config=configspec, location=relocspec, powerOn=poweron) task = template.Clone(folder=folder, name=name, spec=clonespec) self.wait_for_tasks([task]) BaseCommands.register('clone', CloneCommands)
if ip and gateway: # expects script inside template commands = [ '/bin/bash /usr/share/vmcli/provision-interfaces.sh {} {} {} {} {}' .format(ip.ip, ip.netmask, gateway, ip.network, ip.broadcast) ] execute.exec_inside_vm(vm, commands, args.guest_user, args.guest_pass, wait_for_tools=True) if conf.VM_ADDITIONAL_CMDS: execute.exec_inside_vm(vm, conf.VM_ADDITIONAL_CMDS, args.guest_user, args.guest_pass, wait_for_tools=True) self.logger.info('Deployed vm {}'.format(args.name)) # Execute callbacks from callbacks/ directory if args.callback: execute.exec_callbacks(args, args.callback) BaseCommands.register('create', CreateVmCommandBundle) BaseCommands.register('create-empty', CreateEmptyVmCommands)
vm = self.get_vm_obj(name, fail_missing=True) # Get vmware ID representation in form 'vm-XXX' for later association vm_id = vm._GetMoId() vm_dynid = DynamicID(type='VirtualMachine', id=vm_id) # Create API services for Tag and TagAssociation backends tag_svc = Tag(stub_config) tag_asoc = TagAssociation(stub_config) # Search for tag object(s) tags_found = [] if ',' in tags: tags = tags.split(',') else: tags = [tags] for t in tag_svc.list(): tag = tag_svc.get(t) if tag.name in tags: tags_found.append(tag) if len(tags_found) != len(tags): raise VmCLIException('One or more tags were not found') # Asosociate tags with VM for tag in tags_found: tag_asoc.attach(tag_id=tag.id, object_id=vm_dynid) self.logger.info('All tags have been attached to the VM') BaseCommands.register('tag', TagCommands)
# Find last IDE controller and free device key for device in vm.config.hardware.device: if isinstance(device, vim.vm.device.VirtualIDEController): controller = device if isinstance(device, vim.vm.device.VirtualCdrom): cdrom_device_key = int(device.key) + 1 cdspec = vim.vm.device.VirtualDeviceSpec() cdspec.operation = vim.vm.device.VirtualDeviceSpec.Operation.add cdspec.device = vim.vm.device.VirtualCdrom(deviceInfo=vim.Description( label='CD/DVD drive 1', summary='Remote device')) cdspec.device.key = cdrom_device_key cdspec.device.controllerKey = controller.key cdspec.device.backing = vim.vm.device.VirtualCdrom.RemotePassthroughBackingInfo( deviceName='', useAutoDetect=False, exclusive=False) cdspec.device.connectable = vim.vm.device.VirtualDevice.ConnectInfo( startConnected=False, allowGuestControl=True, connected=False, status='untried') config_spec = vim.vm.ConfigSpec(deviceChange=[cdspec]) self.logger.info('Attaching device to the virtual machine...') task = vm.ReconfigVM_Task(config_spec) self.wait_for_tasks([task]) BaseCommands.register('attach', AttachCommands)
First argument to executable is always JSON object containing all arguments passed to vmcli and its subcommands via cli. Following are arguments passed as a value via command line argument callback. For example, this --callback 'var1; var2; multi word var' will be passed as: ./callbacks/script.sh '{"name": "..", "template": ...}' 'var1' 'var2' 'multi word var' """ # Parse additional callback arguments passed from command line if callback_args: callback_args = [x.lstrip() for x in callback_args.rstrip(';').split(';')] else: callback_args = [] # Get all callback scripts callbacks_dir = sorted(os.listdir('callbacks/')) callbacks = [os.path.realpath('callbacks/' + x) for x in callbacks_dir if not x.startswith('.')] # Prepare JSON serializable object from args namespace arguments = {} for argument in [x for x in dir(args) if not x.startswith('_')]: arguments[argument] = getattr(args, argument, None) arguments = json.dumps(arguments) for executable in callbacks: self.logger.info('Running callback "{}" ...'.format(executable)) command = [executable, arguments] command.extend(callback_args) try: subprocess.Popen(command).communicate() except OSError: raise VmCLIException('Unable to execute callback {}! Check it for errors'.format(executable)) BaseCommands.register('exec', ExecCommands)
elif args.off: self.poweroff_vm(args.name) elif args.reboot: self.reboot_vm(args.name) elif args.reset: self.reset_vm(args.name) elif args.show: vm = self.get_obj('vm', args.name) print(vm.runtime.powerState) def poweron_vm(self, name): vm = self.get_vm_obj(name, fail_missing=True) if vm.runtime.powerState == 'poweredOff': self.wait_for_tasks([vm.PowerOnVM_Task()]) def poweroff_vm(self, name): vm = self.get_vm_obj(name, fail_missing=True) if vm.runtime.powerState == 'poweredOn': self.wait_for_tasks([vm.PowerOffVM_Task()]) def reboot_vm(self, name): vm = self.get_vm_obj(name, fail_missing=True) self.wait_for_tasks([vm.RebootGuest()]) def reset_vm(self, name): vm = self.get_vm_obj(name, fail_missing=True) self.wait_for_tasks([vm.ResetVM_Task()]) BaseCommands.register('power', PowerCommands)
callback_args = [ x.lstrip() for x in callback_args.rstrip(';').split(';') ] else: callback_args = [] # Get all callback scripts callbacks_dir = sorted(os.listdir('callbacks/')) callbacks = [ os.path.realpath('callbacks/' + x) for x in callbacks_dir if not x.startswith('.') ] # Prepare JSON serializable object from args namespace arguments = {} for argument in [x for x in dir(args) if not x.startswith('_')]: arguments[argument] = getattr(args, argument, None) arguments = json.dumps(arguments) for executable in callbacks: self.logger.info('Running callback "{}" ...'.format(executable)) command = [executable, arguments] command.extend(callback_args) try: subprocess.Popen(command).communicate() except OSError: raise VmCLIException( 'Unable to execute callback {}! Check it for errors'. format(executable)) BaseCommands.register('exec', ExecCommands)