Example #1
0
    def create_volume(self,
                      context,
                      volume_id,
                      request_spec=None,
                      filter_properties=None,
                      allow_reschedule=True,
                      snapshot_id=None,
                      image_id=None,
                      source_volid=None):
        """Creates and exports the volume."""

        flow = create_volume.get_manager_flow(
            self.db,
            self.driver,
            self.scheduler_rpcapi,
            self.host,
            volume_id,
            request_spec=request_spec,
            filter_properties=filter_properties,
            allow_reschedule=allow_reschedule,
            snapshot_id=snapshot_id,
            image_id=image_id,
            source_volid=source_volid,
            reschedule_context=context.deepcopy())

        assert flow, _('Manager volume flow not retrieved')

        flow.run(context.elevated())
        if flow.state != states.SUCCESS:
            raise exception.CinderException(
                _("Failed to successfully complete"
                  " manager volume workflow"))

        self._reset_stats()
        return volume_id
Example #2
0
    def create_volume(self, context, volume_id, request_spec=None,
                      filter_properties=None, allow_reschedule=True,
                      snapshot_id=None, image_id=None, source_volid=None):
        """Creates and exports the volume."""

        flow = create_volume.get_manager_flow(
            self.db,
            self.driver,
            self.scheduler_rpcapi,
            self.host,
            volume_id,
            request_spec=request_spec,
            filter_properties=filter_properties,
            allow_reschedule=allow_reschedule,
            snapshot_id=snapshot_id,
            image_id=image_id,
            source_volid=source_volid,
            reschedule_context=context.deepcopy())

        assert flow, _('Manager volume flow not retrieved')

        flow.run(context.elevated())
        if flow.state != states.SUCCESS:
            raise exception.CinderException(_("Failed to successfully complete"
                                              " manager volume workflow"))

        self._reset_stats()
        return volume_id
Example #3
0
    def create_volume(self, context, volume_id, request_spec=None,
                      filter_properties=None, allow_reschedule=True,
                      snapshot_id=None, image_id=None, source_volid=None):

        """Creates and exports the volume."""
        context_saved = context.deepcopy()
        context = context.elevated()
        if filter_properties is None:
            filter_properties = {}

        try:
            flow_engine = create_volume.get_manager_flow(
                context,
                self.db,
                self.driver,
                self.scheduler_rpcapi,
                self.host,
                volume_id,
                snapshot_id=snapshot_id,
                image_id=image_id,
                source_volid=source_volid,
                allow_reschedule=allow_reschedule,
                reschedule_context=context_saved,
                request_spec=request_spec,
                filter_properties=filter_properties)
        except Exception:
            LOG.exception(_("Failed to create manager volume flow"))
            raise exception.CinderException(
                _("Failed to create manager volume flow"))

        if snapshot_id is not None:
            # Make sure the snapshot is not deleted until we are done with it.
            locked_action = "%s-%s" % (snapshot_id, 'delete_snapshot')
        elif source_volid is not None:
            # Make sure the volume is not deleted until we are done with it.
            locked_action = "%s-%s" % (source_volid, 'delete_volume')
        else:
            locked_action = None

        def _run_flow():
            # This code executes create volume flow. If something goes wrong,
            # flow reverts all job that was done and reraises an exception.
            # Otherwise, all data that was generated by flow becomes available
            # in flow engine's storage.
            flow_engine.run()

        @utils.synchronized(locked_action, external=True)
        def _run_flow_locked():
            _run_flow()

        if locked_action is None:
            _run_flow()
        else:
            _run_flow_locked()

        # Fetch created volume from storage
        volume_ref = flow_engine.storage.fetch('volume')
        # Update volume stats
        self.stats['allocated_capacity_gb'] += volume_ref['size']
        return volume_ref['id']
Example #4
0
 def get(self, context, volume_id, viewable_admin_meta=False):
     old_ctxt = context.deepcopy()
     if viewable_admin_meta:
         ctxt = context.elevated()
     else:
         ctxt = context
     rv = self.db.volume_get(ctxt, volume_id)
     volume = dict(rv.iteritems())
     try:
         check_policy(old_ctxt, 'get', volume)
     except exception.PolicyNotAuthorized:
         # raise VolumeNotFound instead to make sure Cinder behaves
         # as it used to
         raise exception.VolumeNotFound(volume_id=volume_id)
     return volume
Example #5
0
 def get(self, context, volume_id, viewable_admin_meta=False):
     old_ctxt = context.deepcopy()
     if viewable_admin_meta:
         ctxt = context.elevated()
     else:
         ctxt = context
     rv = self.db.volume_get(ctxt, volume_id)
     volume = dict(rv.iteritems())
     try:
         check_policy(old_ctxt, 'get', volume)
     except exception.PolicyNotAuthorized:
         # raise VolumeNotFound instead to make sure Cinder behaves
         # as it used to
         raise exception.VolumeNotFound(volume_id=volume_id)
     return volume
