Beispiel #1
0
    def test_backup_volume(self):
        self.mox = mox_lib.Mox()
        self._driver.db = self.mox.CreateMockAnything()
        self.mox.StubOutWithMock(self._driver.db, 'volume_get')

        volume = {'id': '2', 'name': self.TEST_VOLNAME}
        self._driver.db.volume_get(context, volume['id']).AndReturn(volume)

        info = imageutils.QemuImgInfo()
        info.file_format = 'raw'
        self.mox.StubOutWithMock(image_utils, 'qemu_img_info')
        image_utils.qemu_img_info(self.TEST_VOLPATH).AndReturn(info)

        self.mox.StubOutWithMock(utils, 'temporary_chown')
        mock_tempchown = mock.MagicMock()
        utils.temporary_chown(self.TEST_VOLPATH).AndReturn(mock_tempchown)

        self.mox.StubOutWithMock(fileutils, 'file_open')
        mock_fileopen = mock.MagicMock()
        fileutils.file_open(self.TEST_VOLPATH).AndReturn(mock_fileopen)

        backup = {'volume_id': volume['id']}
        mock_servicebackup = self.mox.CreateMockAnything()
        mock_servicebackup.backup(backup, mox_lib.IgnoreArg())

        self.mox.ReplayAll()

        self._driver.backup_volume(context, backup, mock_servicebackup)
    def test_backup_volume(self):
        self.mox.StubOutWithMock(self._driver, "db")
        self.mox.StubOutWithMock(self._driver.db, "volume_get")

        volume = {"id": "2", "name": self.TEST_VOLNAME}
        self._driver.db.volume_get(context, volume["id"]).AndReturn(volume)

        info = imageutils.QemuImgInfo()
        info.file_format = "raw"
        self.mox.StubOutWithMock(image_utils, "qemu_img_info")
        image_utils.qemu_img_info(self.TEST_VOLPATH).AndReturn(info)

        self.mox.StubOutWithMock(utils, "temporary_chown")
        mock_tempchown = self.mox.CreateMockAnything()
        utils.temporary_chown(self.TEST_VOLPATH).AndReturn(mock_tempchown)
        mock_tempchown.__enter__()
        mock_tempchown.__exit__(None, None, None)

        self.mox.StubOutWithMock(fileutils, "file_open")
        mock_fileopen = self.mox.CreateMockAnything()
        fileutils.file_open(self.TEST_VOLPATH).AndReturn(mock_fileopen)
        mock_fileopen.__enter__()
        mock_fileopen.__exit__(None, None, None)

        backup = {"volume_id": volume["id"]}
        mock_servicebackup = self.mox.CreateMockAnything()
        mock_servicebackup.backup(backup, mox_lib.IgnoreArg())

        self.mox.ReplayAll()
        self._driver.backup_volume(context, backup, mock_servicebackup)
        self.mox.VerifyAll()
Beispiel #3
0
    def _get_target_chap_auth(self, context, name):

        vol_id = name.split(':')[1]
        if os.path.exists(self.iet_conf):
            try:
                with utils.temporary_chown(self.iet_conf):
                    with open(self.iet_conf, 'r') as f:
                        iet_conf_text = f.readlines()
            except Exception:
                # If we fail to handle config file, raise exception here to
                # prevent unexpected behavior during subsequent operations.
                LOG.exception(_LE("Failed to open config for %s."), vol_id)
                raise

            target_found = False
            for line in iet_conf_text:
                if target_found:
                    m = re.search('(\w+) (\w+) (\w+)', line)
                    if m:
                        return (m.group(2), m.group(3))
                    else:
                        LOG.debug("Failed to find CHAP auth from config "
                                  "for %s", vol_id)
                        return None
                elif name in line:
                    target_found = True
        else:
            # Missing config file is unxepected sisuation. But we will create
            # new config file during create_iscsi_target(). Just we warn the
            # operator here.
            LOG.warning(_LW("Failed to find CHAP auth from config for "
                            "%(vol_id)s. Config file %(conf)s does not "
                            "exist."),
                        {'vol_id': vol_id, 'conf': self.iet_conf})
            return None
Beispiel #4
0
    def remove_iscsi_target(self, tid, lun, vol_id, **kwargs):
        LOG.info(_('Removing iscsi_target for volume: %s') % vol_id)
        self._delete_logicalunit(tid, lun, **kwargs)
        self._delete_target(tid, **kwargs)
        vol_uuid_file = CONF.volume_name_template % vol_id
        conf_file = CONF.iet_conf
        if os.path.exists(conf_file):
            with utils.temporary_chown(conf_file):
                try:
                    iet_conf_text = open(conf_file, 'r+')
                    full_txt = iet_conf_text.readlines()
                    new_iet_conf_txt = []
                    count = 0
                    for line in full_txt:
                        if count > 0:
                            count -= 1
                            continue
                        elif re.search(vol_uuid_file, line):
                            count = 2
                            continue
                        else:
                            new_iet_conf_txt.append(line)

                    iet_conf_text.seek(0)
                    iet_conf_text.truncate(0)
                    iet_conf_text.writelines(new_iet_conf_txt)
                finally:
                    iet_conf_text.close()
