Example #1
0
    def _full_backup(self, backup_id, volume_id, src_volume, src_name, length):
        """Perform a full backup of src volume.

        First creates a base backup image in our backup location then performs
        an chunked copy of all data from source volume to a new backup rbd
        image.
        """
        backup_name = self._get_backup_base_name(volume_id, backup_id)

        with rbd_driver.RADOSClient(self, self._ceph_backup_pool) as client:
            # First create base backup image
            old_format, features = self._get_rbd_support()
            LOG.debug(_("Creating base image='%s'") % (backup_name))
            self.rbd.RBD().create(ioctx=client.ioctx,
                                  name=backup_name,
                                  size=length,
                                  old_format=old_format,
                                  features=features,
                                  stripe_unit=self.rbd_stripe_unit,
                                  stripe_count=self.rbd_stripe_count)

            LOG.debug(_("Copying data"))
            dest_rbd = self.rbd.Image(client.ioctx, backup_name)
            try:
                rbd_meta = rbd_driver.RBDImageMetadata(dest_rbd,
                                                       self._ceph_backup_pool,
                                                       self._ceph_backup_user,
                                                       self._ceph_backup_conf)
                rbd_fd = rbd_driver.RBDImageIOWrapper(rbd_meta)
                self._transfer_data(src_volume, src_name, rbd_fd, backup_name,
                                    length)
            finally:
                dest_rbd.close()
Example #2
0
    def _full_restore(self, backup_id, volume_id, dest_file, dest_name,
                      length, src_snap=None):
        """Restore volume using full copy i.e. all extents.

        This will result in all extents being copied from source to
        destination.
        """
        with rbd_driver.RADOSClient(self, self._ceph_backup_pool) as client:
            # If a source snapshot is provided we assume the base is diff
            # format.
            if src_snap:
                diff_format = True
            else:
                diff_format = False

            backup_name = self._get_backup_base_name(volume_id,
                                                     backup_id=backup_id,
                                                     diff_format=diff_format)

            # Retrieve backup volume
            src_rbd = self.rbd.Image(client.ioctx, backup_name,
                                     snapshot=src_snap, read_only=True)
            try:
                rbd_meta = rbd_driver.RBDImageMetadata(src_rbd,
                                                       self._ceph_backup_pool,
                                                       self._ceph_backup_user,
                                                       self._ceph_backup_conf)
                rbd_fd = rbd_driver.RBDImageIOWrapper(rbd_meta)
                self._transfer_data(rbd_fd, backup_name, dest_file, dest_name,
                                    length)
            finally:
                src_rbd.close()
Example #3
0
    def test_backup_volume_from_rbd_fail2(self, mock_popen, mock_fnctl):
        """Test of when an exception occurs in an exception handler.

        In backup(), after an exception.BackupOperationError occurs in
        self._backup_metadata(), we want to check the process when the
        second exception occurs in self.delete().
        """
        backup_name = self.service._get_backup_base_name(self.backup_id,
                                                         diff_format=True)

        def mock_write_data():
            self.volume_file.seek(0)
            data = self.volume_file.read(self.data_length)
            self.callstack.append('write')
            checksum.update(data)
            test_file.write(data)

        def mock_read_data():
            self.callstack.append('read')
            return self.volume_file.read(self.data_length)

        self._setup_mock_popen(mock_popen, ['out', 'err'],
                               p1hook=mock_read_data,
                               p2hook=mock_write_data)

        self.mock_rbd.RBD.list = mock.Mock()
        self.mock_rbd.RBD.list.return_value = [backup_name]

        with contextlib.nested(
                mock.patch.object(self.service, 'get_backup_snaps'),
                mock.patch.object(self.service, '_rbd_diff_transfer'),
                mock.patch.object(self.service, '_full_backup'),
                mock.patch.object(
                    self.service,
                    '_backup_metadata')) as (_unused1, _u2, _u3,
                                             mock_backup_metadata):

            def mock_backup_metadata_side_effect(backup):
                raise exception.BackupOperationError(_('mock'))

            # Raise a pseudo exception.BackupOperationError.
            mock_backup_metadata.side_effect = mock_backup_metadata_side_effect
            with mock.patch.object(self.service, 'delete') as mock_delete:

                def mock_delete_side_effect(backup):
                    raise self.service.rbd.ImageBusy()

                # Raise a pseudo exception rbd.ImageBusy.
                mock_delete.side_effect = mock_delete_side_effect
                with tempfile.NamedTemporaryFile() as test_file:
                    checksum = hashlib.sha256()
                    image = self.service.rbd.Image()
                    meta = rbddriver.RBDImageMetadata(image, 'pool_foo',
                                                      'user_foo', 'conf_foo')
                    rbdio = rbddriver.RBDImageIOWrapper(meta)

                    # We expect that the second exception is
                    # notified.
                    self.assertRaises(self.service.rbd.ImageBusy,
                                      self.service.backup, self.backup, rbdio)