Example #6
0
    def create_volume(self,
                      context,
                      volume_id,
                      request_spec=None,
                      filter_properties=None,
                      allow_reschedule=True,
                      snapshot_id=None,
                      image_id=None,
                      source_volid=None):
        """Creates and exports the volume."""
        context_saved = context.deepcopy()
        context = context.elevated()
        if filter_properties is None:
            filter_properties = {}
        volume_ref = self.db.volume_get(context, volume_id)
        self._notify_about_volume_usage(context, volume_ref, "create.start")

        # NOTE(vish): so we don't have to get volume from db again
        #             before passing it to the driver.
        volume_ref['host'] = self.host

        if volume_ref['status'] == 'migration_target_creating':
            status = 'migration_target'
        else:
            status = 'available'
        model_update = False
        image_meta = None
        cloned = False

        try:
            LOG.debug(
                _("volume %(vol_name)s: creating lv of"
                  " size %(vol_size)sG"), {
                      'vol_name': volume_ref['name'],
                      'vol_size': volume_ref['size']
                  })
            snapshot_ref = None
            sourcevol_ref = None
            image_service = None
            image_location = None
            image_meta = None

            if snapshot_id is not None:
                LOG.info(_("volume %s: creating from snapshot"),
                         volume_ref['name'])
                snapshot_ref = self.db.snapshot_get(context, snapshot_id)
            elif source_volid is not None:
                LOG.info(_("volume %s: creating from existing volume"),
                         volume_ref['name'])
                sourcevol_ref = self.db.volume_get(context, source_volid)
            elif image_id is not None:
                LOG.info(_("volume %s: creating from image"),
                         volume_ref['name'])
                # create the volume from an image
                image_service, image_id = \
                    glance.get_remote_image_service(context,
                                                    image_id)
                image_location = image_service.get_location(context, image_id)
                image_meta = image_service.show(context, image_id)
            else:
                LOG.info(_("volume %s: creating"), volume_ref['name'])

            try:
                model_update, cloned = self._create_volume(
                    context, volume_ref, snapshot_ref, sourcevol_ref,
                    image_service, image_id, image_location)
            except exception.ImageCopyFailure as ex:
                LOG.error(
                    _('Setting volume: %s status to error '
                      'after failed image copy.'), volume_ref['id'])
                self.db.volume_update(context, volume_ref['id'],
                                      {'status': 'error'})
                return
            except Exception:
                exc_info = sys.exc_info()
                # restore source volume status before reschedule
                # FIXME(zhiteng) do all the clean-up before reschedule
                if sourcevol_ref is not None:
                    self.db.volume_update(context, sourcevol_ref['id'],
                                          {'status': sourcevol_ref['status']})
                rescheduled = False
                # try to re-schedule volume:
                if allow_reschedule:
                    rescheduled = self._reschedule_or_error(
                        context_saved, volume_id, exc_info, snapshot_id,
                        image_id, request_spec, filter_properties)

                if rescheduled:
                    LOG.error(_('Unexpected Error: '), exc_info=exc_info)
                    msg = (_('Creating %(volume_id)s %(snapshot_id)s '
                             '%(image_id)s was rescheduled due to '
                             '%(reason)s') % {
                                 'volume_id': volume_id,
                                 'snapshot_id': snapshot_id,
                                 'image_id': image_id,
                                 'reason': unicode(exc_info[1])
                             })
                    raise exception.CinderException(msg)
                else:
                    # not re-scheduling
                    raise exc_info[0], exc_info[1], exc_info[2]

            if model_update:
                volume_ref = self.db.volume_update(context, volume_ref['id'],
                                                   model_update)
            if sourcevol_ref is not None:
                self.db.volume_glance_metadata_copy_from_volume_to_volume(
                    context, source_volid, volume_id)

            LOG.debug(_("volume %s: creating export"), volume_ref['name'])
            model_update = self.driver.create_export(context, volume_ref)
            if model_update:
                self.db.volume_update(context, volume_ref['id'], model_update)
        except Exception:
            with excutils.save_and_reraise_exception():
                volume_ref['status'] = 'error'
                self.db.volume_update(context, volume_ref['id'],
                                      {'status': volume_ref['status']})
                LOG.error(_("volume %s: create failed"), volume_ref['name'])
                self._notify_about_volume_usage(context, volume_ref,
                                                "create.end")

        if snapshot_id:
            # Copy any Glance metadata from the original volume
            self.db.volume_glance_metadata_copy_to_volume(
                context, volume_ref['id'], snapshot_id)

        if image_id and image_meta:
            # Copy all of the Glance image properties to the
            # volume_glance_metadata table for future reference.
            self.db.volume_glance_metadata_create(context, volume_ref['id'],
                                                  'image_id', image_id)
            name = image_meta.get('name', None)
            if name:
                self.db.volume_glance_metadata_create(context,
                                                      volume_ref['id'],
                                                      'image_name', name)
            # Save some more attributes into the volume metadata
            IMAGE_ATTRIBUTES = [
                'size', 'disk_format', 'container_format', 'checksum',
                'min_disk', 'min_ram'
            ]
            for key in IMAGE_ATTRIBUTES:
                value = image_meta.get(key, None)
                if value is not None:
                    self.db.volume_glance_metadata_create(
                        context, volume_ref['id'], key, value)
            image_properties = image_meta.get('properties', {})
            for key, value in image_properties.items():
                self.db.volume_glance_metadata_create(context,
                                                      volume_ref['id'], key,
                                                      value)

        now = timeutils.utcnow()
        volume_ref['status'] = status
        self.db.volume_update(context, volume_ref['id'], {
            'status': volume_ref['status'],
            'launched_at': now
        })
        LOG.info(_("volume %s: created successfully"), volume_ref['name'])
        self._reset_stats()

        self._notify_about_volume_usage(context, volume_ref, "create.end")
        return volume_ref['id']