Beispiel #5
0
def upload_volume(context, image_service, image_meta, volume_path, volume_format="raw"):
    image_id = image_meta["id"]
    if image_meta["disk_format"] == volume_format:
        LOG.debug("%s was %s, no need to convert to %s" % (image_id, volume_format, image_meta["disk_format"]))
        if os.name == "nt":
            with fileutils.file_open(volume_path) as image_file:
                image_service.update(context, image_id, {}, image_file)
        with utils.temporary_chown(volume_path):
            with fileutils.file_open(volume_path) as image_file:
                image_service.update(context, image_id, {}, image_file)
        return

    if CONF.image_conversion_dir and not os.path.exists(CONF.image_conversion_dir):
        os.makedirs(CONF.image_conversion_dir)

    fd, tmp = tempfile.mkstemp(dir=CONF.image_conversion_dir)
    os.close(fd)
    with fileutils.remove_path_on_error(tmp):
        LOG.debug("%s was %s, converting to %s" % (image_id, volume_format, image_meta["disk_format"]))
        convert_image(volume_path, tmp, image_meta["disk_format"])

        data = qemu_img_info(tmp)
        if data.file_format != image_meta["disk_format"]:
            raise exception.ImageUnacceptable(
                image_id=image_id,
                reason=_("Converted to %(f1)s, but format is now %(f2)s")
                % {"f1": image_meta["disk_format"], "f2": data.file_format},
            )

        with fileutils.file_open(tmp) as image_file:
            image_service.update(context, image_id, {}, image_file)
        fileutils.delete_if_exists(tmp)
Beispiel #6
0
    def create_iscsi_target(self, name, tid, lun, path,
                            chap_auth=None, **kwargs):

        # NOTE (jdg): Address bug: 1175207
        kwargs.pop('old_name', None)

        self._new_target(name, tid, **kwargs)
        self._new_logicalunit(tid, lun, path, **kwargs)
        if chap_auth is not None:
            (type, username, password) = chap_auth.split()
            self._new_auth(tid, type, username, password, **kwargs)

        conf_file = CONF.iet_conf
        if os.path.exists(conf_file):
            try:
                volume_conf = """
                        Target %s
                            %s
                            Lun 0 Path=%s,Type=%s
                """ % (name, chap_auth, path, self._iotype(path))

                with utils.temporary_chown(conf_file):
                    f = open(conf_file, 'a+')
                    f.write(volume_conf)
                    f.close()
            except exception.ProcessExecutionError as e:
                vol_id = name.split(':')[1]
                LOG.error(_("Failed to create iscsi target for volume "
                            "id:%(vol_id)s: %(e)s")
                          % {'vol_id': vol_id, 'e': str(e)})
                raise exception.ISCSITargetCreateFailed(volume_id=vol_id)
        return tid
Beispiel #7
0
def upload_volume(context, image_service, image_meta, volume_path):
    image_id = image_meta['id']
    if (image_meta['disk_format'] == 'raw'):
        LOG.debug("%s was raw, no need to convert to %s" %
                  (image_id, image_meta['disk_format']))
        with utils.temporary_chown(volume_path):
            with fileutils.file_open(volume_path) as image_file:
                image_service.update(context, image_id, {}, image_file)
        return

    if (CONF.image_conversion_dir and not
            os.path.exists(CONF.image_conversion_dir)):
        os.makedirs(CONF.image_conversion_dir)

    fd, tmp = tempfile.mkstemp(dir=CONF.image_conversion_dir)
    os.close(fd)
    with fileutils.remove_path_on_error(tmp):
        LOG.debug("%s was raw, converting to %s" %
                  (image_id, image_meta['disk_format']))
        convert_image(volume_path, tmp, image_meta['disk_format'])

        data = qemu_img_info(tmp)
        if data.file_format != image_meta['disk_format']:
            raise exception.ImageUnacceptable(
                image_id=image_id,
                reason=_("Converted to %(f1)s, but format is now %(f2)s") %
                {'f1': image_meta['disk_format'], 'f2': data.file_format})

        with fileutils.file_open(tmp) as image_file:
            image_service.update(context, image_id, {}, image_file)
        os.unlink(tmp)
Beispiel #8
0
    def _get_available_nvmf_subsystems(self):
        __, tmp_file_path = tempfile.mkstemp(prefix='nvmet')

        # nvmetcli doesn't support printing to stdout yet,
        try:
            out, err = nvmcli.save(tmp_file_path)
        except putils.ProcessExecutionError:
            with excutils.save_and_reraise_exception():
                LOG.exception('Error from nvmetcli save')
                self._delete_file(tmp_file_path)

        # temp file must be readable by this process user
        # in order to avoid executing cat as root
        with utils.temporary_chown(tmp_file_path):
            try:
                out = cinder.privsep.path.readfile(tmp_file_path)
            except putils.ProcessExecutionError:
                with excutils.save_and_reraise_exception():
                    LOG.exception('Failed to read: %s', tmp_file_path)
                    self._delete_file(tmp_file_path)
            nvmf_subsystems = json.loads(out)

        self._delete_file(tmp_file_path)

        return nvmf_subsystems
Beispiel #9
0
 def backup_volume(self, context, backup, backup_service):
     """Create a new backup from an existing volume."""
     volume = self.db.volume_get(context, backup['volume_id'])
     volume_path = self.local_path(volume)
     with utils.temporary_chown(volume_path):
         with fileutils.file_open(volume_path) as volume_file:
             backup_service.backup(backup, volume_file)