Example #4
0
    def test_backup_volume_from_rbd(self):
        self._create_volume_db_entry(self.volume_id, 1)
        backup = db.backup_get(self.ctxt, self.backup_id)

        self._set_common_backup_stubs(self.service)

        backup_name = self.service._get_backup_base_name(self.backup_id,
                                                         diff_format=True)

        self.stubs.Set(self.service, '_try_delete_base_image',
                       lambda *args, **kwargs: None)

        self.stubs.Set(fcntl, 'fcntl', lambda *args, **kwargs: 0)

        with tempfile.NamedTemporaryFile() as test_file:
            checksum = hashlib.sha256()

            def write_data():
                self.volume_file.seek(0)
                data = self.volume_file.read(self.length)
                self.called.append('write')
                checksum.update(data)
                test_file.write(data)

            def read_data():
                self.called.append('read')
                return self.volume_file.read(self.length)

            def rbd_list(inst, ioctx):
                self.called.append('list')
                return [backup_name]

            self._setup_mock_popen(self, ['out', 'err'],
                                   p1hook=read_data,
                                   p2hook=write_data)

            self.stubs.Set(self.service.rbd.RBD, 'list', rbd_list)

            self.stubs.Set(self.service, '_discard_bytes', lambda *args: None)

            meta = rbddriver.RBDImageMetadata(self.service.rbd.Image(),
                                              'pool_foo', 'user_foo',
                                              'conf_foo')
            rbd_io = rbddriver.RBDImageIOWrapper(meta)

            self.service.backup(backup, rbd_io)

            self.assertEqual(self.called, [
                'list', 'popen_init', 'read', 'popen_init', 'write',
                'stdout_close', 'communicate'
            ])

            # Ensure the files are equal
            self.assertEqual(checksum.digest(), self.checksum.digest())
Example #5
0
    def test_backup_volume_from_rbd(self, mock_popen, mock_fnctl):
        backup_name = self.service._get_backup_base_name(self.backup_id,
                                                         diff_format=True)

        def mock_write_data():
            self.volume_file.seek(0)
            data = self.volume_file.read(self.data_length)
            self.callstack.append('write')
            checksum.update(data)
            test_file.write(data)

        def mock_read_data():
            self.callstack.append('read')
            return self.volume_file.read(self.data_length)

        self._setup_mock_popen(mock_popen,
                               ['out', 'err'],
                               p1hook=mock_read_data,
                               p2hook=mock_write_data)

        self.mock_rbd.RBD.list = mock.Mock()
        self.mock_rbd.RBD.list.return_value = [backup_name]

        with mock.patch.object(self.service, '_backup_metadata'):
            with mock.patch.object(self.service, 'get_backup_snaps') as \
                    mock_get_backup_snaps:
                with mock.patch.object(self.service, '_full_backup') as \
                        mock_full_backup:
                    with mock.patch.object(self.service,
                                           '_try_delete_base_image'):
                        with tempfile.NamedTemporaryFile() as test_file:
                            checksum = hashlib.sha256()
                            image = self.service.rbd.Image()
                            meta = rbddriver.RBDImageMetadata(image,
                                                              'pool_foo',
                                                              'user_foo',
                                                              'conf_foo')
                            rbdio = rbddriver.RBDImageIOWrapper(meta)
                            self.service.backup(self.backup, rbdio)

                            self.assertEqual(self.callstack, ['popen_init',
                                                              'read',
                                                              'popen_init',
                                                              'write',
                                                              'stdout_close',
                                                              'communicate'])

                            self.assertFalse(mock_full_backup.called)
                            self.assertTrue(mock_get_backup_snaps.called)

                            # Ensure the files are equal
                            self.assertEqual(checksum.digest(),
                                             self.checksum.digest())
