Esempio n. 1
0
def qemu_img_info(path, run_as_root=True):
    """Return an object containing the parsed output from qemu-img info."""
    cmd = ['env', 'LC_ALL=C', 'qemu-img', 'info', path]

    if os.name == 'nt':
        cmd = cmd[2:]
    out, _err = utils.execute(*cmd,
                              run_as_root=run_as_root,
                              prlimit=QEMU_IMG_LIMITS)
    info = imageutils.QemuImgInfo(out)

    # From Cinder's point of view, any 'luks' formatted images
    # should be treated as 'raw'.
    if info.file_format == 'luks':
        info.file_format = 'raw'

    return info
Esempio n. 2
0
def qemu_img_info(path, format=None):
    """Return an object containing the parsed output from qemu-img info."""
    # TODO(mikal): this code should not be referring to a libvirt specific
    # flag.
    if not os.path.exists(path) and CONF.libvirt.images_type != 'rbd':
        raise exception.DiskNotFound(location=path)

    try:
        # The following check is about ploop images that reside within
        # directories and always have DiskDescriptor.xml file beside them
        if (os.path.isdir(path)
                and os.path.exists(os.path.join(path, "DiskDescriptor.xml"))):
            path = os.path.join(path, "root.hds")

        cmd = ('env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info', path)
        if format is not None:
            cmd = cmd + ('-f', format)
        # Check to see if the qemu version is >= 2.10 because if so, we need
        # to add the --force-share flag.
        if QEMU_VERSION and operator.ge(QEMU_VERSION, QEMU_VERSION_REQ_SHARED):
            cmd = cmd + ('--force-share', )
        out, err = utils.execute(*cmd, prlimit=QEMU_IMG_LIMITS)
    except processutils.ProcessExecutionError as exp:
        # this means we hit prlimits, make the exception more specific
        if exp.exit_code == -9:
            msg = (_("qemu-img aborted by prlimits when inspecting "
                     "%(path)s : %(exp)s") % {
                         'path': path,
                         'exp': exp
                     })
        else:
            msg = (_("qemu-img failed to execute on %(path)s : %(exp)s") % {
                'path': path,
                'exp': exp
            })
        raise exception.InvalidDiskInfo(reason=msg)

    if not out:
        msg = (_("Failed to run qemu-img info on %(path)s : %(error)s") % {
            'path': path,
            'error': err
        })
        raise exception.InvalidDiskInfo(reason=msg)

    return imageutils.QemuImgInfo(out)
Esempio n. 3
0
    def test_copy_volume_to_image_raw_image(self):
        drv = self._driver

        volume = self._simple_volume()
        volume_path = '%s/%s' % (self.TEST_MNT_POINT, volume['name'])
        image_meta = {'id': '10958016-e196-42e3-9e7f-5d8927ae3099'}

        with mock.patch.object(drv, 'get_active_image_from_info') as \
                mock_get_active_image_from_info, \
                mock.patch.object(drv, '_local_volume_dir') as \
                mock_local_volume_dir, \
                mock.patch.object(image_utils, 'qemu_img_info') as \
                mock_qemu_img_info, \
                mock.patch.object(image_utils, 'upload_volume') as \
                mock_upload_volume, \
                mock.patch.object(image_utils, 'create_temporary_file') as \
                mock_create_temporary_file:
            mock_get_active_image_from_info.return_value = volume['name']

            mock_local_volume_dir.return_value = self.TEST_MNT_POINT

            mock_create_temporary_file.return_value = self.TEST_TMP_FILE

            qemu_img_output = """image: %s
            file format: raw
            virtual size: 1.0G (1073741824 bytes)
            disk size: 173K
            """ % volume['name']
            img_info = imageutils.QemuImgInfo(qemu_img_output)
            mock_qemu_img_info.return_value = img_info

            upload_path = volume_path

            drv.copy_volume_to_image(mock.ANY, volume, mock.ANY, image_meta)

            mock_get_active_image_from_info.assert_called_once_with(volume)
            mock_local_volume_dir.assert_called_once_with(volume)
            mock_qemu_img_info.assert_called_once_with(volume_path,
                                                       run_as_root=False)
            mock_upload_volume.assert_called_once_with(mock.ANY,
                                                       mock.ANY,
                                                       mock.ANY,
                                                       upload_path,
                                                       run_as_root=False)
            self.assertTrue(mock_create_temporary_file.called)
