class Tiny_Core_Linux: def __init__(self): self.url_core_iso = 'https://distro.ibiblio.org/tinycorelinux/11.x/x86/release/Core-current.iso' self.path_core_iso = '/tmp/core-currenet.iso' self.vm_name = 'tiny-core-linux' self.sdk = Sdk() def create_vm(self): self.sdk.content() print('-----') vm = self.sdk.vm(self.vm_name) print('-----') #if vm is None: # print('need to create vm') #print(f"VM: {vm}") pass def download_iso(self): if file_not_exists(self.path_core_iso): Http.GET_bytes_to_file(self.url_core_iso, self.path_core_iso) return self.path_core_iso
class VM_Process: def __init__(self, vm): self.sdk = Sdk() self.vm = vm self.vm_account = Config().vm_account() self.server_details = Config().vsphere_server_details() self.vm_user_name = self.vm_account['username'] self.vm_password = self.vm_account['password'] self.ip_server = self.server_details['host'] def exec(self, program_path, arguments=""): return self.start_process_return_stdout(program_path, arguments) def set_vm_account(self, username, password): self.vm_user_name = username self.vm_password = password def set_vm_account_from_env(self, env_prefix): self.vm_account['username'] = environ.get(f'{env_prefix}_USERNAME') self.vm_account['password'] = environ.get(f'{env_prefix}_PASSWORD') return self def start_process_return_stdout(self, program_path, arguments=""): content = self.sdk.content() # assert self.vm.guest().toolsStatus == 'toolsOk' file_stdout = f"/tmp/_vm_exec_{random_string()}" arguments += f" > {file_stdout}" # capture stdout in a file creds = pyVmomi.vim.vm.guest.NamePasswordAuthentication( username=self.vm_user_name, password=self.vm_password) pm = content.guestOperationsManager.processManager ps = pyVmomi.vim.vm.guest.ProcessManager.ProgramSpec( programPath=program_path, arguments=arguments) res = pm.StartProgramInGuest(self.vm.vm, creds, ps) file_transfer = content.guestOperationsManager.fileManager.InitiateFileTransferFromGuest( self.vm.vm, creds, file_stdout) file_url = file_transfer.url.replace("*:443", self.ip_server) resp = requests.get(file_url, verify=False) return resp.text # helper commands def curl(self, target='-h'): return self.exec('/usr/bin/curl', target) def ls(self, path=""): return self.exec('/bin/ls', path)
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')