Example #6
0
    def test_backup_volume_from_rbd(self):
        self._create_volume_db_entry(self.volume_id, 1)
        backup = db.backup_get(self.ctxt, self.backup_id)

        self._set_common_backup_stubs(self.service)

        backup_name = self.service._get_backup_base_name(self.backup_id,
                                                         diff_format=True)

        self.stubs.Set(self.service, '_try_delete_base_image',
                       lambda *args, **kwargs: None)

        with tempfile.NamedTemporaryFile() as test_file:
            checksum = hashlib.sha256()

            def write_data(inst, data, offset):
                checksum.update(data)
                test_file.write(data)

            def read_data(inst, offset, length):
                return self.volume_file.read(self.length)

            def rbd_list(inst, ioctx):
                return [backup_name]

            self.stubs.Set(self.service.rbd.Image, 'read', read_data)
            self.stubs.Set(self.service.rbd.Image, 'write', write_data)
            self.stubs.Set(self.service.rbd.RBD, 'list', rbd_list)

            meta = rbddriver.RBDImageMetadata(self.service.rbd.Image(),
                                              'pool_foo', 'user_foo',
                                              'conf_foo')
            rbd_io = rbddriver.RBDImageIOWrapper(meta)

            self.service.backup(backup, rbd_io)

            # Ensure the files are equal
            self.assertEqual(checksum.digest(), self.checksum.digest())
    def test_backup_volume_from_rbd_fail(self, mock_popen, mock_fnctl):
        """Test of when an exception occurs in an exception handler.

        In _backup_rbd(), after an exception.BackupRBDOperationFailed
        occurs in self._rbd_diff_transfer(), we want to check the
        process when the second exception occurs in
        self._try_delete_base_image().
        """
        backup_name = self.service._get_backup_base_name(self.backup_id,
                                                         diff_format=True)

        def mock_write_data():
            self.volume_file.seek(0)
            data = self.volume_file.read(self.data_length)
            self.callstack.append('write')
            checksum.update(data)
            test_file.write(data)

        def mock_read_data():
            self.callstack.append('read')
            return self.volume_file.read(self.data_length)

        self._setup_mock_popen(mock_popen, ['out', 'err'],
                               p1hook=mock_read_data,
                               p2hook=mock_write_data)

        self.mock_rbd.RBD.list = mock.Mock()
        self.mock_rbd.RBD.list.return_value = [backup_name]

        with mock.patch.object(self.service, 'get_backup_snaps'), \
                mock.patch.object(self.service, '_rbd_diff_transfer') as \
                mock_rbd_diff_transfer:

            def mock_rbd_diff_transfer_side_effect(src_name, src_pool,
                                                   dest_name, dest_pool,
                                                   src_user, src_conf,
                                                   dest_user, dest_conf,
                                                   src_snap, from_snap):
                raise exception.BackupRBDOperationFailed(_('mock'))

            # Raise a pseudo exception.BackupRBDOperationFailed.
            mock_rbd_diff_transfer.side_effect \
                = mock_rbd_diff_transfer_side_effect

            with mock.patch.object(self.service, '_full_backup'), \
                    mock.patch.object(self.service,
                                      '_try_delete_base_image') as \
                    mock_try_delete_base_image:

                def mock_try_delete_base_image_side_effect(
                        backup_id, volume_id, base_name):
                    raise self.service.rbd.ImageNotFound(_('mock'))

                # Raise a pesudo exception rbd.ImageNotFound.
                mock_try_delete_base_image.side_effect \
                    = mock_try_delete_base_image_side_effect
                with mock.patch.object(self.service, '_backup_metadata'):
                    with tempfile.NamedTemporaryFile() as test_file:
                        checksum = hashlib.sha256()
                        image = self.service.rbd.Image()
                        meta = rbddriver.RBDImageMetadata(
                            image, 'pool_foo', 'user_foo', 'conf_foo')
                        rbdio = rbddriver.RBDImageIOWrapper(meta)

                        # We expect that the second exception is
                        # notified.
                        self.assertRaises(self.service.rbd.ImageNotFound,
                                          self.service.backup, self.backup,
                                          rbdio)
 def _get_wrapped_rbd_io(self, rbd_image):
     rbd_meta = rbddriver.RBDImageMetadata(rbd_image, 'pool_foo',
                                           'user_foo', 'conf_foo')
     return rbddriver.RBDImageIOWrapper(rbd_meta)