def test_get_linked_clone_image_path(self):
        image_path = self.vm_manager.get_linked_clone_image_path

        # VM not found
        vm = MagicMock(return_value=None)
        self.vm_manager.vim_client.get_vm_in_cache = vm
        assert_that(image_path("vm1"), is_(None))

        # disks is None
        vm = MagicMock(return_value=VmCache(disks=None))
        self.vm_manager.vim_client.get_vm_in_cache = vm
        assert_that(image_path("vm1"), is_(None))

        # disks is an empty list
        vm = MagicMock(return_value=VmCache(disks=[]))
        self.vm_manager.vim_client.get_vm_in_cache = vm
        assert_that(image_path("vm1"), is_(None))

        # no image disk
        vm = MagicMock(return_value=VmCache(disks=["a", "b", "c"]))
        self.vm_manager.vim_client.get_vm_in_cache = vm
        assert_that(image_path("vm1"), is_(None))

        # image found
        image = "[ds1] image_ttylinux/ttylinux.vmdk"
        vm = MagicMock(return_value=VmCache(disks=["a", "b", image]))
        self.vm_manager.vim_client.get_vm_in_cache = vm
        assert_that(image_path("vm1"), is_(datastore_to_os_path(image)))
Exemplo n.º 2
0
    def create_vm(self, vm_id, create_spec):
        """Create a new Virtual Maching given a VM create spec.

        :param vm_id: The Vm id
        :type vm_id: string
        :param create_spec: The VM spec builder
        :type ConfigSpec
        :raise: VmAlreadyExistException
        """
        folder = self.vim_client.vm_folder
        resource_pool = self.vim_client.root_resource_pool

        # sanity check since VIM does not prevent this
        try:
            if self.vim_client.get_vm_in_cache(vm_id):
                raise VmAlreadyExistException("VM already exists")
        except VmNotFoundException:
            pass

        # The scenario of the vm creation at ESX where intermediate directory
        # has to be created has not been well exercised and is known to be
        # racy and not informative on failures. So be defensive and proactively
        # create the intermediate directory ("/vmfs/volumes/<dsid>/vms/xy").
        vm_parent_dir = datastore_to_os_path(create_spec.files.vmPathName)
        if os.path.exists(vm_parent_dir):
            self._logger.debug("Parent directory %s exists" % vm_parent_dir)
        else:
            mkdir_p(vm_parent_dir)

        task = folder.CreateVm(create_spec, resource_pool, None)
        self.vim_client.wait_for_task(task)
        self.vim_client.wait_for_vm_create(vm_id)
Exemplo n.º 3
0
    def create_vm(self, vm_id, create_spec):
        """Create a new Virtual Maching given a VM create spec.

        :param vm_id: The Vm id
        :type vm_id: string
        :param create_spec: The VM spec builder
        :type ConfigSpec
        :raise: VmAlreadyExistException
        """
        folder = self.vim_client.vm_folder
        resource_pool = self.vim_client.root_resource_pool

        # sanity check since VIM does not prevent this
        try:
            if self.vim_client.get_vm_in_cache(vm_id):
                raise VmAlreadyExistException("VM already exists")
        except VmNotFoundException:
            pass

        # The scenario of the vm creation at ESX where intermediate directory
        # has to be created has not been well exercised and is known to be
        # racy and not informative on failures. So be defensive and proactively
        # create the intermediate directory ("/vmfs/volumes/<dsid>/vms/xy").
        vm_parent_dir = datastore_to_os_path(create_spec.files.vmPathName)
        if os.path.exists(vm_parent_dir):
            self._logger.debug("Parent directory %s exists" % vm_parent_dir)
        else:
            mkdir_p(vm_parent_dir)

        task = folder.CreateVm(create_spec, resource_pool, None)
        self.vim_client.wait_for_task(task)
        self.vim_client.wait_for_vm_create(vm_id)