Beispiel #10
0
def upload_volume(context, image_service, image_meta, volume_path,
                  volume_format='raw', run_as_root=True):
    image_id = image_meta['id']
    if (image_meta['disk_format'] == volume_format):
        LOG.debug("%s was %s, no need to convert to %s",
                  image_id, volume_format, image_meta['disk_format'])
        if os.name == 'nt' or os.access(volume_path, os.R_OK):
            with fileutils.file_open(volume_path, 'rb') as image_file:
                image_service.update(context, image_id, {}, image_file)
        else:
            with utils.temporary_chown(volume_path):
                with fileutils.file_open(volume_path) as image_file:
                    image_service.update(context, image_id, {}, image_file)
        return

    with temporary_file() as tmp:
        LOG.debug("%s was %s, converting to %s",
                  image_id, volume_format, image_meta['disk_format'])
        convert_image(volume_path, tmp, image_meta['disk_format'],
                      run_as_root=run_as_root)

        data = qemu_img_info(tmp, run_as_root=run_as_root)
        if data.file_format != image_meta['disk_format']:
            raise exception.ImageUnacceptable(
                image_id=image_id,
                reason=_("Converted to %(f1)s, but format is now %(f2)s") %
                {'f1': image_meta['disk_format'], 'f2': data.file_format})

        with fileutils.file_open(tmp, 'rb') as image_file:
            image_service.update(context, image_id, {}, image_file)
Beispiel #11
0
    def backup_volume(self, context, backup, backup_service):
        """Create a new backup from an existing volume."""
        volume = self.db.volume_get(context, backup.volume_id)
        snapshot = None
        if backup.snapshot_id:
            snapshot = objects.Snapshot.get_by_id(context, backup.snapshot_id)
        temp_snapshot = None
        # NOTE(xyang): If it is to backup from snapshot, back it up
        # directly. No need to clean it up.
        if snapshot:
            volume_path = self.local_path(snapshot)
        else:
            # NOTE(xyang): If it is not to backup from snapshot, check volume
            # status. If the volume status is 'in-use', create a temp snapshot
            # from the source volume, backup the temp snapshot, and then clean
            # up the temp snapshot; if the volume status is 'available', just
            # backup the volume.
            previous_status = volume.get('previous_status', None)
            if previous_status == "in-use":
                temp_snapshot = self._create_temp_snapshot(context, volume)
                backup.temp_snapshot_id = temp_snapshot.id
                backup.save()
                volume_path = self.local_path(temp_snapshot)
            else:
                volume_path = self.local_path(volume)

        try:
            with utils.temporary_chown(volume_path):
                with open(volume_path) as volume_file:
                    backup_service.backup(backup, volume_file)
        finally:
            if temp_snapshot:
                self._delete_temp_snapshot(context, temp_snapshot)
                backup.temp_snapshot_id = None
                backup.save()
Beispiel #12
0
def _open_volume_with_path(path, mode):
    try:
        with utils.temporary_chown(path):
            handle = open(path, mode)
            return handle
    except Exception:
        LOG.error(_LE("Failed to open volume from %(path)s."), {'path': path})
Beispiel #13
0
    def create_iscsi_target(self, name, tid, lun, path,
                            chap_auth=None, **kwargs):
        self._new_target(name, tid, **kwargs)
        self._new_logicalunit(tid, lun, path, **kwargs)
        if chap_auth is not None:
            (type, username, password) = chap_auth.split()
            self._new_auth(tid, type, username, password, **kwargs)

        conf_file = FLAGS.iet_conf
        if os.path.exists(conf_file):
            try:
                volume_conf = """
                        Target %s
                            %s
                            Lun 0 Path=%s,Type=fileio
                """ % (name, chap_auth, path)

                with utils.temporary_chown(conf_file):
                    f = open(conf_file, 'a+')
                    f.write(volume_conf)
                    f.close()
            except exception.ProcessExecutionError, e:
                vol_id = name.split(':')[1]
                LOG.error(_("Failed to create iscsi target for volume "
                            "id:%(vol_id)s.") % locals())
                raise exception.ISCSITargetCreateFailed(volume_id=vol_id)
Beispiel #14
0
    def _run_restore(self, context, backup, volume):
        backup_service = self.service.get_backup_driver(context)

        properties = utils.brick_get_connector_properties()
        secure_enabled = (
            self.volume_rpcapi.secure_file_operations_enabled(context,
                                                              volume))
        attach_info = self._attach_device(context, volume, properties)
        try:
            device_path = attach_info['device']['path']
            if (isinstance(device_path, six.string_types) and
                    not os.path.isdir(device_path)):
                if secure_enabled:
                    with open(device_path, 'wb') as device_file:
                        backup_service.restore(backup, volume.id, device_file)
                else:
                    with utils.temporary_chown(device_path):
                        with open(device_path, 'wb') as device_file:
                            backup_service.restore(backup, volume.id,
                                                   device_file)
            # device_path is already file-like so no need to open it
            else:
                backup_service.restore(backup, volume.id, device_path)
        finally:
            self._detach_device(context, attach_info, volume, properties,
                                force=True)
Beispiel #15
0
    def _run_backup(self, context, backup, volume):
        backup_service = self.service.get_backup_driver(context)

        properties = utils.brick_get_connector_properties()
        backup_dic = self.volume_rpcapi.get_backup_device(context,
                                                          backup, volume)
        try:
            backup_device = backup_dic.get('backup_device')
            is_snapshot = backup_dic.get('is_snapshot')
            attach_info = self._attach_device(context, backup_device,
                                              properties, is_snapshot)
            try:
                device_path = attach_info['device']['path']
                if isinstance(device_path, six.string_types):
                    if backup_dic.get('secure_enabled', False):
                        with open(device_path) as device_file:
                            backup_service.backup(backup, device_file)
                    else:
                        with utils.temporary_chown(device_path):
                            with open(device_path) as device_file:
                                backup_service.backup(backup, device_file)
                # device_path is already file-like so no need to open it
                else:
                    backup_service.backup(backup, device_path)

            finally:
                self._detach_device(context, attach_info,
                                    backup_device, properties,
                                    is_snapshot)
        finally:
            backup = objects.Backup.get_by_id(context, backup.id)
            self._cleanup_temp_volumes_snapshots_when_backup_created(
                context, backup)