Esempio n. 4
0
    def test_create_snapshot_from_bootable_volume_fail(self, mock_qemu_info):
        """Test create snapshot from bootable volume.

        But it fails to volume_glance_metadata_copy_to_snapshot.
        As a result, status of snapshot is changed to ERROR.
        """
        # create bootable volume from image
        volume = self._create_volume_from_image()
        volume_id = volume['id']
        self.assertEqual('available', volume['status'])
        self.assertTrue(volume['bootable'])

        image_info = imageutils.QemuImgInfo()
        image_info.virtual_size = '1073741824'
        mock_qemu_info.return_value = image_info

        # get volume's volume_glance_metadata
        ctxt = context.get_admin_context()
        vol_glance_meta = db.volume_glance_metadata_get(ctxt, volume_id)
        self.assertTrue(vol_glance_meta)
        snap = create_snapshot(volume_id)
        snap_stat = snap.status
        self.assertTrue(snap.id)
        self.assertTrue(snap_stat)

        # set to return DB exception
        with mock.patch.object(db, 'volume_glance_metadata_copy_to_snapshot')\
                as mock_db:
            mock_db.side_effect = exception.MetadataCopyFailure(
                reason="Because of DB service down.")
            # create snapshot from bootable volume
            self.assertRaises(exception.MetadataCopyFailure,
                              self.volume.create_snapshot, ctxt, snap)

        # get snapshot's volume_glance_metadata
        self.assertRaises(exception.GlanceMetadataNotFound,
                          db.volume_snapshot_glance_metadata_get, ctxt,
                          snap.id)

        # ensure that status of snapshot is 'error'
        self.assertEqual(fields.SnapshotStatus.ERROR, snap.status)

        # cleanup resource
        snap.destroy()
        db.volume_destroy(ctxt, volume_id)
Esempio n. 5
0
    def test_create_volume_from_image_with_img_too_big(self, mock_qemu_info):
        """Test create volume with ImageCopyFailure

        This exception should not trigger rescheduling and allocated_capacity
        should be incremented so we're having assert for that here.
        """
        image_info = imageutils.QemuImgInfo()
        image_info.virtual_size = '1073741824'
        mock_qemu_info.return_value = image_info

        def fake_copy_image_to_volume(context, volume, image_service,
                                      image_id):
            raise exception.ImageTooBig(image_id=image_id, reason='')

        self.mock_object(self.volume.driver, 'copy_image_to_volume',
                         fake_copy_image_to_volume)
        self.assertRaises(exception.ImageTooBig,
                          self._create_volume_from_image)
Esempio n. 6
0
    def test_create_from_image_cache_miss_error_size_invalid(
            self, mock_qemu_info, mock_get_internal_context,
            mock_create_from_img_dl, mock_create_from_src,
            mock_handle_bootable, mock_fetch_img):
        mock_fetch_img.return_value = mock.MagicMock()
        image_info = imageutils.QemuImgInfo()
        image_info.virtual_size = '2147483648'
        mock_qemu_info.return_value = image_info
        self.mock_driver.clone_image.return_value = (None, False)
        self.mock_cache.get_entry.return_value = None

        volume = fake_volume.fake_volume_obj(self.ctxt, size=1,
                                             host='foo@bar#pool')
        image_volume = fake_volume.fake_db_volume(size=2)
        self.mock_db.volume_create.return_value = image_volume

        image_location = 'someImageLocationStr'
        image_id = 'c7a8b8d4-e519-46c7-a0df-ddf1b9b9fff2'
        image_meta = mock.MagicMock()

        manager = create_volume_manager.CreateVolumeFromSpecTask(
            self.mock_volume_manager,
            self.mock_db,
            self.mock_driver,
            image_volume_cache=self.mock_cache
        )

        self.assertRaises(
            exception.ImageUnacceptable,
            manager._create_from_image,
            self.ctxt,
            volume,
            image_location,
            image_id,
            image_meta,
            self.mock_image_service
        )

        # The volume size should NOT be changed when in this case
        self.assertFalse(self.mock_db.volume_update.called)

        # Make sure we didn't try and create a cache entry
        self.assertFalse(self.mock_cache.ensure_space.called)
        self.assertFalse(self.mock_cache.create_cache_entry.called)