Exemplo n.º 4
0
    def test_get_linked_clone_image_path(self):
        image_path = self.vm_manager.get_linked_clone_image_path

        # VM not found
        vm = MagicMock(return_value=None)
        self.vm_manager.vim_client.get_vm_in_cache = vm
        assert_that(image_path("vm1"), is_(None))

        # disks is None
        vm = MagicMock(return_value=VmCache(disks=None))
        self.vm_manager.vim_client.get_vm_in_cache = vm
        assert_that(image_path("vm1"), is_(None))

        # disks is an empty list
        vm = MagicMock(return_value=VmCache(disks=[]))
        self.vm_manager.vim_client.get_vm_in_cache = vm
        assert_that(image_path("vm1"), is_(None))

        # no image disk
        vm = MagicMock(return_value=VmCache(disks=["a", "b", "c"]))
        self.vm_manager.vim_client.get_vm_in_cache = vm
        assert_that(image_path("vm1"), is_(None))

        # image found
        image = "[ds1] image_ttylinux/ttylinux.vmdk"
        vm = MagicMock(return_value=VmCache(disks=["a", "b", image]))
        self.vm_manager.vim_client.get_vm_in_cache = vm
        assert_that(image_path("vm1"), is_(datastore_to_os_path(image)))
Exemplo n.º 5
0
    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)
Exemplo n.º 6
0
    def create_image_with_vm_disk(self, datastore_id, tmp_dir, image_id,
                                  vm_disk_os_path):
        """ Fills a temp image directory with a disk from a VM,
            then installs directory in the shared image folder.
        """
        # Create parent directory as required by CopyVirtualDisk_Task
        dst_vmdk_path = os.path.join(datastore_to_os_path(tmp_dir), "%s.vmdk" % image_id)
        if os.path.exists(dst_vmdk_path):
            self._logger.warning(
                "Unexpected disk %s present, overwriting" % dst_vmdk_path)
        dst_vmdk_ds_path = os_to_datastore_path(dst_vmdk_path)

        _vd_spec = self._prepare_virtual_disk_spec(
            vim.VirtualDiskManager.VirtualDiskType.thin,
            vim.VirtualDiskManager.VirtualDiskAdapterType.lsiLogic)

        self._manage_disk(vim.VirtualDiskManager.CopyVirtualDisk_Task,
                          sourceName=os_to_datastore_path(vm_disk_os_path),
                          destName=dst_vmdk_ds_path,
                          destSpec=_vd_spec)

        try:
            self.finalize_image(datastore_id, tmp_dir, image_id)
        except:
            self._logger.warning("Delete copied disk %s" % dst_vmdk_ds_path)
            self._manage_disk(vim.VirtualDiskManager.DeleteVirtualDisk_Task,
                              name=dst_vmdk_ds_path)
            raise
Exemplo n.º 7
0
    def create_image_with_vm_disk(self, datastore_id, tmp_dir, image_id,
                                  vm_disk_os_path):
        """ Fills a temp image directory with a disk from a VM,
            then installs directory in the shared image folder.
        """
        # Create parent directory as required by CopyVirtualDisk_Task
        dst_vmdk_path = os.path.join(datastore_to_os_path(tmp_dir), "%s.vmdk" % image_id)
        if os.path.exists(dst_vmdk_path):
            self._logger.warning(
                "Unexpected disk %s present, overwriting" % dst_vmdk_path)
        dst_vmdk_ds_path = os_to_datastore_path(dst_vmdk_path)

        _vd_spec = self._prepare_virtual_disk_spec(
            vim.VirtualDiskManager.VirtualDiskType.thin,
            vim.VirtualDiskManager.VirtualDiskAdapterType.lsiLogic)

        self._manage_disk(vim.VirtualDiskManager.CopyVirtualDisk_Task,
                          sourceName=os_to_datastore_path(vm_disk_os_path),
                          destName=dst_vmdk_ds_path,
                          destSpec=_vd_spec)

        try:
            self.finalize_image(datastore_id, tmp_dir, image_id)
        except:
            self._logger.warning("Delete copied disk %s" % dst_vmdk_ds_path)
            self._manage_disk(vim.VirtualDiskManager.DeleteVirtualDisk_Task,
                              name=dst_vmdk_ds_path)
            raise