Beispiel #16
0
    def update_config_file(self, name, tid, path, config_auth):

        conf_file = self.iet_conf
        vol_id = name.split(':')[1]

        # If config file does not exist, create a blank conf file and
        # add configuration for the volume on the new file.
        if not os.path.exists(conf_file):
            try:
                utils.execute("truncate", conf_file, "--size=0",
                              run_as_root=True)
            except putils.ProcessExecutionError:
                LOG.exception(_LE("Failed to create %(conf)s for volume "
                                  "id:%(vol_id)s"),
                              {'conf': conf_file, 'vol_id': vol_id})
                raise exception.ISCSITargetCreateFailed(volume_id=vol_id)

        try:
            volume_conf = """
                    Target %s
                        %s
                        Lun 0 Path=%s,Type=%s
            """ % (name, config_auth, path, self._iotype(path))

            with utils.temporary_chown(conf_file):
                with open(conf_file, 'a+') as f:
                    f.write(volume_conf)
        except Exception:
            LOG.exception(_LE("Failed to update %(conf)s for volume "
                              "id:%(vol_id)s"),
                          {'conf': conf_file, 'vol_id': vol_id})
            raise exception.ISCSITargetCreateFailed(volume_id=vol_id)
Beispiel #17
0
    def restore_backup(self, context, backup, volume, backup_service):
        """Restore an existing backup to a new or existing volume."""
        LOG.debug("Begin restore of backup %s." % backup["id"])

        volume_path = self.local_path(volume)
        with utils.temporary_chown(volume_path):
            with fileutils.file_open(volume_path, "wb") as volume_file:
                backup_service.restore(backup, volume["id"], volume_file)
Beispiel #18
0
 def restore_backup(self, context, backup, volume, backup_service):
     """Restore an existing backup to a new or existing volume."""
     LOG.info(_LI('Restoring backup %(backup)s to volume %(volume)s.') %
              {'backup': backup['id'], 'volume': volume['name']})
     volume_local_path = self.local_path(volume)
     with utils.temporary_chown(volume_local_path):
         with fileutils.file_open(volume_local_path, 'wb') as volume_file:
             backup_service.restore(backup, volume['id'], volume_file)
Beispiel #19
0
 def test_matching_uid(self, mock_exec, mock_getuid, mock_stat):
     mock_stat.return_value.st_uid = 5678
     test_filename = 'a_file'
     with utils.temporary_chown(test_filename):
         pass
     mock_getuid.asset_called_once_with()
     mock_stat.assert_called_once_with(test_filename)
     self.assertFalse(mock_exec.called)
def write_data(device, data):
    print("Write data to volume.")
    if isinstance(device, six.string_types):
        with cinder_utils.temporary_chown(device):
            with open(device, 'w') as device_file:
                device_file.write(data)
    else:
        device.write(data)
    print("data is written to volume.")
Beispiel #21
0
 def restore_backup(self, context, backup, volume, backup_service):
     """Restore an existing backup to a new or existing volume."""
     LOG.info(
         _LI("Restoring backup %(backup)s to volume %(volume)s."), {"backup": backup["id"], "volume": volume.name}
     )
     volume_local_path = self.local_path(volume)
     with utils.temporary_chown(volume_local_path):
         with open(volume_local_path, "wb") as volume_file:
             backup_service.restore(backup, volume.id, volume_file)
Beispiel #22
0
    def test_temporary_chown(self):
        def fake_execute(*args, **kwargs):
            if args[0] == 'chown':
                fake_execute.uid = args[1]
        self.stubs.Set(utils, 'execute', fake_execute)

        with tempfile.NamedTemporaryFile() as f:
            with utils.temporary_chown(f.name, owner_uid=2):
                self.assertEqual(fake_execute.uid, 2)
            self.assertEqual(fake_execute.uid, os.getuid())
Beispiel #23
0
    def test_restore_backup(self):
        volume = {'id': '2', 'name': self.TEST_VOLNAME}

        self.mox.StubOutWithMock(utils, 'temporary_chown')
        mock_tempchown = mock.MagicMock()
        utils.temporary_chown(self.TEST_VOLPATH).AndReturn(mock_tempchown)

        self.mox.StubOutWithMock(fileutils, 'file_open')
        mock_fileopen = mock.MagicMock()
        fileutils.file_open(self.TEST_VOLPATH, 'wb').AndReturn(mock_fileopen)

        backup = {'id': 123, 'volume_id': volume['id']}
        mock_servicebackup = self.mox.CreateMockAnything()
        mock_servicebackup.restore(backup, volume['id'], mox_lib.IgnoreArg())

        self.mox.ReplayAll()

        self._driver.restore_backup(context, backup, volume,
                                    mock_servicebackup)
def read_data(device):
    print("Read 512 bytes from device.")
    if isinstance(device, six.string_types):
        with cinder_utils.temporary_chown(device):
            with open(device, 'r') as device_file:
                data = device_file.read(512)
                print("data is %s." % data_convert(data))

    else:
        data = device.read(512)
        print("data is %s." % data_convert(data))
