Esempio n. 1
0
 def _manage_disk(self, op, **kwargs):
     try:
         self._logger.debug("Invoking %s(%s)" % (op.info.name, kwargs))
         task = op(self._manager, **kwargs)
         self._vim_client.wait_for_task(task)
     except vim.Fault.FileAlreadyExists, e:
         raise DiskAlreadyExistException(e.msg)
Esempio n. 2
0
    def _move_image(self, image_id, datastore, tmp_dir):
        """
        Atomic move of a tmp folder into the image datastore. Handles
        concurrent moves by locking a well know derivative of the image_id
        while doing the atomic move.
        The exclusive file lock ensures that only one move is successful.
        Has the following side effects:
            a - If the destination image already exists, it is assumed that
            someone else successfully copied the image over and the temp
            directory is deleted.
            b - If we fail to acquire the file lock after retrying 3 times,
            or the atomic move fails, the tmp image directory will be left
            behind and needs to be garbage collected later.

        image_id: String.The image id of the image being moved.
        datastore: String. The datastore id of the datastore.
        tmp_dir: String. The absolute path of the temp image directory.

        raises: OsError if the move fails
                AcquireLockFailure, InvalidFile if we fail to lock the
                destination image.
        """
        ds_type = self._get_datastore_type(datastore)
        image_path = os.path.dirname(
            os_vmdk_path(datastore, image_id, IMAGE_FOLDER_NAME))
        parent_path = os.path.dirname(image_path)
        # Create the parent image directory if it doesn't exist.
        try:
            mkdir_p(parent_path)
        except OSError as e:
            if e.errno == errno.EEXIST and os.path.isdir(parent_path):
                # Parent directory exists nothing to do.
                pass
            else:
                raise
        try:
            with FileBackedLock(image_path, ds_type, retry=300,
                                wait_secs=0.01):  # wait lock for 3 seconds
                if self._check_image_repair(image_id, datastore):
                    raise DiskAlreadyExistException("Image already exists")

                shutil.move(tmp_dir, image_path)
        except (AcquireLockFailure, InvalidFile):
            self._logger.info("Unable to lock %s for atomic move" % image_id)
            raise
        except DiskAlreadyExistException:
            self._logger.info("Image %s already copied" % image_id)
            rm_rf(tmp_dir)
            raise
Esempio n. 3
0
    def _move_image(self, image_id, datastore, tmp_dir):
        """
        Atomic move of a tmp folder into the image datastore. Handles
        concurrent moves by locking a well know derivative of the image_id
        while doing the atomic move.
        The exclusive file lock ensures that only one move is successful.
        Has the following side effects:
            a - If the destination image already exists, it is assumed that
            someone else successfully copied the image over and the temp
            directory is deleted.
            b - If we fail to acquire the file lock after retrying 3 times,
            or the atomic move fails, the tmp image directory will be left
            behind and needs to be garbage collected later.

        image_id: String.The image id of the image being moved.
        datastore: String. The datastore id of the datastore.
        tmp_dir: String. The absolute path of the temp image directory.

        raises: OsError if the move fails
                AcquireLockFailure, InvalidFile if we fail to lock the
                destination image.
        """
        ds_type = self._get_datastore_type(datastore)
        image_path = os_datastore_path(datastore, compond_path_join(IMAGE_FOLDER_NAME_PREFIX, image_id))
        self._logger.info("_move_image: %s => %s, ds_type: %s" % (tmp_dir, image_path, ds_type))

        if not os.path.exists(tmp_dir):
            raise ImageNotFoundException("Temp image %s not found" % tmp_dir)

        try:
            with FileBackedLock(image_path, ds_type, retry=300, wait_secs=0.01):  # wait lock for 3 seconds
                if self._check_image_repair(image_id, datastore):
                    raise DiskAlreadyExistException("Image already exists")

                if ds_type == DatastoreType.VSAN:
                    # on VSAN, move all files under [datastore]/image_[image_id]/tmp_image_[uuid]/* to
                    # [datastore]/image_[image_id]/*.
                    # Also we do not delete tmp_image folder in success case, because VSAN accesses it
                    # when creating linked VM, even the folder is now empty.
                    for entry in os.listdir(tmp_dir):
                        shutil.move(os.path.join(tmp_dir, entry), os.path.join(image_path, entry))
                else:
                    # on VMFS/NFS/etc, rename [datastore]/tmp_image_[uuid] to [datastore]/tmp_image_[image_id]
                    self._vim_client.move_file(tmp_dir, image_path)
        except:
            self._logger.exception("Move image %s to %s failed" % (image_id, image_path))
            self._vim_client.delete_file(tmp_dir)
            raise