Example #7
0
    def create_volume(self, context, volume_id, request_spec=None,
                      filter_properties=None, allow_reschedule=True,
                      snapshot_id=None, image_id=None, source_volid=None):
        """Creates and exports the volume."""
        context_saved = context.deepcopy()
        context = context.elevated()
        if filter_properties is None:
            filter_properties = {}
        volume_ref = self.db.volume_get(context, volume_id)
        self._notify_about_volume_usage(context, volume_ref, "create.start")

        # NOTE(vish): so we don't have to get volume from db again
        #             before passing it to the driver.
        volume_ref['host'] = self.host

        if volume_ref['status'] == 'migration_target_creating':
            status = 'migration_target'
        else:
            status = 'available'
        model_update = False
        image_meta = None
        cloned = False

        try:
            LOG.debug(_("volume %(vol_name)s: creating lv of"
                        " size %(vol_size)sG"),
                      {'vol_name': volume_ref['name'],
                       'vol_size': volume_ref['size']})
            snapshot_ref = None
            sourcevol_ref = None
            image_service = None
            image_location = None
            image_meta = None

            if snapshot_id is not None:
                LOG.info(_("volume %s: creating from snapshot"),
                         volume_ref['name'])
                snapshot_ref = self.db.snapshot_get(context, snapshot_id)
            elif source_volid is not None:
                LOG.info(_("volume %s: creating from existing volume"),
                         volume_ref['name'])
                sourcevol_ref = self.db.volume_get(context, source_volid)
            elif image_id is not None:
                LOG.info(_("volume %s: creating from image"),
                         volume_ref['name'])
                # create the volume from an image
                image_service, image_id = \
                    glance.get_remote_image_service(context,
                                                    image_id)
                image_location = image_service.get_location(context, image_id)
                image_meta = image_service.show(context, image_id)
            else:
                LOG.info(_("volume %s: creating"), volume_ref['name'])

            try:
                model_update, cloned = self._create_volume(context,
                                                           volume_ref,
                                                           snapshot_ref,
                                                           sourcevol_ref,
                                                           image_service,
                                                           image_id,
                                                           image_location)
            except exception.ImageCopyFailure as ex:
                LOG.error(_('Setting volume: %s status to error '
                            'after failed image copy.'), volume_ref['id'])
                self.db.volume_update(context,
                                      volume_ref['id'],
                                      {'status': 'error'})
                return
            except Exception:
                exc_info = sys.exc_info()
                # restore source volume status before reschedule
                # FIXME(zhiteng) do all the clean-up before reschedule
                if sourcevol_ref is not None:
                    self.db.volume_update(context, sourcevol_ref['id'],
                                          {'status': sourcevol_ref['status']})
                rescheduled = False
                # try to re-schedule volume:
                if allow_reschedule:
                    rescheduled = self._reschedule_or_error(context_saved,
                                                            volume_id,
                                                            exc_info,
                                                            snapshot_id,
                                                            image_id,
                                                            request_spec,
                                                            filter_properties)

                if rescheduled:
                    # log the original build error
                    self._log_original_error(exc_info)
                    msg = (_('Creating %(volume_id)s %(snapshot_id)s '
                             '%(image_id)s was rescheduled due to '
                             '%(reason)s')
                           % {'volume_id': volume_id,
                              'snapshot_id': snapshot_id,
                              'image_id': image_id,
                              'reason': unicode(exc_info[1])})
                    raise exception.CinderException(msg)
                else:
                    # not re-scheduling
                    raise exc_info[0], exc_info[1], exc_info[2]

            if model_update:
                volume_ref = self.db.volume_update(
                    context, volume_ref['id'], model_update)
            if sourcevol_ref is not None:
                self.db.volume_glance_metadata_copy_from_volume_to_volume(
                    context,
                    source_volid,
                    volume_id)

            LOG.debug(_("volume %s: creating export"), volume_ref['name'])
            model_update = self.driver.create_export(context, volume_ref)
            if model_update:
                self.db.volume_update(context, volume_ref['id'], model_update)
        except Exception:
            with excutils.save_and_reraise_exception():
                volume_ref['status'] = 'error'
                self.db.volume_update(context,
                                      volume_ref['id'],
                                      {'status': volume_ref['status']})
                LOG.error(_("volume %s: create failed"), volume_ref['name'])
                self._notify_about_volume_usage(context, volume_ref,
                                                "create.end")

        if snapshot_id:
            # Copy any Glance metadata from the original volume
            self.db.volume_glance_metadata_copy_to_volume(context,
                                                          volume_ref['id'],
                                                          snapshot_id)

        if image_id and image_meta:
            # Copy all of the Glance image properties to the
            # volume_glance_metadata table for future reference.
            self.db.volume_glance_metadata_create(context,
                                                  volume_ref['id'],
                                                  'image_id', image_id)
            name = image_meta.get('name', None)
            if name:
                self.db.volume_glance_metadata_create(context,
                                                      volume_ref['id'],
                                                      'image_name', name)
            # Save some more attributes into the volume metadata
            IMAGE_ATTRIBUTES = ['size', 'disk_format',
                                'container_format', 'checksum',
                                'min_disk', 'min_ram']
            for key in IMAGE_ATTRIBUTES:
                value = image_meta.get(key, None)
                if value is not None:
                    self.db.volume_glance_metadata_create(context,
                                                          volume_ref['id'],
                                                          key, value)
            image_properties = image_meta.get('properties', {})
            for key, value in image_properties.items():
                self.db.volume_glance_metadata_create(context,
                                                      volume_ref['id'],
                                                      key, value)

        now = timeutils.utcnow()
        volume_ref['status'] = status
        self.db.volume_update(context,
                              volume_ref['id'],
                              {'status': volume_ref['status'],
                               'launched_at': now})
        LOG.info(_("volume %s: created successfully"), volume_ref['name'])
        self._reset_stats()

        self._notify_about_volume_usage(context, volume_ref, "create.end")
        return volume_ref['id']
