def receive_image(self, image_id, datastore_id, imported_vm_name, metadata, manifest): """ Creates an image using the data from the imported vm. This is run at the destination host end of the host-to-host image transfer. """ vm = self._vim_client.get_vm_obj_in_cache(imported_vm_name) vmx_os_path = datastore_to_os_path(vm.config.files.vmPathName) vm_dir = os.path.dirname(vmx_os_path) vm.Unregister() if self.check_image_dir(image_id, datastore_id): self._logger.info("Image %s on datastore %s already exists" % (image_id, datastore_id)) raise DiskAlreadyExistException() self._move_image(image_id, datastore_id, vm_dir) # Save raw manifest manifest_path = os_image_manifest_path(datastore_id, image_id) with open(manifest_path, "w") as f: f.write(manifest) # Save raw metadata metadata_path = os_metadata_path(datastore_id, image_id, IMAGE_FOLDER_NAME) with open(metadata_path, "w") as f: f.write(metadata) self._create_image_timestamp_file_from_ids(datastore_id, image_id)
def _create_tmp_image(self, source_datastore, source_id, dest_datastore, dest_id): """ Copy an image into a temp location. 1. Lock a tmp image destination file with an exclusive lock. This is to prevent the GC thread from garbage collecting directories that are actively being used. The temp directory name contains a random UUID to prevent collisions with concurrent copies 2. Create the temp directory. 3. Copy the metadata file over. 4. Copy the vmdk over. @return the tmp image directory on success. """ source = vmdk_path(source_datastore, source_id, IMAGE_FOLDER_NAME) temp_dest = tmp_image_path(dest_datastore, dest_id) ds_type = self._get_datastore_type(dest_datastore) tmp_image_dir_path = os.path.dirname(datastore_to_os_path(temp_dest)) # Try grabbing the lock on the temp directory if it fails # (very unlikely) someone else is copying an image just retry # later. with FileBackedLock(tmp_image_dir_path, ds_type): source_meta = os_metadata_path(source_datastore, source_id, IMAGE_FOLDER_NAME) # Create the temp directory mkdir_p(tmp_image_dir_path) # Copy the metadata file if it exists. if os.path.exists(source_meta): try: dest_meta = os.path.join(tmp_image_dir_path, metadata_filename(dest_id)) shutil.copy(source_meta, dest_meta) except: self._logger.exception("Failed to copy metadata file %s", source_meta) raise # Copy the manifest file if it exists source_manifest = os_image_manifest_path(source_datastore, source_id) if os.path.exists(source_manifest): try: dest_manifest = os.path.join(tmp_image_dir_path, manifest_filename(dest_id)) shutil.copy(source_manifest, dest_manifest) except: # Swallow it. Not critical. pass # Create the timestamp file self._create_image_timestamp_file(tmp_image_dir_path) _vd_spec = self._prepare_virtual_disk_spec( vim.VirtualDiskManager.VirtualDiskType.thin, vim.VirtualDiskManager.VirtualDiskAdapterType.lsiLogic ) self._manage_disk( vim.VirtualDiskManager.CopyVirtualDisk_Task, sourceName=source, destName=temp_dest, destSpec=_vd_spec ) return tmp_image_dir_path
def _read_metadata(self, image_datastore, image_id): try: # Transfer raw metadata metadata_path = os_metadata_path(image_datastore, image_id, IMAGE_FOLDER_NAME_PREFIX) metadata = None if os.path.exists(metadata_path): with open(metadata_path, 'r') as f: metadata = f.read() return metadata except: self._logger.exception("Failed to read metadata") raise
def _create_tmp_image(self, source_datastore, source_id, dest_datastore, dest_id): """ Copy an image into a temp location. 1. Lock a tmp image destination file with an exclusive lock. This is to prevent the GC thread from garbage collecting directories that are actively being used. The temp directory name contains a random UUID to prevent collisions with concurrent copies 2. Create the temp directory. 3. Copy the metadata file over. 4. Copy the vmdk over. @return the tmp image directory on success. """ source = vmdk_path(source_datastore, source_id, IMAGE_FOLDER_NAME) temp_dest = tmp_image_path(dest_datastore, dest_id) ds_type = self._get_datastore_type(dest_datastore) tmp_image_dir_path = os.path.dirname(datastore_to_os_path(temp_dest)) # Try grabbing the lock on the temp directory if it fails # (very unlikely) someone else is copying an image just retry # later. with FileBackedLock(tmp_image_dir_path, ds_type): source_meta = os_metadata_path(source_datastore, source_id, IMAGE_FOLDER_NAME) # Create the temp directory mkdir_p(tmp_image_dir_path) # Copy the metadata file if it exists. if os.path.exists(source_meta): try: shutil.copy(source_meta, tmp_image_dir_path) except: self._logger.exception("Failed to copy metadata file %s", source_meta) raise # Create the timestamp file self._create_image_timestamp_file(tmp_image_dir_path) _vd_spec = self._prepare_virtual_disk_spec( vim.VirtualDiskManager.VirtualDiskType.thin, vim.VirtualDiskManager.VirtualDiskAdapterType.lsiLogic) self._manage_disk(vim.VirtualDiskManager.CopyVirtualDisk_Task, sourceName=source, destName=temp_dest, destSpec=_vd_spec) return tmp_image_dir_path
def _copy_to_tmp_image(self, source_datastore, source_id, dest_datastore, dest_id): """ Copy an image into a temp location. 1. Lock a tmp image destination file with an exclusive lock. This is to prevent the GC thread from garbage collecting directories that are actively being used. The temp directory name contains a random UUID to prevent collisions with concurrent copies 2. Create the temp directory. 3. Copy the metadata file over. 4. Copy the vmdk over. @return the tmp image directory on success. """ ds_type = self._get_datastore_type(dest_datastore) if ds_type == DatastoreType.VSAN: tmp_image_dir = os_datastore_path(dest_datastore, compond_path_join(IMAGE_FOLDER_NAME_PREFIX, dest_id), compond_path_join(TMP_IMAGE_FOLDER_NAME_PREFIX, str(uuid.uuid4()))) else: tmp_image_dir = os_datastore_path(dest_datastore, compond_path_join(TMP_IMAGE_FOLDER_NAME_PREFIX, str(uuid.uuid4()))) # Create the temp directory self._vim_client.make_directory(tmp_image_dir) # Copy the metadata file if it exists. source_meta = os_metadata_path(source_datastore, source_id, IMAGE_FOLDER_NAME_PREFIX) if os.path.exists(source_meta): try: dest_meta = os.path.join(tmp_image_dir, metadata_filename(dest_id)) shutil.copy(source_meta, dest_meta) except: self._logger.exception("Failed to copy metadata file %s", source_meta) raise # Create the timestamp file self._create_image_timestamp_file(tmp_image_dir) _vd_spec = self._prepare_virtual_disk_spec( vim.VirtualDiskManager.VirtualDiskType.thin, vim.VirtualDiskManager.VirtualDiskAdapterType.lsiLogic) self._manage_disk(vim.VirtualDiskManager.CopyVirtualDisk_Task, sourceName=vmdk_path(source_datastore, source_id, IMAGE_FOLDER_NAME_PREFIX), destName=os_to_datastore_path(os.path.join(tmp_image_dir, "%s.vmdk" % dest_id)), destSpec=_vd_spec) return tmp_image_dir
def _read_metadata(self, image_datastore, image_id): try: # Transfer raw manifest manifest_path = os_image_manifest_path(image_datastore, image_id) with open(manifest_path) as f: manifest = f.read() # Transfer raw metadata metadata_path = os_metadata_path(image_datastore, image_id, IMAGE_FOLDER_NAME) with open(metadata_path, 'r') as f: metadata = f.read() return manifest, metadata except: self._logger.exception("Failed to read metadata") raise
def receive_image(self, image_id, datastore_id, imported_vm_name, metadata): """ Creates an image using the data from the imported vm. This is run at the destination host end of the host-to-host image transfer. """ self._vim_client.wait_for_vm_create(imported_vm_name) vm = self._vim_client.get_vm_obj_in_cache(imported_vm_name) self._logger.warning("receive_image found vm %s, %s" % (imported_vm_name, vm)) vm_dir = os.path.dirname(datastore_to_os_path(vm.config.files.vmPathName)) vm.Unregister() ds_type = self._get_datastore_type(datastore_id) if ds_type == DatastoreType.VSAN: # on VSAN datastore, vm_dir is [vsanDatastore] image_[image_id], we only need to # rename the vmdk file to [image_id].vmdk try: with FileBackedLock(vm_dir, ds_type, retry=300, wait_secs=0.01): # wait lock for 3 seconds if self._check_image_repair(image_id, datastore_id): raise DiskAlreadyExistException("Image already exists") self._vim_client.move_file(os.path.join(vm_dir, vmdk_add_suffix(imported_vm_name)), os.path.join(vm_dir, vmdk_add_suffix(image_id))) except: self._logger.exception("Move image %s to %s failed" % (image_id, vm_dir)) self._vim_client.delete_file(vm_dir) raise else: self._move_image(image_id, datastore_id, vm_dir) # Save raw metadata if metadata: metadata_path = os_metadata_path(datastore_id, image_id, IMAGE_FOLDER_NAME_PREFIX) with open(metadata_path, 'w') as f: f.write(metadata) self._create_image_timestamp_file_from_ids(datastore_id, image_id)
def get_image_metadata(self, image_id, datastore): metadata_path = os_metadata_path(datastore, image_id, IMAGE_FOLDER_NAME) self._logger.info("Loading metadata %s" % metadata_path) return self._load_json(metadata_path)