Beispiel #25
0
 def test_supplied_owner_uid(self, mock_exec, mock_getuid, mock_stat):
     mock_stat.return_value.st_uid = 5678
     test_filename = 'a_file'
     with utils.temporary_chown(test_filename, owner_uid=9101):
         mock_exec.assert_called_once_with('chown', 9101, test_filename,
                                           run_as_root=True)
     self.assertFalse(mock_getuid.called)
     mock_stat.assert_called_once_with(test_filename)
     calls = [mock.call('chown', 9101, test_filename, run_as_root=True),
              mock.call('chown', 5678, test_filename, run_as_root=True)]
     mock_exec.assert_has_calls(calls)
Beispiel #26
0
 def test_get_uid(self, mock_exec, mock_getuid, mock_stat):
     mock_stat.return_value.st_uid = 5678
     test_filename = 'a_file'
     with utils.temporary_chown(test_filename):
         mock_exec.assert_called_once_with('chown', 1234, test_filename,
                                           run_as_root=True)
     mock_getuid.asset_called_once_with()
     mock_stat.assert_called_once_with(test_filename)
     calls = [mock.call('chown', 1234, test_filename, run_as_root=True),
              mock.call('chown', 5678, test_filename, run_as_root=True)]
     mock_exec.assert_has_calls(calls)
Beispiel #27
0
def upload_volume(context, image_service, image_meta, volume_path,
                  volume_format='raw', run_as_root=True):
    image_id = image_meta['id']
    if (image_meta['disk_format'] == volume_format):
        LOG.debug("%s was %s, no need to convert to %s",
                  image_id, volume_format, image_meta['disk_format'])
        if os.name == 'nt' or os.access(volume_path, os.R_OK):
            with open(volume_path, 'rb') as image_file:
                image_service.update(context, image_id, {}, image_file)
        else:
            with utils.temporary_chown(volume_path):
                with open(volume_path, 'rb') as image_file:
                    image_service.update(context, image_id, {}, image_file)
        return

    with temporary_file() as tmp:
        LOG.debug("%s was %s, converting to %s",
                  image_id, volume_format, image_meta['disk_format'])

        data = qemu_img_info(volume_path, run_as_root=run_as_root)
        backing_file = data.backing_file
        fmt = data.file_format
        if backing_file is not None:
            # Disallow backing files as a security measure.
            # This prevents a user from writing an image header into a raw
            # volume with a backing file pointing to data they wish to
            # access.
            raise exception.ImageUnacceptable(
                image_id=image_id,
                reason=_("fmt=%(fmt)s backed by:%(backing_file)s")
                % {'fmt': fmt, 'backing_file': backing_file})

        out_format = image_meta['disk_format']
        # qemu-img accepts 'vpc' as argument for 'vhd 'format and 'parallels'
        # as argument for 'ploop'.
        if out_format == 'vhd':
            out_format = 'vpc'
        if out_format == 'ploop':
            out_format = 'parallels'

        convert_image(volume_path, tmp, out_format,
                      run_as_root=run_as_root)

        data = qemu_img_info(tmp, run_as_root=run_as_root)
        if data.file_format != out_format:
            raise exception.ImageUnacceptable(
                image_id=image_id,
                reason=_("Converted to %(f1)s, but format is now %(f2)s") %
                {'f1': out_format, 'f2': data.file_format})

        with open(tmp, 'rb') as image_file:
            image_service.update(context, image_id, {}, image_file)
Beispiel #28
0
    def test_restore_backup(self):
        volume = {"id": "2", "name": self.TEST_VOLNAME}

        self.mox.StubOutWithMock(utils, "temporary_chown")
        mock_tempchown = self.mox.CreateMockAnything()
        utils.temporary_chown(self.TEST_VOLPATH).AndReturn(mock_tempchown)
        mock_tempchown.__enter__()
        mock_tempchown.__exit__(None, None, None)

        self.mox.StubOutWithMock(fileutils, "file_open")
        mock_fileopen = self.mox.CreateMockAnything()
        fileutils.file_open(self.TEST_VOLPATH, "wb").AndReturn(mock_fileopen)
        mock_fileopen.__enter__()
        mock_fileopen.__exit__(None, None, None)

        backup = {"id": 123, "volume_id": volume["id"]}
        mock_servicebackup = self.mox.CreateMockAnything()
        mock_servicebackup.restore(backup, volume["id"], mox_lib.IgnoreArg())

        self.mox.ReplayAll()
        self._driver.restore_backup(context, backup, volume, mock_servicebackup)
        self.mox.VerifyAll()
def upload_volume(context, image_service, image_meta, volume_path,
                  volume_format='raw'):
    image_id = image_meta['id']
    if (image_meta['disk_format'] == volume_format):
        LOG.debug("%s was %s, no need to convert to %s" %
                  (image_id, volume_format, image_meta['disk_format']))
        if os.name == 'nt' or os.access(volume_path, os.R_OK):
            with fileutils.file_open(volume_path, 'rb') as image_file:
                image_service.update(context, image_id, {}, image_file)
        else:
            with utils.temporary_chown(volume_path):
                with fileutils.file_open(volume_path) as image_file:
                    image_service.update(context, image_id, {}, image_file)
        return

    if (CONF.image_conversion_dir and not
            os.path.exists(CONF.image_conversion_dir)):
        os.makedirs(CONF.image_conversion_dir)

    fd, tmp = tempfile.mkstemp(dir=CONF.image_conversion_dir)
    os.close(fd)
    with fileutils.remove_path_on_error(tmp):
        LOG.debug("%s was %s, converting to %s" %
                  (image_id, volume_format, image_meta['disk_format']))

        data = qemu_img_info(volume_path)
        backing_file = data.backing_file
        fmt = data.file_format
        if backing_file is not None:
            # Disallow backing files as a security measure.
            # This prevents a user from writing an image header into a raw
            # volume with a backing file pointing to data they wish to
            # access.
            raise exception.ImageUnacceptable(
                image_id=image_id,
                reason=_("fmt=%(fmt)s backed by:%(backing_file)s")
                % {'fmt': fmt, 'backing_file': backing_file})

        convert_image(volume_path, tmp, image_meta['disk_format'],
                      bps_limit=CONF.volume_copy_bps_limit)

        data = qemu_img_info(tmp)
        if data.file_format != image_meta['disk_format']:
            raise exception.ImageUnacceptable(
                image_id=image_id,
                reason=_("Converted to %(f1)s, but format is now %(f2)s") %
                {'f1': image_meta['disk_format'], 'f2': data.file_format})

        with fileutils.file_open(tmp, 'rb') as image_file:
            image_service.update(context, image_id, {}, image_file)
        fileutils.delete_if_exists(tmp)