Esempio n. 7
0
    def test_backup_volume(self, mock_open, mock_temporary_chown,
                           mock_qemu_img_info):
        """Backup a volume with no snapshots."""

        info = imageutils.QemuImgInfo()
        info.file_format = 'raw'
        mock_qemu_img_info.return_value = info

        backup = {'volume_id': _FAKE_VOLUME['id']}
        mock_backup_service = mock.MagicMock()
        self.drv.db.volume_get.return_value = _FAKE_VOLUME

        self.drv.backup_volume(context, backup, mock_backup_service)

        mock_qemu_img_info.assert_called_once_with(_FAKE_VOL_PATH)
        mock_temporary_chown.assert_called_once_with(_FAKE_VOL_PATH)
        mock_open.assert_called_once_with(_FAKE_VOL_PATH)
        mock_backup_service.backup.assert_called_once_with(
            backup,
            mock_open().__enter__())
Esempio n. 8
0
    def test_create_volume_from_image_unavailable_no_attach_info(
            self, mock_qemu_info, mock_detach, mock_connect, *args):
        """Test create volume with ImageCopyFailure

        We'll raise an exception on _connect_device call to confirm that it
        detaches the volume even if the exception doesn't have attach_info.
        """
        mock_connect.side_effect = NameError
        image_info = imageutils.QemuImgInfo()
        image_info.virtual_size = '1073741824'
        mock_qemu_info.return_value = image_info

        unbound_copy_method = cinder.volume.driver.BaseVD.copy_image_to_volume
        bound_copy_method = unbound_copy_method.__get__(self.volume.driver)
        with mock.patch.object(self.volume.driver, 'copy_image_to_volume',
                               side_effect=bound_copy_method):
            self.assertRaises(exception.ImageCopyFailure,
                              self._create_volume_from_image,
                              fakeout_copy_image_to_volume=False)
        # We must have called detach method.
        self.assertEqual(1, mock_detach.call_count)
Esempio n. 9
0
 def test_qemu_img_info(self):
     img_info = self._initialize_img_info()
     img_info = img_info + ('cluster_size: %s' % self.cluster_size, )
     if self.backing_file is not None:
         img_info = img_info + ('backing file: %s' % self.backing_file, )
     if self.encrypted is not None:
         img_info = img_info + ('encrypted: %s' % self.encrypted, )
     if self.garbage_before_snapshot is True:
         img_info = img_info + ('blah BLAH: bb', )
     if self.snapshot_count is not None:
         img_info = self._insert_snapshots(img_info)
     if self.garbage_before_snapshot is False:
         img_info = img_info + ('junk stuff: bbb', )
     example_output = '\n'.join(img_info)
     image_info = imageutils.QemuImgInfo(example_output)
     self._base_validation(image_info)
     self.assertEqual(image_info.cluster_size, self.exp_cluster_size)
     if self.backing_file is not None:
         self.assertEqual(image_info.backing_file, self.exp_backing_file)
     if self.encrypted is not None:
         self.assertEqual(image_info.encrypted, self.encrypted)