Exemplo n.º 8
0
    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
Exemplo n.º 9
0
 def _ensure_directory_cleanup(self, vm_ds_path):
     # Upon successful destroy of VM, log any stray files still left in the
     # VM directory and delete the directory.
     vm_dir = os.path.dirname(datastore_to_os_path(vm_ds_path))
     if os.path.isdir(vm_dir):
         files = os.listdir(vm_dir)
         for f in files:
             if f.endswith(".vmdk"):
                 self._logger.info("Stray disk "
                                   "(possible data leak): %s" % f)
             else:
                 self._logger.info("Stray file: %s" % f)
         self._logger.warning("Force delete vm directory %s" % vm_dir)
         rm_rf(vm_dir)
Exemplo n.º 10
0
 def _ensure_directory_cleanup(self, vm_ds_path):
     # Upon successful destroy of VM, log any stray files still left in the
     # VM directory and delete the directory.
     vm_dir = os.path.dirname(datastore_to_os_path(vm_ds_path))
     if os.path.isdir(vm_dir):
         files = os.listdir(vm_dir)
         for f in files:
             if f.endswith(".vmdk"):
                 self._logger.info("Stray disk "
                                   "(possible data leak): %s" % f)
             else:
                 self._logger.info("Stray file: %s" % f)
         self._logger.warning("Force delete vm directory %s" % vm_dir)
         rm_rf(vm_dir)
Exemplo n.º 11
0
    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
Exemplo n.º 12
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)
Exemplo n.º 13
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)
Exemplo n.º 14
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)
Exemplo n.º 15
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)
Exemplo n.º 16
0
 def test_path_conversion(self, ds_path, expected_os_path):
     path = datastore_to_os_path(ds_path)
     assert_that(path, equal_to(expected_os_path))
Exemplo n.º 17
0
 def _vmdk_pairs(ds_path):
     vmdk_path = datastore_to_os_path(ds_path)
     pos = vmdk_path.rfind(".vmdk")
     vmdk_flat_path = vmdk_path[:pos] + "-flat" + vmdk_path[pos:]
     return (vmdk_path, vmdk_flat_path)
 def _vmdk_pairs(ds_path):
     vmdk_path = datastore_to_os_path(ds_path)
     pos = vmdk_path.rfind(".vmdk")
     vmdk_flat_path = vmdk_path[:pos] + "-flat" + vmdk_path[pos:]
     return (vmdk_path, vmdk_flat_path)
Exemplo n.º 19
0
 def remove_iso(self, iso_ds_path):
     try:
         os.remove(datastore_to_os_path(iso_ds_path))
     except:
         # The iso may not exist, so just catch and move on.
         pass
Exemplo n.º 20
0
 def remove_iso(self, iso_ds_path):
     try:
         os.remove(datastore_to_os_path(iso_ds_path))
     except:
         # The iso may not exist, so just catch and move on.
         pass
Exemplo n.º 21
0
 def finalize_image(self, datastore_id, tmp_dir, image_id):
     """ Installs an image using image data staged at a temp directory.
     """
     self._move_image(image_id, datastore_id, datastore_to_os_path(tmp_dir))
     self._create_image_timestamp_file_from_ids(datastore_id, image_id)
Exemplo n.º 22
0
 def test_path_conversion(self, ds_path, expected_os_path):
     path = datastore_to_os_path(ds_path)
     assert_that(path, equal_to(expected_os_path))
Exemplo n.º 23
0
 def finalize_image(self, datastore_id, tmp_dir, image_id):
     """ Installs an image using image data staged at a temp directory.
     """
     self._move_image(image_id, datastore_id, datastore_to_os_path(tmp_dir))
     self._create_image_timestamp_file_from_ids(datastore_id, image_id)