Beispiel #30
0
    def copy_image_to_volume(self, context, volume, image_service, image_id):
        """Fetch the image from image_service and write it to the volume."""
        LOG.debug(_('copy_image_to_volume %s.') % volume['name'])
        initiator = get_iscsi_initiator()
        connector = {}
        connector['initiator'] = initiator

        iscsi_properties, volume_path = self._attach_volume(
            context, volume, connector)

        with utils.temporary_chown(volume_path):
            with utils.file_open(volume_path, "wb") as image_file:
                image_service.download(context, image_id, image_file)

        self.terminate_connection(volume, connector)
Beispiel #31
0
 def restore_backup(self, context, backup, volume, backup_service):
     """Restore an existing backup to a new or existing volume."""
     volume_path = self.local_path(volume)
     with utils.temporary_chown(volume_path):
         with fileutils.file_open(volume_path, 'wb') as volume_file:
             backup_service.restore(backup, volume['id'], volume_file)
def upload_volume(context,
                  image_service,
                  image_meta,
                  volume_path,
                  volume_format='raw',
                  run_as_root=True):
    image_id = image_meta['id']
    if (image_meta['disk_format'] == volume_format):
        LOG.debug("%s was %s, no need to convert to %s", image_id,
                  volume_format, image_meta['disk_format'])
        if os.name == 'nt' or os.access(volume_path, os.R_OK):
            with open(volume_path, 'rb') as image_file:
                image_service.update(context, image_id,
                                     {"size": image_meta.get("size", 0)},
                                     image_file)
        else:
            with utils.temporary_chown(volume_path):
                with open(volume_path, 'rb') as image_file:
                    image_service.update(context, image_id,
                                         {"size": image_meta.get("size", 0)},
                                         image_file)
        return

    with temporary_file() as tmp:
        LOG.debug("%s was %s, converting to %s", image_id, volume_format,
                  image_meta['disk_format'])

        data = qemu_img_info(volume_path, run_as_root=run_as_root)
        backing_file = data.backing_file
        fmt = data.file_format
        if backing_file is not None:
            # Disallow backing files as a security measure.
            # This prevents a user from writing an image header into a raw
            # volume with a backing file pointing to data they wish to
            # access.
            raise exception.ImageUnacceptable(
                image_id=image_id,
                reason=_("fmt=%(fmt)s backed by:%(backing_file)s") % {
                    'fmt': fmt,
                    'backing_file': backing_file
                })

        out_format = image_meta['disk_format']
        # qemu-img accepts 'vpc' as argument for 'vhd 'format and 'parallels'
        # as argument for 'ploop'.
        if out_format == 'vhd':
            out_format = 'vpc'
        if out_format == 'ploop':
            out_format = 'parallels'

        convert_image(volume_path, tmp, out_format, run_as_root=run_as_root)

        data = qemu_img_info(tmp, run_as_root=run_as_root)
        if data.file_format != out_format:
            raise exception.ImageUnacceptable(
                image_id=image_id,
                reason=_("Converted to %(f1)s, but format is now %(f2)s") % {
                    'f1': out_format,
                    'f2': data.file_format
                })

        # qemu_img_info round the size of the of the image created.
        # For the upload process we need the exact size of the file size
        # so we get it from the opened file
        with open(tmp, 'rb') as image_file:
            old_file_position = image_file.tell()
            image_file.seek(0, os.SEEK_END)
            file_size = image_file.tell()
            image_file.seek(old_file_position, os.SEEK_SET)
            image_service.update(context, image_id, {"size": file_size},
                                 image_file)
Beispiel #33
0
 def copy_image_to_volume(self, context, volume, image_service, image_id):
     """Fetch the image from image_service and write it to the volume."""
     volume_path = self.local_path(volume)
     with utils.temporary_chown(volume_path):
         with utils.file_open(volume_path, "wb") as image_file:
             image_service.download(context, image_id, image_file)
Beispiel #34
0
 def copy_volume_to_image(self, context, volume, image_service, image_id):
     """Copy the volume to the specified image."""
     volume_path = self.local_path(volume)
     with utils.temporary_chown(volume_path):
         with utils.file_open(volume_path) as volume_file:
             image_service.update(context, image_id, {}, volume_file)