Esempio n. 10
0
    def test_create_snapshot_from_bootable_volume(self, mock_qemu_info):
        """Test create snapshot from bootable volume."""
        # create bootable volume from image
        volume = self._create_volume_from_image()
        volume_id = volume['id']
        self.assertEqual('available', volume['status'])
        self.assertTrue(volume['bootable'])

        image_info = imageutils.QemuImgInfo()
        image_info.virtual_size = '1073741824'
        mock_qemu_info.return_value = image_info

        # get volume's volume_glance_metadata
        ctxt = context.get_admin_context()
        vol_glance_meta = db.volume_glance_metadata_get(ctxt, volume_id)
        self.assertTrue(bool(vol_glance_meta))

        # create snapshot from bootable volume
        snap = create_snapshot(volume_id)
        self.volume.create_snapshot(ctxt, snap)

        # get snapshot's volume_glance_metadata
        snap_glance_meta = db.volume_snapshot_glance_metadata_get(
            ctxt, snap.id)
        self.assertTrue(bool(snap_glance_meta))

        # ensure that volume's glance metadata is copied
        # to snapshot's glance metadata
        self.assertEqual(len(vol_glance_meta), len(snap_glance_meta))
        vol_glance_dict = {x.key: x.value for x in vol_glance_meta}
        snap_glance_dict = {x.key: x.value for x in snap_glance_meta}
        self.assertDictEqual(vol_glance_dict, snap_glance_dict)

        # ensure that snapshot's status is changed to 'available'
        self.assertEqual(fields.SnapshotStatus.AVAILABLE, snap.status)

        # cleanup resource
        snap.destroy()
        db.volume_destroy(ctxt, volume_id)
Esempio n. 11
0
def qemu_img_info(path, format=None):
    """Return an object containing the parsed output from qemu-img info."""
    # TODO(mikal): this code should not be referring to a libvirt specific
    # flag.
    if not os.path.exists(path) and CONF.libvirt.images_type != 'rbd':
        raise exception.DiskNotFound(location=path)

    try:
        cmd = ('env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info', path)
        if format is not None:
            cmd = cmd + ('-f', format)
        out, err = utils.execute(*cmd, prlimit=QEMU_IMG_LIMITS)
    except processutils.ProcessExecutionError as exp:
        msg = (_("qemu-img failed to execute on %(path)s : %(exp)s") %
                {'path': path, 'exp': exp})
        raise exception.InvalidDiskInfo(reason=msg)

    if not out:
        msg = (_("Failed to run qemu-img info on %(path)s : %(error)s") %
               {'path': path, 'error': err})
        raise exception.InvalidDiskInfo(reason=msg)

    return imageutils.QemuImgInfo(out)
Esempio n. 12
0
def qemu_img_info(path, run_as_root=True, force_share=False):
    """Return an object containing the parsed output from qemu-img info."""
    cmd = ['env', 'LC_ALL=C', 'qemu-img', 'info']
    if force_share:
        if qemu_img_supports_force_share():
            cmd.append('--force-share')
        else:
            msg = _("qemu-img --force-share requested, but "
                    "qemu-img does not support this parameter")
            LOG.warning(msg)
    cmd.append(path)

    if os.name == 'nt':
        cmd = cmd[2:]
    out, _err = utils.execute(*cmd, run_as_root=run_as_root,
                              prlimit=QEMU_IMG_LIMITS)
    info = imageutils.QemuImgInfo(out)

    # From Cinder's point of view, any 'luks' formatted images
    # should be treated as 'raw'.
    if info.file_format == 'luks':
        info.file_format = 'raw'

    return info