Esempio n. 4
0
    def receive_image(self, image_id, datastore_id, imported_vm_name):
        """ 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)
        self._create_image_timestamp_file_from_ids(datastore_id, image_id)
Esempio n. 5
0
    def create_image(self, datastore_id, tmp_dir, image_id):
        """ Installs an image using image data staged at a temp directory.
        """
        src_path = os_datastore_path(datastore_id, tmp_dir)
        if not os.path.exists(src_path):
            self._logger.info("Tmp dir %s on datastore %s not found" %
                              (tmp_dir, datastore_id))
            raise ImageNotFoundException("Image %s not found" % src_path)

        # Check if the dest image id already exists
        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, src_path)
        self._create_image_timestamp_file_from_ids(datastore_id, image_id)
Esempio n. 6
0
    def _register_imported_image_at_host(self, agent_client, image_id,
                                         destination_datastore,
                                         imported_vm_name, metadata):
        """ Installs an image at another host.

        Image data was transferred via ImportVApp to said host.
        """

        request = ReceiveImageRequest(image_id=image_id,
                                      datastore_id=destination_datastore,
                                      transferred_image_id=imported_vm_name,
                                      metadata=metadata)

        response = agent_client.receive_image(request)
        if response.result == ReceiveImageResultCode.DESTINATION_ALREADY_EXIST:
            raise DiskAlreadyExistException(response.error)
        if response.result != ReceiveImageResultCode.OK:
            raise ReceiveImageException(response.result, response.error)
Esempio n. 7
0
    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)
Esempio n. 8
0
    def copy_image(self, source_datastore, source_id, dest_datastore, dest_id):
        """Copy an image between datastores.

        This method is used to create a "full clone" of a vmdk.
        It does so by copying a disk to a unique directory in a well known
        temporary directory then moving the disk to the destination image
        location. Data in the temporary directory not properly cleaned up
        will be periodically garbage collected by the reaper thread.

        This minimizes the window during which the vmdk path exists with
        incomplete content. It also works around a hostd issue where
        cp -f does not work.

        The current behavior for when the destination disk exists is
        to overwrite said disk.

        source_datastore: id of the source datastore
        source_id: id of the image to copy from
        dest_datastore: id of the destination datastore
        dest_id: id of the new image in the destination datastore

        throws: AcquireLockFailure if timed out waiting to acquire lock on tmp
                image directory
        throws: InvalidFile if unable to lock tmp image directory or some other
                reasons
        """
        if self.check_and_validate_image(dest_id, dest_datastore):
            # The image is copied, presumably via some other concurrent
            # copy, so we move on.
            self._logger.info("Image %s already copied" % dest_id)
            raise DiskAlreadyExistException("Image already exists")

        # Copy image to the tmp directory.
        tmp_dir = self._create_tmp_image(source_datastore, source_id,
                                         dest_datastore, dest_id)

        self._move_image(dest_id, dest_datastore, tmp_dir)
Esempio n. 9
0
 def _assert_not_exists(self, name, datastore):
     if os.path.exists(self._disk_path(datastore, name)):
         self._logger.warning("disk in datastore (%s:%s) already exists" %
                              (name, datastore))
         raise DiskAlreadyExistException("EEXISTS")