Beispiel #35
0
def upload_volume_to_vgw(context,
                         image_service,
                         image_meta,
                         volume_path,
                         volume,
                         vgw_url,
                         volume_format='raw',
                         run_as_root=True):
    LOG.error('begin time of upload_volume_to_vgw is %s' %
              (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())))
    image_id = image_meta['id']
    volume_id = volume['id']
    if (image_meta['disk_format'] == volume_format):
        LOG.debug("%s was %s, no need to convert to %s" %
                  (image_id, volume_format, image_meta['disk_format']))
        if os.name == 'nt' or os.access(volume_path, os.R_OK):
            with fileutils.file_open(volume_path, 'rb') as files:
                r = requests.post(vgw_url, data=files)
                if r.status_code != 200:
                    #LOG.error('upload file  %s  to %s failed' %(file_name,vgw_url))
                    raise exception.ImageUnacceptable(
                        reason=("upload the volume %s back_file failed" %
                                volume_id))
        else:
            with utils.temporary_chown(volume_path):
                with fileutils.file_open(volume_path) as files:
                    r = requests.post(vgw_url, data=files)
                    #LOG.debug('the request result is %s' %(str(r.status_code)))
                    if r.status_code != 200:
                        #LOG.error('upload file  %s  to %s failed' %(file_name,vgw_url))
                        raise exception.ImageUnacceptable(
                            reason=("upload the volume %s back_file failed" %
                                    volume_id))
        return

    with temporary_file() as tmp:
        LOG.debug("%s was %s, converting to %s" %
                  (image_id, volume_format, image_meta['disk_format']))
        LOG.error('begin time of convert_image is %s' %
                  (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())))
        convert_image(volume_path, tmp, image_meta['disk_format'])
        LOG.error('end time of upload_volume_to_vgw is %s' %
                  (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())))
        data = qemu_img_info(tmp)
        if data.file_format != image_meta['disk_format']:
            raise exception.ImageUnacceptable(
                image_id=image_id,
                reason=_("Converted to %(f1)s, but format is now %(f2)s") % {
                    'f1': image_meta['disk_format'],
                    'f2': data.file_format
                })

        with fileutils.file_open(tmp, 'rb') as files:
            LOG.error('begin time of upload file is %s' %
                      (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())))
            r = requests.post(vgw_url, data=files)
            #LOG.debug('the request result is %' %(str(r.status_code)))
            if r.status_code != 200:
                #LOG.error('upload file  %s  to %s failed' %(file_name,vgw_url))
                raise exception.ImageUnacceptable(
                    reason=("upload the volume %s back_file failed" %
                            volume_id))
            LOG.error('end time of upload file is %s' %
                      (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())))
    #todo delete the tmp file
    fileutils.delete_if_exists(tmp)
    LOG.error('end time of upload_volume_to_vgw is %s' %
              (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())))
    def backup_volume(self, context, backup, backup_service):
        """Create a new backup from an existing volume."""
        volume = self.db.volume_get(context, backup.volume_id)
        snapshot = None
        if backup.snapshot_id:
            snapshot = objects.Snapshot.get_by_id(context, backup.snapshot_id)

        root_helper = utils.get_root_helper()
        temp_zvol = None
        temp_zvol_snapshot = None

        temp_snapshot = None
        # NOTE(xyang): If it is to backup from snapshot, back it up
        # directly. No need to clean it up.
        if snapshot:
            volume_path = self.local_path(snapshot)
        else:
            # NOTE(xyang): If it is not to backup from snapshot, check volume
            # status. If the volume status is 'in-use', create a temp snapshot
            # from the source volume, backup the temp snapshot, and then clean
            # up the temp snapshot; if the volume status is 'available', just
            # backup the volume.
            previous_status = volume.get('previous_status', None)
            if previous_status == "in-use":
                temp_snapshot = self._create_temp_snapshot(context, volume)
                backup.temp_snapshot_id = temp_snapshot.id
                backup.save()
                volume_path = self.local_path(temp_snapshot)
            else:
                volume_path = self.local_path(volume)

        try:
            with utils.temporary_chown(volume_path):
                with open(volume_path) as volume_file:
                    backup_service.backup(backup, volume_file)
        finally:
            # Destroy temporary volume (if exists)
            if temp_zvol:
                try:
                    self._execute('zfs',
                                  'destroy',
                                  '-d',
                                  temp_zvol,
                                  root_helper=root_helper,
                                  run_as_root=True)
                except processutils.ProcessExecutionError as exc:
                    exception_message = (_("Failed to delete temporary zvol, "
                                           "error message was: %s") %
                                         six.text_type(exc.stderr))
                    raise exception.VolumeBackendAPIException(
                        data=exception_message)

            # Destroy temporary snapshot (if exists)
            if temp_zvol_snapshot:
                try:
                    self._execute('zfs',
                                  'destroy',
                                  '-d',
                                  temp_zvol_snapshot,
                                  root_helper=root_helper,
                                  run_as_root=True)
                except processutils.ProcessExecutionError as exc:
                    exception_message = (
                        _("Failed to delete temporary snapshot, "
                          "error message was: %s") % six.text_type(exc.stderr))
                    raise exception.VolumeBackendAPIException(
                        data=exception_message)