Esempio n. 13
0
    def test_create_from_image_cache_miss_error_downloading(
            self, mock_qemu_info, mock_volume_get, mock_volume_update,
            mock_get_internal_context,
            mock_create_from_img_dl, mock_create_from_src,
            mock_handle_bootable, mock_fetch_img):
        mock_fetch_img.return_value = mock.MagicMock()
        image_info = imageutils.QemuImgInfo()
        image_info.virtual_size = '2147483648'
        mock_qemu_info.return_value = image_info
        self.mock_driver.clone_image.return_value = (None, False)
        self.mock_cache.get_entry.return_value = None

        volume = fake_volume.fake_volume_obj(self.ctxt, size=10,
                                             host='foo@bar#pool')
        mock_volume_get.return_value = volume

        mock_create_from_img_dl.side_effect = exception.CinderException()

        image_location = 'someImageLocationStr'
        image_id = 'c7a8b8d4-e519-46c7-a0df-ddf1b9b9fff2'
        image_meta = mock.MagicMock()

        manager = create_volume_manager.CreateVolumeFromSpecTask(
            self.mock_volume_manager,
            self.mock_db,
            self.mock_driver,
            image_volume_cache=self.mock_cache
        )

        self.assertRaises(
            exception.CinderException,
            manager._create_from_image,
            self.ctxt,
            volume,
            image_location,
            image_id,
            image_meta,
            self.mock_image_service
        )

        # Make sure clone_image is always called
        self.assertTrue(self.mock_driver.clone_image.called)

        # The image download should happen if clone fails and
        # we get a cache miss
        mock_create_from_img_dl.assert_called_once_with(
            self.ctxt,
            mock.ANY,
            image_location,
            image_id,
            self.mock_image_service
        )

        # The volume size should be reduced to virtual_size and then put back,
        # especially if there is an exception while creating the volume.
        self.assertEqual(2, mock_volume_update.call_count)
        mock_volume_update.assert_any_call(self.ctxt, volume.id, {'size': 2})
        mock_volume_update.assert_any_call(self.ctxt, volume.id, {'size': 10})

        # Make sure we didn't try and create a cache entry
        self.assertFalse(self.mock_cache.ensure_space.called)
        self.assertFalse(self.mock_cache.create_cache_entry.called)
Esempio n. 14
0
    def test_create_from_image_cache_miss(
            self, mock_qemu_info, mock_volume_get, mock_volume_update,
            mock_get_internal_context, mock_create_from_img_dl,
            mock_create_from_src, mock_handle_bootable, mock_fetch_img):
        mock_get_internal_context.return_value = self.ctxt
        mock_fetch_img.return_value = mock.MagicMock(
            spec=utils.get_file_spec())
        image_info = imageutils.QemuImgInfo()
        image_info.virtual_size = '2147483648'
        mock_qemu_info.return_value = image_info
        self.mock_driver.clone_image.return_value = (None, False)
        self.mock_cache.get_entry.return_value = None

        volume = fake_volume.fake_volume_obj(self.ctxt, size=10,
                                             host='foo@bar#pool')
        mock_volume_get.return_value = volume

        image_location = 'someImageLocationStr'
        image_id = 'c7a8b8d4-e519-46c7-a0df-ddf1b9b9fff2'
        image_meta = mock.MagicMock()

        manager = create_volume_manager.CreateVolumeFromSpecTask(
            self.mock_volume_manager,
            self.mock_db,
            self.mock_driver,
            image_volume_cache=self.mock_cache
        )

        manager._create_from_image(self.ctxt,
                                   volume,
                                   image_location,
                                   image_id,
                                   image_meta,
                                   self.mock_image_service)

        # Make sure clone_image is always called
        self.assertTrue(self.mock_driver.clone_image.called)

        # The image download should happen if clone fails and
        # we get a cache miss
        mock_create_from_img_dl.assert_called_once_with(
            self.ctxt,
            mock.ANY,
            image_location,
            image_id,
            self.mock_image_service
        )

        # The volume size should be reduced to virtual_size and then put back
        mock_volume_update.assert_any_call(self.ctxt, volume.id, {'size': 2})
        mock_volume_update.assert_any_call(self.ctxt, volume.id, {'size': 10})

        # Make sure created a new cache entry
        (self.mock_volume_manager.
            _create_image_cache_volume_entry.assert_called_once_with(
                self.ctxt, volume, image_id, image_meta))

        mock_handle_bootable.assert_called_once_with(
            self.ctxt,
            volume['id'],
            image_id=image_id,
            image_meta=image_meta
        )