class Datastore: def __init__(self, name="datastore1", datacenter='ha-datacenter'): self.name = name self.datacenter = datacenter self.sdk = Sdk() def datastore(self): return self.sdk.get_object(pyVmomi.vim.Datastore, self.name) def delete(self, target): item_path = f'[{self.name}]/{target}'.replace('//','/') return self.delete_path(item_path) def delete_path(self, item_path): content = self.sdk.content() datacenter = self.sdk.datacenter() try: task = content.fileManager.DeleteDatastoreFile_Task(item_path, datacenter) Task().wait_for_task(task) if task.info.state == "success": return True except Exception as error: print(f"[Error][delete] {error.msg}") # todo: add global error handler and use it here return False def info(self): info = self.datastore().info vmfs = info.vmfs data = { "Capacity": self.sizeof_fmt(vmfs.capacity) , "Name" : info.name , "Type" : vmfs.type , "SSD" : vmfs.ssd , "UUID" : vmfs.uuid , } return data def add_query_details_to_search_spec(self,search_spec): query_details = pyVmomi.vim.host.DatastoreBrowser.FileInfo.Details(fileOwner = True, fileSize = True, fileType = True, modification = True) search_spec.details = query_details return self def execute_search_task(self, search_function, search_spec): self.add_query_details_to_search_spec(search_spec) task = search_function("[%s]" % self.name, search_spec) Task().wait_for_task(task) return task.info.result def get_search_data__for_files(self, search_results): data = [] for item in search_results: #print(item) for file in item.file: data.append({ "Folder_path": item.folderPath , "Modified" : str(file.modification) , "Owner" : file.owner , "FileName" : file.path , "Size" : self.sizeof_fmt(file.fileSize), "Type" : type(file).__name__.replace('vim.host.DatastoreBrowser.','') }) return data def get_search_data__for_folders(self, search_results): data = [] for item in search_results: data.append({ "Modified" : str(item.modification) , "Owner" : item.owner , "FolderName": item.path , "Size" : self.sizeof_fmt(item.fileSize) }) return data def file_delete(self, folder_name, file_name): file_path = f"{folder_name}/{file_name}" return self.delete(file_path) @index_by @group_by def files(self, match_pattern="*"): search_function = self.datastore().browser.SearchDatastoreSubFolders_Task search_spec = pyVmomi.vim.HostDatastoreBrowserSearchSpec() search_spec.matchPattern = match_pattern search_results = self.execute_search_task(search_function, search_spec) return self.get_search_data__for_files(search_results) def files_names(self, match_pattern="*"): return sorted(list(set(self.files(match_pattern, index_by='FileName')))) def files_paths(self, match_pattern="*"): files = self.files(match_pattern) paths = [] for file in files: path = f"{file['Folder_path']}/{file['FileName']}" #path = path.replace(f'[{self.name}] ', "") # remove datastore from path paths.append(path) return sorted(paths) # note the content.fileManager.MakeDirectory doesn't return a Task so need to keep an eye on this for side effect # it might be that these legacy methods do the folder creation in a sync way (vs a task) def folder_create(self, folder_name): folder_path = f'[{self.name}]/{folder_name}' content = self.sdk.content() datacenter = self.sdk.datacenter() content.fileManager.MakeDirectory(name=folder_path, datacenter=datacenter, createParentDirectories=True) # this method doesn't return a task #Task().wait_for_task(task) return True def folder_delete(self, folder_name): return self.delete(folder_name) @index_by @group_by def folders(self, match_pattern="*"): search_function = self.datastore().browser.SearchSubFolders query_folder = pyVmomi.vim.host.DatastoreBrowser.FolderQuery() search_spec = pyVmomi.vim.host.DatastoreBrowser.SearchSpec(query=[query_folder]) search_spec.matchPattern = match_pattern search_results = self.execute_search_task(search_function, search_spec) return self.get_search_data__for_folders(search_results[0].file) def folders_names(self, match_pattern="*"): return sorted(list(set(self.folders(match_pattern, index_by="FolderName")))) def sizeof_fmt(self, num): """ Returns the human readable version of a file size :param num: :return: """ for item in ['bytes', 'KB', 'MB', 'GB']: if num < 1024.0: return "%3.1f %s" % (num, item) num /= 1024.0 return "%3.1f %s" % (num, 'TB')
class test_Sdk(TestCase_VM): vm_name = f"tests__unit__" + __name__ def setUp(self): self.sdk = Sdk() def test_about(self): content = self.sdk.about() assert content.vendor == "VMware, Inc." assert content.version == "6.7.0" assert content.licenseProductName == "VMware ESX Server" assert content.licenseProductName == "VMware ESX Server" assert content.licenseProductVersion == "6.0" def test_file_info(self): datastore_path = 'an data store' vmx_file = self.sdk.file_info(datastore_path) assert vmx_file.vmPathName == datastore_path # def test_find_iso(self): # vm = self.sdk.find_by_host_name('haproxy-icap') # #pprint(vm.info()) # #print(self.sdk.json_dump("VirtualMachine","42")) # #vim.vm.device.VirtualCdrom # print(vm.config().hardware) def test_find_by_host_name(self): for vm in self.sdk.vms(): host_name = vm.host_name() if host_name: assert self.sdk.find_by_host_name( host_name).host_name() == host_name return print( "Warning test ESX server had no VMs with host_names (dnsNames) setup" ) def test_find_by_name(self): assert self.sdk.find_by_name(self.vm_name).name() == self.vm_name assert self.sdk.find_by_name("AAA_BBB_CCC") is None def test_find_by_ip(self): for vm in self.sdk.vms(): ip = vm.ip() if ip: assert self.sdk.find_by_ip(ip).ip() == ip return print("Warning test ESX server had no VMs with IPs") def test_find_by_uuid(self): uuid = self.vm.uuid() assert self.sdk.find_by_uuid(uuid).uuid() == uuid def test_get_object(self): name = self.vm.name() vm = self.sdk.get_object(pyVmomi.vim.VirtualMachine, name) assert vm.name == name def test_get_objects_Datastore(self): datastores = self.sdk.get_objects_Datastore() assert len(datastores) > 0 def test_get_object_virtual_machine(self): name = self.vm.name() vm = VM(self.sdk.get_object_virtual_machine(name)) assert vm.name() == name def test_get_objects(self): objects = self.sdk.get_objects() assert len(objects) > 0 def test_folders(self): folders = self.sdk.folders() assert str(folders) == "['vim.Folder:ha-folder-vm']" def test_vms(self): vms = self.sdk.vms() assert len(vms) > 0 def test_names(self): names = self.sdk.vms_names() assert len(names) > 0 def test_service_instance(self): service_instance = self.sdk.service_instance() assert service_instance.content.about.apiVersion == '6.7.3' assert service_instance.content.about.licenseProductName == 'VMware ESX Server' assert service_instance.content.about.osType == 'vmnix-x86' def test_dump_json(self): obj_type = "VirtualMachine" moid = self.vm.moid() json_dump = self.sdk.json_dump(obj_type, moid) json_data = json.loads(json_dump) assert json_data['_vimid'] == moid assert json_data['_vimtype'] == "vim.VirtualMachine" def test_tasks( self ): # todo: find better way to do this since when running multiple tests the self.sdk.tasks_recent() can take multiple seconds to execute self.sdk.find_by_ip('aaaaaa') recent_tasks = self.sdk.tasks_recent() most_recent_one = recent_tasks.pop() assert most_recent_one['DescriptionId'] == 'SearchIndex.findByIp' assert most_recent_one[ 'Key'] == f"haTask--vim.SearchIndex.findByIp-{most_recent_one['EventChainId']}" assert most_recent_one['State'] == 'success' assert most_recent_one['Entity'] == 'None'
class test_Sdk(TestCase_VM): vm_name = f"tests__unit__" + __name__ def setUp(self): self.sdk = Sdk() def test_about(self): content = self.sdk.about() assert content.vendor == "VMware, Inc." assert content.version == "6.7.0" assert content.licenseProductName == "VMware ESX Server" assert content.licenseProductName == "VMware ESX Server" assert content.licenseProductVersion == "6.0" def test_file_info(self): datastore_path = 'an data store' vmx_file = self.sdk.file_info(datastore_path) assert vmx_file.vmPathName == datastore_path # def test_find_iso(self): # vm = self.sdk.find_by_host_name('haproxy-icap') # #pprint(vm.info()) # #print(self.sdk.json_dump("VirtualMachine","42")) # #vim.vm.device.VirtualCdrom # print(vm.config().hardware) def test_find_by_host_name(self): for vm in self.sdk.vms(): host_name = vm.host_name() if host_name: assert self.sdk.find_by_host_name( host_name).host_name() == host_name return print( "Warning test ESX server had no VMs with host_names (dnsNames) setup" ) def test_find_by_name(self): assert self.sdk.find_by_name(self.vm_name).name() == self.vm_name assert self.sdk.find_by_name("AAA_BBB_CCC") is None def test_find_by_ip(self): for vm in self.sdk.vms(): ip = vm.ip() if ip: assert self.sdk.find_by_ip(ip).ip() == ip return print("Warning test ESX server had no VMs with IPs") def test_find_by_uuid(self): uuid = self.vm.uuid() assert self.sdk.find_by_uuid(uuid).uuid() == uuid def test_get_object(self): with View_Soap_Calls(): name = self.vm.name() vm = self.sdk.get_object(pyVmomi.vim.VirtualMachine, name) pprint(vm) #assert vm.name == name def test_get_objects_Datastore(self): datastores = self.sdk.get_objects_Datastore() assert len(datastores) > 0 def test_get_object_virtual_machine(self): name = self.vm.name() vm = VM(self.sdk.get_object_virtual_machine(name)) assert vm.name() == name def test_get_objects(self): objects = self.sdk.get_objects() assert len(objects) > 0 def test_get_objects_properties(self): target_objects = [self.vm.vm ] # use a temp vm to make sure we always have one object_type = type(self.vm.vm) vm_id = self.vm.id() properties_names = self.sdk.object_properties_names(object_type) results = self.sdk.get_objects_properties(object_type, target_objects, properties_names) assert vm_id == f'vim.VirtualMachine:{self.vm.moid()}' assert vm_id in results assert len(results) == 1 object_properties = results[vm_id] properties_names.remove( 'alarmActionsEnabled' ) # these properties are not returned from the server properties_names.remove('parentVApp') properties_names.remove('snapshot') assert sorted(list(set(object_properties))) == sorted(properties_names) assert object_properties['name'] == self.vm.name() # to get properties from all current VMs use: # target_objects = self.sdk.get_objects_Virtual_Machines() def test_folders(self): folders = self.sdk.folders() assert str(folders) == "['vim.Folder:ha-folder-vm']" def test_object_filter_spec(self): # see test_get_objects_properties pass def test_object_methods_names(self): object_type = pyVmomi.vim.VirtualMachine method_names = self.sdk.object_methods_names(object_type) assert method_names == [ 'SetCustomValue', 'Destroy', 'Reload', 'Rename', # these ones where not in list(object._methodInfo.keys()) 'AcquireMksTicket', 'AcquireTicket', 'Answer', 'ApplyEvcMode', 'AttachDisk', 'CheckCustomizationSpec', 'Clone', 'ConsolidateDisks', 'CreateScreenshot', 'CreateSecondaryEx', 'CreateSecondary', 'CreateSnapshotEx', 'CreateSnapshot', 'CryptoUnlock', 'Customize', 'DefragmentAllDisks', 'DetachDisk', 'DisableSecondary', 'DropConnections', 'EnableSecondary', 'EstimateStorageRequirementForConsolidate', 'ExportVm', 'ExtractOvfEnvironment', 'InstantClone', 'MakePrimary', 'MarkAsTemplate', 'MarkAsVirtualMachine', 'Migrate', 'MountToolsInstaller', 'PowerOff', 'PowerOn', 'PromoteDisks', 'PutUsbScanCodes', 'QueryChangedDiskAreas', 'QueryConnections', 'QueryFaultToleranceCompatibility', 'QueryFaultToleranceCompatibilityEx', 'QueryUnownedFiles', 'RebootGuest', 'Reconfigure', 'RefreshStorageInfo', 'Relocate', 'RemoveAllSnapshots', 'ResetGuestInformation', 'Reset', 'RevertToCurrentSnapshot', 'SendNMI', 'SetDisplayTopology', 'SetScreenResolution', 'ShutdownGuest', 'StandbyGuest', 'StartRecording', 'StartReplaying', 'StopRecording', 'StopReplaying', 'Suspend', 'TerminateFaultTolerantVM', 'Terminate', 'TurnOffFaultTolerance', 'UnmountToolsInstaller', 'Unregister', 'UpgradeTools', 'UpgradeVirtualHardware', 'ReloadFromPath' ] datastore_methods = self.sdk.object_methods_names( pyVmomi.vim.Datastore) assert datastore_methods == [ 'SetCustomValue', 'Destroy', 'Reload', 'Rename', 'EnterMaintenanceMode', 'ExitMaintenanceMode', 'DestroyDatastore', 'Refresh', 'RefreshStorageInfo', 'RenameDatastore', 'UpdateVVolVirtualMachineFiles', 'UpdateVirtualMachineFiles' ] def test_object_properties_names(self): object_type = pyVmomi.vim.VirtualMachine properties_names = self.sdk.object_properties_names(object_type) assert properties_names == [ 'value', 'availableField', 'parent', 'customValue', 'overallStatus', 'configStatus', 'configIssue', 'effectiveRole', 'permission', 'name', 'disabledMethod', 'recentTask', 'declaredAlarmState', 'triggeredAlarmState', 'alarmActionsEnabled', 'tag', 'capability', 'config', 'layout', 'layoutEx', 'storage', 'environmentBrowser', 'resourcePool', 'parentVApp', 'resourceConfig', 'runtime', 'guest', 'summary', 'datastore', 'network', 'snapshot', 'rootSnapshot', 'guestHeartbeatStatus' ] datastore_properties = self.sdk.object_properties_names( pyVmomi.vim.Datastore) assert datastore_properties == [ 'value', 'availableField', 'parent', 'customValue', 'overallStatus', 'configStatus', 'configIssue', 'effectiveRole', 'permission', 'name', 'disabledMethod', 'recentTask', 'declaredAlarmState', 'triggeredAlarmState', 'alarmActionsEnabled', 'tag', 'info', 'summary', 'host', 'vm', 'browser', 'capability', 'iormConfiguration' ] def test_vms(self): vms = self.sdk.vms() assert len(vms) > 0 def test_names(self): names = self.sdk.vms_names() assert len(names) > 0 def test_service_instance(self): service_instance = self.sdk.service_instance() assert service_instance.content.about.apiVersion == '6.7.3' assert service_instance.content.about.licenseProductName == 'VMware ESX Server' assert service_instance.content.about.osType == 'vmnix-x86' # def test_dump_json(self): # # obj_type = "VirtualMachine" # moid = self.vm.moid() # # json_dump = self.sdk.json_dump(obj_type, moid) # json_data = json.loads(json_dump) # assert json_data['_vimid' ] == moid # assert json_data['_vimtype'] == "vim.VirtualMachine" # todo: fix experiment (see tasks_recent_experiment) def test_tasks( self ): # todo: find better way to do this since when running multiple tests the self.sdk.tasks_recent() can take multiple seconds to execute #with View_Soap_Calls(): # with Catch(): # #pprint(self.sdk.get_objects()) # self.sdk.find_by_ip('aaaaaa') # recent_tasks = self.sdk.tasks_recent(self.vm.vm) # pprint(recent_tasks) # return self.sdk.find_by_ip('aaaaaa') recent_tasks = self.sdk.tasks_recent() most_recent_one = recent_tasks.pop() assert most_recent_one['DescriptionId'] == 'SearchIndex.findByIp' assert most_recent_one[ 'Key'] == f"haTask--vim.SearchIndex.findByIp-{most_recent_one['EventChainId']}" assert most_recent_one['State'] == 'success' assert most_recent_one['Entity'] == 'None'