Beispiel #37
0
def upload_volume(context,
                  image_service,
                  image_meta,
                  volume_path,
                  volume_format='raw',
                  run_as_root=True,
                  compress=True,
                  store_id=None,
                  base_image_ref=None):
    # NOTE: You probably want to use volume_utils.upload_volume(),
    # not this function.
    image_id = image_meta['id']
    if image_meta.get('container_format') != 'compressed':
        if (image_meta['disk_format'] == volume_format):
            LOG.debug("%s was %s, no need to convert to %s", image_id,
                      volume_format, image_meta['disk_format'])
            if os.name == 'nt' or os.access(volume_path, os.R_OK):
                with open(volume_path, 'rb') as image_file:
                    image_service.update(context,
                                         image_id, {},
                                         tpool.Proxy(image_file),
                                         store_id=store_id,
                                         base_image_ref=base_image_ref)
            else:
                with utils.temporary_chown(volume_path):
                    with open(volume_path, 'rb') as image_file:
                        image_service.update(context,
                                             image_id, {},
                                             tpool.Proxy(image_file),
                                             store_id=store_id,
                                             base_image_ref=base_image_ref)
            return

    with temporary_file() as tmp:
        LOG.debug("%s was %s, converting to %s", image_id, volume_format,
                  image_meta['disk_format'])

        data = qemu_img_info(volume_path, run_as_root=run_as_root)
        backing_file = data.backing_file
        fmt = data.file_format
        if backing_file is not None:
            # Disallow backing files as a security measure.
            # This prevents a user from writing an image header into a raw
            # volume with a backing file pointing to data they wish to
            # access.
            raise exception.ImageUnacceptable(
                image_id=image_id,
                reason=_("fmt=%(fmt)s backed by:%(backing_file)s") % {
                    'fmt': fmt,
                    'backing_file': backing_file
                })

        out_format = fixup_disk_format(image_meta['disk_format'])
        convert_image(volume_path,
                      tmp,
                      out_format,
                      run_as_root=run_as_root,
                      compress=compress)

        data = qemu_img_info(tmp, run_as_root=run_as_root)
        if data.file_format != out_format:
            raise exception.ImageUnacceptable(
                image_id=image_id,
                reason=_("Converted to %(f1)s, but format is now %(f2)s") % {
                    'f1': out_format,
                    'f2': data.file_format
                })

        # NOTE(ZhengMa): This is used to do image compression on image
        # uploading with 'compressed' container_format.
        # Compress file 'tmp' in-place
        if image_meta.get('container_format') == 'compressed':
            LOG.debug("Container_format set to 'compressed', compressing "
                      "image before uploading.")
            accel = accelerator.ImageAccel(tmp, tmp)
            accel.compress_img(run_as_root=run_as_root)
        with open(tmp, 'rb') as image_file:
            image_service.update(context,
                                 image_id, {},
                                 tpool.Proxy(image_file),
                                 store_id=store_id,
                                 base_image_ref=base_image_ref)
Beispiel #38
0
    def _run_restore(self, context, backup, volume):
        orig_key_id = volume.encryption_key_id
        backup_service = self.service(context)

        properties = utils.brick_get_connector_properties()
        secure_enabled = (self.volume_rpcapi.secure_file_operations_enabled(
            context, volume))
        attach_info = self._attach_device(context, volume, properties)

        # NOTE(geguileo): Not all I/O disk operations properly do greenthread
        # context switching and may end up blocking the greenthread, so we go
        # with native threads proxy-wrapping the device file object.
        try:
            device_path = attach_info['device']['path']
            open_mode = 'rb+' if os.name == 'nt' else 'wb'
            if (isinstance(device_path, six.string_types)
                    and not os.path.isdir(device_path)):
                if secure_enabled:
                    with open(device_path, open_mode) as device_file:
                        backup_service.restore(backup, volume.id,
                                               tpool.Proxy(device_file))
                else:
                    with utils.temporary_chown(device_path):
                        with open(device_path, open_mode) as device_file:
                            backup_service.restore(backup, volume.id,
                                                   tpool.Proxy(device_file))
            # device_path is already file-like so no need to open it
            else:
                backup_service.restore(backup, volume.id,
                                       tpool.Proxy(device_path))
        except exception.BackupRestoreCancel:
            raise
        except Exception:
            LOG.exception(
                'Restoring backup %(backup_id)s to volume '
                '%(volume_id)s failed.', {
                    'backup_id': backup.id,
                    'volume_id': volume.id
                })
            raise
        finally:
            self._detach_device(context,
                                attach_info,
                                volume,
                                properties,
                                force=True)

        # Regardless of whether the restore was successful, do some
        # housekeeping to ensure the restored volume's encryption key ID is
        # unique, and any previous key ID is deleted. Start by fetching fresh
        # info on the restored volume.
        restored_volume = objects.Volume.get_by_id(context, volume.id)
        restored_key_id = restored_volume.encryption_key_id
        if restored_key_id != orig_key_id:
            LOG.info(
                'Updating encryption key ID for volume %(volume_id)s '
                'from backup %(backup_id)s.', {
                    'volume_id': volume.id,
                    'backup_id': backup.id
                })

            key_mgr = key_manager.API(CONF)
            if orig_key_id is not None:
                LOG.debug('Deleting original volume encryption key ID.')
                volume_utils.delete_encryption_key(context, key_mgr,
                                                   orig_key_id)

            if backup.encryption_key_id is None:
                # This backup predates the current code that stores the cloned
                # key ID in the backup database. Fortunately, the key ID
                # restored from the backup data _is_ a clone of the original
                # volume's key ID, so grab it.
                LOG.debug('Gleaning backup encryption key ID from metadata.')
                backup.encryption_key_id = restored_key_id
                backup.save()

            # Clone the key ID again to ensure every restored volume has
            # a unique key ID. The volume's key ID should not be the same
            # as the backup.encryption_key_id (the copy made when the backup
            # was first created).
            new_key_id = volume_utils.clone_encryption_key(
                context, key_mgr, backup.encryption_key_id)
            restored_volume.encryption_key_id = new_key_id
            restored_volume.save()
        else:
            LOG.debug(
                'Encryption key ID for volume %(volume_id)s already '
                'matches encryption key ID in backup %(backup_id)s.', {
                    'volume_id': volume.id,
                    'backup_id': backup.id
                })