Example #8
0
    def create_volume(self,
                      context,
                      volume_id,
                      request_spec=None,
                      filter_properties=None,
                      allow_reschedule=True,
                      snapshot_id=None,
                      image_id=None,
                      source_volid=None):
        """Creates and exports the volume."""
        context_saved = context.deepcopy()
        context = context.elevated()
        if filter_properties is None:
            filter_properties = {}

        try:
            flow_engine = create_volume.get_manager_flow(
                context,
                self.db,
                self.driver,
                self.scheduler_rpcapi,
                self.host,
                volume_id,
                snapshot_id=snapshot_id,
                image_id=image_id,
                source_volid=source_volid,
                allow_reschedule=allow_reschedule,
                reschedule_context=context_saved,
                request_spec=request_spec,
                filter_properties=filter_properties)
        except Exception:
            LOG.exception(_("Failed to create manager volume flow"))
            raise exception.CinderException(
                _("Failed to create manager volume flow"))

        if snapshot_id is not None:
            # Make sure the snapshot is not deleted until we are done with it.
            locked_action = "%s-%s" % (snapshot_id, 'delete_snapshot')
        elif source_volid is not None:
            # Make sure the volume is not deleted until we are done with it.
            locked_action = "%s-%s" % (source_volid, 'delete_volume')
        else:
            locked_action = None

        def _run_flow():
            # This code executes create volume flow. If something goes wrong,
            # flow reverts all job that was done and reraises an exception.
            # Otherwise, all data that was generated by flow becomes available
            # in flow engine's storage.
            flow_engine.run()

        @utils.synchronized(locked_action, external=True)
        def _run_flow_locked():
            _run_flow()

        if locked_action is None:
            _run_flow()
        else:
            _run_flow_locked()

        # Fetch created volume from storage
        volume_ref = flow_engine.storage.fetch('volume')
        return volume_ref['id']