示例#1
0
    def test_retype_volume_different_backend(self):
        ctxt = self.context
        loc = 'GPFSDriver:%s:testpath' % self.driver._cluster_id
        cap = {'location_info': loc}
        host = {'host': 'foo', 'capabilities': cap}

        key_specs_old = {'capabilities:storage_pool': 'bronze',
                         'volume_backend_name': 'backend1'}
        key_specs_new = {'capabilities:storage_pool': 'gold',
                         'volume_backend_name': 'backend2'}

        old_type_ref = volume_types.create(ctxt, 'old', key_specs_old)
        new_type_ref = volume_types.create(ctxt, 'new', key_specs_new)

        old_type = volume_types.get_volume_type(ctxt, old_type_ref['id'])
        new_type = volume_types.get_volume_type(ctxt, new_type_ref['id'])

        diff, equal = volume_types.volume_types_diff(ctxt,
                                                     old_type_ref['id'],
                                                     new_type_ref['id'])
        # set volume host to match target host
        volume = test_utils.create_volume(ctxt, host=host['host'])
        volume['volume_type_id'] = old_type['id']

        with mock.patch('cinder.utils.execute'):
            LOG.debug('Retype different backends, cannot migrate. '
                      'Expected rv = False.')
            self.driver.create_volume(volume)
            rv = self.driver.retype(ctxt, volume, old_type, diff, host)
            self.assertFalse(rv)
            self.driver.delete_volume(volume)
            LOG.debug('Retype different backends, cannot migrate, '
                      'rv = %s.' % rv)
示例#2
0
    def test_retype(self):
        """Test that retype returns successfully."""

        self.driver.do_setup(None)

        # prepare parameters
        ctxt = context.get_admin_context()

        host = {"host": "foo", "capabilities": {"location_info": "xiv_ds8k_fake_1", "extent_size": "1024"}}

        key_specs_old = {"easytier": False, "warning": 2, "autoexpand": True}
        key_specs_new = {"easytier": True, "warning": 5, "autoexpand": False}
        old_type_ref = volume_types.create(ctxt, "old", key_specs_old)
        new_type_ref = volume_types.create(ctxt, "new", key_specs_new)

        diff, equal = volume_types.volume_types_diff(ctxt, old_type_ref["id"], new_type_ref["id"])

        volume = copy.deepcopy(VOLUME)
        old_type = volume_types.get_volume_type(ctxt, old_type_ref["id"])
        volume["volume_type"] = old_type
        volume["host"] = host
        new_type = volume_types.get_volume_type(ctxt, new_type_ref["id"])

        self.driver.create_volume(volume)
        ret = self.driver.retype(ctxt, volume, new_type, diff, host)
        self.assertTrue(ret)
        self.assertTrue(volume["easytier"])
示例#3
0
    def test_retype_with_no_LH_extra_specs(self):
        # setup drive with default configuration
        # and return the mock HTTP LeftHand client
        mock_client = self.setup_driver()

        ctxt = context.get_admin_context()

        host = {'host': self.serverName}
        key_specs_old = {'foo': False, 'bar': 2, 'error': True}
        key_specs_new = {'foo': True, 'bar': 5, 'error': False}
        old_type_ref = volume_types.create(ctxt, 'old', key_specs_old)
        new_type_ref = volume_types.create(ctxt, 'new', key_specs_new)

        diff, equal = volume_types.volume_types_diff(ctxt, old_type_ref['id'],
                                                     new_type_ref['id'])

        volume = dict.copy(self.volume)
        old_type = volume_types.get_volume_type(ctxt, old_type_ref['id'])
        volume['volume_type'] = old_type
        volume['host'] = host
        new_type = volume_types.get_volume_type(ctxt, new_type_ref['id'])

        self.driver.retype(ctxt, volume, new_type, diff, host)

        expected = self.driver_startup_call_stack + [
            mock.call.getVolumeByName('fakevolume')]

        # validate call chain
        mock_client.assert_has_calls(expected)
示例#4
0
    def test_retype_same_extra_specs(self):
        # setup drive with default configuration
        # and return the mock HTTP LeftHand client
        mock_client = self.setup_driver()
        mock_client.getVolumeByName.return_value = {'id': self.volume_id}

        ctxt = context.get_admin_context()

        host = {'host': self.serverName}
        key_specs_old = {'hplh:provisioning': 'full', 'hplh:ao': 'true'}
        key_specs_new = {'hplh:provisioning': 'full', 'hplh:ao': 'false'}
        old_type_ref = volume_types.create(ctxt, 'old', key_specs_old)
        new_type_ref = volume_types.create(ctxt, 'new', key_specs_new)

        diff, equal = volume_types.volume_types_diff(ctxt, old_type_ref['id'],
                                                     new_type_ref['id'])

        volume = dict.copy(self.volume)
        old_type = volume_types.get_volume_type(ctxt, old_type_ref['id'])
        volume['volume_type'] = old_type
        volume['host'] = host
        new_type = volume_types.get_volume_type(ctxt, new_type_ref['id'])

        self.driver.retype(ctxt, volume, new_type, diff, host)

        expected = self.driver_startup_call_stack + [
            mock.call.getVolumeByName('fakevolume'),
            mock.call.modifyVolume(
                1,
                {'isAdaptiveOptimizationEnabled': False})]

        # validate call chain
        mock_client.assert_has_calls(expected)
示例#5
0
    def _update(self, req, id, body):
        # Update description for a given volume type.
        context = req.environ["cinder.context"]
        authorize(context)

        if not self.is_valid_body(body, "volume_type"):
            raise webob.exc.HTTPBadRequest()

        vol_type = body["volume_type"]
        description = vol_type.get("description", None)

        if description is None:
            msg = _("Specify the description to update.")
            raise webob.exc.HTTPBadRequest(explanation=msg)

        try:
            # check it exists
            vol_type = volume_types.get_volume_type(context, id)
            volume_types.update(context, id, description)
            # get the updated
            vol_type = volume_types.get_volume_type(context, id)
            req.cache_resource(vol_type, name="types")
            self._notify_volume_type_info(context, "volume_type.update", vol_type)

        except exception.VolumeTypeNotFound as err:
            self._notify_volume_type_error(context, "volume_type.update", err, id=id)
            raise webob.exc.HTTPNotFound(explanation=six.text_type(err))
        except exception.VolumeTypeExists as err:
            self._notify_volume_type_error(context, "volume_type.update", err, volume_type=vol_type)
            raise webob.exc.HTTPConflict(explanation=six.text_type(err))
        except exception.VolumeTypeUpdateFailed as err:
            self._notify_volume_type_error(context, "volume_type.update", err, volume_type=vol_type)
            raise webob.exc.HTTPInternalServerError(explanation=six.text_type(err))

        return self._view_builder.show(req, vol_type)
示例#6
0
    def test_retype_volume_different_pool_and_host(self):
        ctxt = self.context
        loc = 'GPFSDriver:%s:testpath' % self.driver._cluster_id
        cap = {'location_info': loc}
        host = {'host': 'foo', 'capabilities': cap}

        key_specs_old = {'capabilities:storage_pool': 'bronze',
                         'volume_backend_name': 'backend1'}
        key_specs_new = {'capabilities:storage_pool': 'gold',
                         'volume_backend_name': 'backend1'}
        old_type_ref = volume_types.create(ctxt, 'old', key_specs_old)
        new_type_ref = volume_types.create(ctxt, 'new', key_specs_new)

        old_type = volume_types.get_volume_type(ctxt, old_type_ref['id'])
        new_type = volume_types.get_volume_type(ctxt, new_type_ref['id'])

        diff, equal = volume_types.volume_types_diff(ctxt,
                                                     old_type_ref['id'],
                                                     new_type_ref['id'])

        # set volume host to be different from target host
        volume = test_utils.create_volume(ctxt, host=CONF.host)
        volume['volume_type_id'] = old_type['id']

        with mock.patch('cinder.utils.execute'):
            # different host different pool
            LOG.debug('Retype different pools and hosts, expected rv = True.')
            self.driver.db = mock.Mock()
            self.driver.create_volume(volume)
            rv = self.driver.retype(ctxt, volume, new_type, diff, host)
            self.assertTrue(rv)
            self.driver.delete_volume(volume)
            LOG.debug('Retype different pools and hosts, rv = %s.' % rv)
 def testGetVolumeTypeExtraSpec_NoOverridePrefixInExtraSpecKey(self):
     volume = {'volume_type_id': 1}
     volume_type = {'extra_specs': {'test_key': 'test_value'}}
     self.m.StubOutWithMock(context, 'get_admin_context')
     self.m.StubOutWithMock(volume_types, 'get_volume_type')
     context.get_admin_context().AndReturn(None)
     volume_types.get_volume_type(None, 1).AndReturn(volume_type)
     self.m.ReplayAll()
     result = self.driver._get_volume_type_extra_spec(volume, 'test_key')
     self.assertEqual(result, 'test_value')
     self.m.VerifyAll()
示例#8
0
文件: api.py 项目: akutz/cinder
    def migrate_volume(self, context, volume, host, force_host_copy):
        """Migrate the volume to the specified host."""

        # We only handle "available" volumes for now
        if volume['status'] != "available":
            msg = _("status must be available")
            LOG.error(msg)
            raise exception.InvalidVolume(reason=msg)

        # We only handle volumes without snapshots for now
        snaps = self.db.snapshot_get_all_for_volume(context, volume['id'])
        if snaps:
            msg = _("volume must not have snapshots")
            LOG.error(msg)
            raise exception.InvalidVolume(reason=msg)

        # Make sure the host is in the list of available hosts
        elevated = context.elevated()
        topic = CONF.volume_topic
        services = self.db.service_get_all_by_topic(elevated, topic)
        found = False
        for service in services:
            if utils.service_is_up(service) and service['host'] == host:
                found = True
        if not found:
            msg = (_('No available service named %s') % host)
            LOG.error(msg)
            raise exception.InvalidHost(reason=msg)

        # Make sure the destination host is different than the current one
        if host == volume['host']:
            msg = _('Destination host must be different than current host')
            LOG.error(msg)
            raise exception.InvalidHost(reason=msg)

        self.update(context, volume, {'status': 'migrating'})

        # Call the scheduler to ensure that the host exists and that it can
        # accept the volume
        volume_type = {}
        if volume['volume_type_id']:
            volume_types.get_volume_type(context, volume['volume_type_id'])
        request_spec = {'volume_properties': volume,
                        'volume_type': volume_type,
                        'volume_id': volume['id']}
        self.scheduler_rpcapi.migrate_volume_to_host(context,
                                                     CONF.volume_topic,
                                                     volume['id'],
                                                     host,
                                                     force_host_copy,
                                                     request_spec)
示例#9
0
    def _delete(self, req, id):
        """Deletes an existing volume type."""
        context = req.environ['cinder.context']
        authorize(context)

        try:
            vol_type = volume_types.get_volume_type(context, id)
            volume_types.destroy(context, vol_type['id'])
            notifier_info = dict(volume_types=vol_type)
            notifier_api.notify(context, 'volumeType',
                                'volume_type.delete',
                                notifier_api.INFO, notifier_info)
        except exception.VolumeTypeInUse as err:
            notifier_err = dict(id=id, error_message=str(err))
            self._notify_voloume_type_error(context,
                                            'volume_type.delete',
                                            notifier_err)
            msg = 'Target volume type is still in use.'
            raise webob.exc.HTTPBadRequest(explanation=msg)
        except exception.NotFound as err:
            notifier_err = dict(id=id, error_message=str(err))
            self._notify_voloume_type_error(context,
                                            'volume_type.delete',
                                            notifier_err)

            raise webob.exc.HTTPNotFound()

        return webob.Response(status_int=202)
示例#10
0
    def get_vdisk_params(self, config, state, type_id, volume_type=None,
                         volume_metadata=None):
        """Return the parameters for creating the vdisk.

        Takes volume type and defaults from config options into account.
        """
        opts = self.build_default_opts(config)
        ctxt = context.get_admin_context()
        if volume_type is None and type_id is not None:
            volume_type = volume_types.get_volume_type(ctxt, type_id)
        if volume_type:
            qos_specs_id = volume_type.get('qos_specs_id')
            specs = dict(volume_type).get('extra_specs')

            # NOTE(vhou): We prefer the qos_specs association
            # and over-ride any existing
            # extra-specs settings if present
            if qos_specs_id is not None:
                kvs = qos_specs.get_qos_specs(ctxt, qos_specs_id)['specs']
                # Merge the qos_specs into extra_specs and qos_specs has higher
                # priority than extra_specs if they have different values for
                # the same key.
                specs.update(kvs)
            opts = self._get_opts_from_specs(opts, specs)
        if (opts['qos'] is None and config.storwize_svc_allow_tenant_qos
                and volume_metadata):
            qos = self._get_qos_from_volume_metadata(volume_metadata)
            if len(qos) != 0:
                opts['qos'] = qos

        self.check_vdisk_opts(state, opts)
        return opts
    def _get_volume_type_extra_spec(self, volume, spec_key):
        """
        Code adapted from examples in
        cinder/volume/drivers/solidfire.py and
        cinder/openstack/common/scheduler/filters/capabilities_filter.py.
        """
        spec_value = None
        ctxt = context.get_admin_context()
        typeid = volume['volume_type_id']
        if typeid:
            volume_type = volume_types.get_volume_type(ctxt, typeid)
            volume_specs = volume_type.get('extra_specs')
            for key, val in volume_specs.iteritems():

                # Havana release altered extra_specs to require a
                # prefix on all non-host-capability related extra
                # specs, so that prefix is dropped here before
                # checking the key.
                #
                if ':' in key:
                    scope = key.split(':')

                if scope[1] == spec_key:
                    spec_value = val
                    break

        return spec_value
示例#12
0
    def test_volume_type_get_by_id_and_name(self):
        """Ensure volume types get returns same entry."""
        volume_types.create(self.ctxt, self.vol_type1_name, self.vol_type1_specs)
        new = volume_types.get_volume_type_by_name(self.ctxt, self.vol_type1_name)

        new2 = volume_types.get_volume_type(self.ctxt, new["id"])
        self.assertEqual(new, new2)
示例#13
0
    def _update(self, req, id, body):
        # Update description for a given volume type.
        context = req.environ['cinder.context']
        authorize(context)

        self.assert_valid_body(body, 'volume_type')

        vol_type = body['volume_type']
        description = vol_type.get('description')
        name = vol_type.get('name')
        is_public = vol_type.get('is_public')

        # Name and description can not be both None.
        # If name specified, name can not be empty.
        if name and len(name.strip()) == 0:
            msg = _("Volume type name can not be empty.")
            raise webob.exc.HTTPBadRequest(explanation=msg)

        if name is None and description is None and is_public is None:
            msg = _("Specify volume type name, description, is_public or "
                    "a combination thereof.")
            raise webob.exc.HTTPBadRequest(explanation=msg)

        if is_public is not None and not utils.is_valid_boolstr(is_public):
            msg = _("Invalid value '%s' for is_public. Accepted values: "
                    "True or False.") % is_public
            raise webob.exc.HTTPBadRequest(explanation=msg)

        if name:
            utils.check_string_length(name, 'Type name',
                                      min_length=1, max_length=255)

        if description is not None:
            utils.check_string_length(description, 'Type description',
                                      min_length=0, max_length=255)

        try:
            volume_types.update(context, id, name, description,
                                is_public=is_public)
            # Get the updated
            vol_type = volume_types.get_volume_type(context, id)
            req.cache_resource(vol_type, name='types')
            self._notify_volume_type_info(
                context, 'volume_type.update', vol_type)

        except exception.VolumeTypeNotFound as err:
            self._notify_volume_type_error(
                context, 'volume_type.update', err, id=id)
            raise webob.exc.HTTPNotFound(explanation=six.text_type(err))
        except exception.VolumeTypeExists as err:
            self._notify_volume_type_error(
                context, 'volume_type.update', err, volume_type=vol_type)
            raise webob.exc.HTTPConflict(explanation=six.text_type(err))
        except exception.VolumeTypeUpdateFailed as err:
            self._notify_volume_type_error(
                context, 'volume_type.update', err, volume_type=vol_type)
            raise webob.exc.HTTPInternalServerError(
                explanation=six.text_type(err))

        return self._view_builder.show(req, vol_type)
示例#14
0
文件: api.py 项目: apporc/cinder
    def _create_cg_from_source_cg(self, context, group, source_cg):
        try:
            source_vols = self.db.volume_get_all_by_group(context,
                                                          source_cg.id)

            if not source_vols:
                msg = _("Source CG is empty. No consistency group "
                        "will be created.")
                raise exception.InvalidConsistencyGroup(reason=msg)

            for source_vol in source_vols:
                kwargs = {}
                kwargs['availability_zone'] = group.availability_zone
                kwargs['source_cg'] = source_cg
                kwargs['consistencygroup'] = group
                kwargs['source_volume'] = source_vol
                volume_type_id = source_vol.get('volume_type_id')
                if volume_type_id:
                    kwargs['volume_type'] = volume_types.get_volume_type(
                        context, volume_type_id)

                # Since source_cg is passed in, the following call will
                # create a db entry for the volume, but will not call the
                # volume manager to create a real volume in the backend yet.
                # If error happens, taskflow will handle rollback of quota
                # and removal of volume entry in the db.
                try:
                    self.volume_api.create(context,
                                           source_vol['size'],
                                           None,
                                           None,
                                           **kwargs)
                except exception.CinderException:
                    with excutils.save_and_reraise_exception():
                        LOG.error(_LE("Error occurred when creating cloned "
                                      "volume in the process of creating "
                                      "consistency group %(group)s from "
                                      "source CG %(source_cg)s."),
                                  {'group': group.id,
                                   'source_cg': source_cg.id})
        except Exception:
            with excutils.save_and_reraise_exception():
                try:
                    group.destroy()
                finally:
                    LOG.error(_LE("Error occurred when creating consistency "
                                  "group %(group)s from source CG "
                                  "%(source_cg)s."),
                              {'group': group.id,
                               'source_cg': source_cg.id})

        volumes = self.db.volume_get_all_by_group(context,
                                                  group.id)
        for vol in volumes:
            # Update the host field for the volume.
            self.db.volume_update(context, vol['id'],
                                  {'host': group.host})

        self.volume_rpcapi.create_consistencygroup_from_src(context, group,
                                                            None, source_cg)
示例#15
0
def get_volume_type_from_volume(volume):
    """Provides volume type associated with volume."""
    type_id = volume.get('volume_type_id')
    if type_id is None:
        return {}
    ctxt = context.get_admin_context()
    return volume_types.get_volume_type(ctxt, type_id)
示例#16
0
    def _get_qos_by_volume_type(self, ctxt, type_id):
        """Get the properties which can be QoS or file system related."""

        update_qos_group_params = {}
        update_file_system_params = {}

        volume_type = volume_types.get_volume_type(ctxt, type_id)
        qos_specs_id = volume_type.get('qos_specs_id')
        extra_specs = volume_type.get('extra_specs')

        if qos_specs_id is not None:
            specs = qos_specs.get_qos_specs(ctxt, qos_specs_id)['specs']

            # Override extra specs with specs
            # Hence specs will prefer QoS than extra specs
            extra_specs.update(specs)

        for key, value in extra_specs.items():
            if ':' in key:
                fields = key.split(':')
                key = fields[1]

            if key in self.configuration.cb_update_qos_group:
                update_qos_group_params[key] = value

            elif key in self.configuration.cb_update_file_system:
                update_file_system_params[key] = value

        return update_qos_group_params, update_file_system_params
示例#17
0
    def migrate_volume(self, ctxt, volume, host):
        """Migrate directly if source and dest are managed by same storage.

        We create a new vdisk copy in the desired pool, and add the original
        vdisk copy to the admin_metadata of the volume to be deleted. The
        deletion will occur using a periodic task once the new copy is synced.

        :param ctxt: Context
        :param volume: A dictionary describing the volume to migrate
        :param host: A dictionary describing the host to migrate to, where
                     host['host'] is its name, and host['capabilities'] is a
                     dictionary of its reported capabilities.
        """
        LOG.debug('enter: migrate_volume: id=%(id)s, host=%(host)s' %
                  {'id': volume['id'], 'host': host['host']})

        false_ret = (False, None)
        dest_pool = self._helpers.can_migrate_to_host(host, self._state)
        if dest_pool is None:
            return false_ret

        ctxt = context.get_admin_context()
        if volume['volume_type_id'] is not None:
            volume_type_id = volume['volume_type_id']
            vol_type = volume_types.get_volume_type(ctxt, volume_type_id)
        else:
            vol_type = None

        self._check_volume_copy_ops()
        new_op = self.add_vdisk_copy(volume['name'], dest_pool, vol_type)
        self._add_vdisk_copy_op(ctxt, volume, new_op)
        LOG.debug('leave: migrate_volume: id=%(id)s, host=%(host)s' %
                  {'id': volume['id'], 'host': host['host']})
        return (True, None)
示例#18
0
文件: api.py 项目: apporc/cinder
    def _create_cg_from_cgsnapshot(self, context, group, cgsnapshot):
        try:
            snapshots = objects.SnapshotList.get_all_for_cgsnapshot(
                context, cgsnapshot.id)

            if not snapshots:
                msg = _("Cgsnahost is empty. No consistency group "
                        "will be created.")
                raise exception.InvalidConsistencyGroup(reason=msg)

            for snapshot in snapshots:
                kwargs = {}
                kwargs['availability_zone'] = group.availability_zone
                kwargs['cgsnapshot'] = cgsnapshot
                kwargs['consistencygroup'] = group
                kwargs['snapshot'] = snapshot
                volume_type_id = snapshot.volume_type_id
                if volume_type_id:
                    kwargs['volume_type'] = volume_types.get_volume_type(
                        context, volume_type_id)

                # Since cgsnapshot is passed in, the following call will
                # create a db entry for the volume, but will not call the
                # volume manager to create a real volume in the backend yet.
                # If error happens, taskflow will handle rollback of quota
                # and removal of volume entry in the db.
                try:
                    self.volume_api.create(context,
                                           snapshot.volume_size,
                                           None,
                                           None,
                                           **kwargs)
                except exception.CinderException:
                    with excutils.save_and_reraise_exception():
                        LOG.error(_LE("Error occurred when creating volume "
                                      "entry from snapshot in the process of "
                                      "creating consistency group %(group)s "
                                      "from cgsnapshot %(cgsnap)s."),
                                  {'group': group.id,
                                   'cgsnap': cgsnapshot.id})
        except Exception:
            with excutils.save_and_reraise_exception():
                try:
                    group.destroy()
                finally:
                    LOG.error(_LE("Error occurred when creating consistency "
                                  "group %(group)s from cgsnapshot "
                                  "%(cgsnap)s."),
                              {'group': group.id,
                               'cgsnap': cgsnapshot.id})

        volumes = self.db.volume_get_all_by_group(context,
                                                  group.id)
        for vol in volumes:
            # Update the host field for the volume.
            self.db.volume_update(context, vol['id'],
                                  {'host': group.get('host')})

        self.volume_rpcapi.create_consistencygroup_from_src(
            context, group, cgsnapshot)
    def _get_violin_extra_spec(self, volume, spec_key):
        """Parse data stored in a volume_type's extra_specs table.
           and extract the value of the specified violin key.

        Code adapted from examples in
        cinder/volume/drivers/solidfire.py and
        cinder/openstack/common/scheduler/filters/capabilities_filter.py.

        Arguments:
            volume   -- volume object containing volume_type to query
            spec_key -- the metadata key to search for

        Returns:
            spec_value -- string value associated with spec_key
        """
        spec_value = None
        ctxt = context.get_admin_context()
        typeid = volume['volume_type_id']
        if typeid:
            volume_type = volume_types.get_volume_type(ctxt, typeid)
            volume_specs = volume_type.get('extra_specs')
            for key, val in volume_specs.iteritems():

                # Strip the prefix "violin"
                if ':' in key:
                    scope = key.split(':')
                    key = scope[1]
                    if scope[0] == "violin" and key == spec_key:
                        spec_value = val
                        break
        return spec_value
示例#20
0
    def _migrate_volume(self, volume, host, new_type=None):
        if not self._check_migration_valid(host, volume):
            return (False, None)

        type_id = volume['volume_type_id']

        volume_type = None
        if type_id:
            volume_type = volume_types.get_volume_type(None, type_id)

        pool_name = host['capabilities']['pool_name']
        pools = self.restclient.find_all_pools()
        pool_info = self.restclient.find_pool_info(pool_name, pools)
        src_volume_name = huawei_utils.encode_name(volume['id'])
        dst_volume_name = six.text_type(hash(src_volume_name))
        src_id = volume.get('provider_location', None)

        src_lun_params = self.restclient.get_lun_info(src_id)

        opts = None
        qos = None
        if new_type:
            # If new type exists, use new type.
            opts = huawei_utils._get_extra_spec_value(
                new_type['extra_specs'])
            opts = smartx.SmartX().get_smartx_specs_opts(opts)
            if 'LUNType' not in opts:
                opts['LUNType'] = huawei_utils.find_luntype_in_xml(
                    self.xml_file_path)

            qos = huawei_utils.get_qos_by_volume_type(new_type)
        elif volume_type:
            qos = huawei_utils.get_qos_by_volume_type(volume_type)

        if not opts:
            opts = huawei_utils.get_volume_params(volume)
            opts = smartx.SmartX().get_smartx_specs_opts(opts)

        lun_info = self._create_lun_with_extra_feature(pool_info,
                                                       dst_volume_name,
                                                       src_lun_params,
                                                       opts)
        lun_id = lun_info['ID']

        if qos:
            LOG.info(_LI('QoS: %s.'), qos)
            SmartQos = smartx.SmartQos(self.restclient)
            SmartQos.create_qos(qos, lun_id)
        if opts:
            smartpartition = smartx.SmartPartition(self.restclient)
            smartpartition.add(opts, lun_id)
            smartcache = smartx.SmartCache(self.restclient)
            smartcache.add(opts, lun_id)

        dst_id = lun_info['ID']
        self._wait_volume_ready(dst_id)
        moved = self._migrate_lun(src_id, dst_id)

        return moved, {}
示例#21
0
 def _set_qos_by_volume_type(self, ctxt, type_id):
     qos = {}
     volume_type = volume_types.get_volume_type(ctxt, type_id)
     specs = volume_type.get('extra_specs')
     for key, value in specs.iteritems():
         if key in self.sf_qos_keys:
             qos[key] = int(value)
     return qos
示例#22
0
def _fake_volume_type(*args, **kwargs):
    ctxt = context.get_admin_context()
    type_ref = volume_types.create(ctxt, "qos_extra_specs", {})
    qos_ref = qos_specs.create(ctxt, 'qos-specs', {})
    qos_specs.associate_qos_with_type(ctxt, qos_ref['id'],
                                      type_ref['id'])
    qos_type = volume_types.get_volume_type(ctxt, type_ref['id'])
    return qos_type
示例#23
0
文件: netapp.py 项目: jdurgin/cinder
 def _get_ss_type(self, volume):
     """Get the storage service type for a volume."""
     id = volume['volume_type_id']
     if not id:
         return None
     volume_type = volume_types.get_volume_type(None, id)
     if not volume_type:
         return None
     return volume_type['name']
示例#24
0
文件: types.py 项目: C2python/cinder
    def show(self, req, id):
        """Return a single volume type item."""
        context = req.environ['cinder.context']

        # Not found exception will be handled at the wsgi level
        vol_type = volume_types.get_volume_type(context, id)
        req.cache_resource(vol_type, name='types')

        return self._view_builder.show(req, vol_type)
示例#25
0
文件: utils.py 项目: JamesBai/cinder
def get_volume_extra_specs(volume):
    """Provides extra specs associated with volume."""
    ctxt = context.get_admin_context()
    type_id = volume.get('volume_type_id')
    specs = None
    if type_id is not None:
        volume_type = volume_types.get_volume_type(ctxt, type_id)
        specs = volume_type.get('extra_specs')
    return specs
示例#26
0
 def _get_volume_extra_specs(self, volume):
     """Get extra specs from a volume."""
     extra_specs = {}
     type_id = volume.get('volume_type_id', None)
     if type_id is not None:
         ctxt = context.get_admin_context()
         volume_type = volume_types.get_volume_type(ctxt, type_id)
         extra_specs = volume_type.get('extra_specs')
     return extra_specs
示例#27
0
 def _get_qos_type(self, volume):
     """Get the storage service type for a volume."""
     type_id = volume["volume_type_id"]
     if not type_id:
         return None
     volume_type = volume_types.get_volume_type(None, type_id)
     if not volume_type:
         return None
     return volume_type["name"]
示例#28
0
    def create_replica(self, ctxt, volume):
        conf = self.driver.configuration
        vol_type = volume['volume_type_id']
        vol_type = volume_types.get_volume_type(ctxt, vol_type)
        dest_pool = conf.storwize_svc_stretched_cluster_partner

        self.driver.add_vdisk_copy(volume['name'], dest_pool, vol_type)
        vol_update = {'replication_status': 'copying'}
        return vol_update
示例#29
0
 def _update_volume_info_from_volume_type(self, volume_info, volume_type_id):
     if not volume_type_id:
         return
     else:
         volume_type = volume_types.get_volume_type(context.get_admin_context(), volume_type_id)
         extra_specs = volume_type.get("extra_specs")
         self._update_volume_info_from_extra_specs(volume_info, extra_specs)
         qos_specs = volume_types.get_volume_type_qos_specs(volume_type_id)
         self._update_volume_info_from_qos_specs(volume_info, qos_specs)
示例#30
0
def get_volume_qos(volume):
    qos = {}
    ctxt = context.get_admin_context()
    type_id = volume['volume_type_id']
    if type_id is not None:
        volume_type = volume_types.get_volume_type(ctxt, type_id)
        qos = get_qos_by_volume_type(volume_type)

    return qos
示例#31
0
    def test_volume_type_create_then_destroy_with_non_admin(self):
        """Ensure volume types can be created and deleted by non-admin user.

        If a non-admn user is authorized at API, volume type operations
        should be permitted.
        """
        prev_all_vtypes = volume_types.get_all_types(self.ctxt)
        self.ctxt = context.RequestContext('fake', 'fake', is_admin=False)

        # create
        type_ref = volume_types.create(self.ctxt,
                                       self.vol_type1_name,
                                       self.vol_type1_specs,
                                       description=self.vol_type1_description)
        new = volume_types.get_volume_type_by_name(self.ctxt,
                                                   self.vol_type1_name)
        self.assertEqual(self.vol_type1_description, new['description'])
        new_all_vtypes = volume_types.get_all_types(self.ctxt)
        self.assertEqual(len(prev_all_vtypes) + 1,
                         len(new_all_vtypes),
                         'drive type was not created')

        # update
        new_type_name = self.vol_type1_name + '_updated'
        new_type_desc = self.vol_type1_description + '_updated'
        volume_types.update(self.ctxt, type_ref.id, new_type_name,
                            new_type_desc)
        type_ref_updated = volume_types.get_volume_type(self.ctxt, type_ref.id)
        self.assertEqual(new_type_name, type_ref_updated['name'])
        self.assertEqual(new_type_desc, type_ref_updated['description'])

        # destroy
        volume_types.destroy(self.ctxt, type_ref['id'])
        new_all_vtypes = volume_types.get_all_types(self.ctxt)
        self.assertEqual(prev_all_vtypes,
                         new_all_vtypes,
                         'drive type was not deleted')
示例#32
0
    def _get_volume_type_extra_spec(self, volume, spec_key):
        """Parse data stored in a volume_type's extra_specs table.

        :param volume:  volume object containing volume_type to query
        :param spec_key:  the metadata key to search for
        :returns: string value associated with spec_key
        """
        spec_value = None
        ctxt = context.get_admin_context()
        typeid = volume['volume_type_id']
        if typeid:
            volume_type = volume_types.get_volume_type(ctxt, typeid)
            volume_specs = volume_type.get('extra_specs')
            for key, val in volume_specs.items():

                # Strip the prefix "capabilities"
                if ':' in key:
                    scope = key.split(':')
                    key = scope[1]
                if key == spec_key:
                    spec_value = val
                    break

        return spec_value
示例#33
0
    def _get_volume_type_extra_spec(self, volume, spec_key):
        """
        Parse data stored in a volume_type's extra_specs table.

        Code adapted from examples in
        cinder/volume/drivers/solidfire.py and
        cinder/openstack/common/scheduler/filters/capabilities_filter.py.

        Arguments:
            volume   -- volume object containing volume_type to query
            spec_key -- the metadata key to search for

        Returns:
            spec_value -- string value associated with spec_key
        """
        spec_value = None
        ctxt = context.get_admin_context()
        typeid = volume['volume_type_id']
        if typeid:
            volume_type = volume_types.get_volume_type(ctxt, typeid)
            volume_specs = volume_type.get('extra_specs')
            for key, val in volume_specs.iteritems():

                # Havana release altered extra_specs to require a
                # prefix on all non-host-capability related extra
                # specs, so that prefix is stripped here before
                # checking the key.
                #
                if ':' in key:
                    scope = key.split(':')
                    key = scope[1]
                if key == spec_key:
                    spec_value = val
                    break

        return spec_value
示例#34
0
    def create(self, req, type_id, body=None):
        context = req.environ['cinder.context']
        authorize(context)
        self._allow_update(context, type_id)

        self.assert_valid_body(body, 'extra_specs')

        self._check_type(context, type_id)
        specs = body['extra_specs']
        self._check_key_names(specs.keys())
        utils.validate_dictionary_string_length(specs)

        db.volume_type_extra_specs_update_or_create(context,
                                                    type_id,
                                                    specs)
        # Get created_at and updated_at for notification
        volume_type = volume_types.get_volume_type(context, type_id)
        notifier_info = dict(type_id=type_id, specs=specs,
                             created_at=volume_type['created_at'],
                             updated_at=volume_type['updated_at'])
        notifier = rpc.get_notifier('volumeTypeExtraSpecs')
        notifier.info(context, 'volume_type_extra_specs.create',
                      notifier_info)
        return body
示例#35
0
    def get_vdisk_params(self,
                         config,
                         state,
                         type_id,
                         volume_type=None,
                         volume_metadata=None):
        """Return the parameters for creating the vdisk.

        Takes volume type and defaults from config options into account.
        """
        opts = self.build_default_opts(config)
        ctxt = context.get_admin_context()
        if volume_type is None and type_id is not None:
            volume_type = volume_types.get_volume_type(ctxt, type_id)
        if volume_type:
            qos_specs_id = volume_type.get('qos_specs_id')
            specs = dict(volume_type).get('extra_specs')

            # NOTE(vhou): We prefer the qos_specs association
            # and over-ride any existing
            # extra-specs settings if present
            if qos_specs_id is not None:
                kvs = qos_specs.get_qos_specs(ctxt, qos_specs_id)['specs']
                # Merge the qos_specs into extra_specs and qos_specs has higher
                # priority than extra_specs if they have different values for
                # the same key.
                specs.update(kvs)
            opts = self._get_opts_from_specs(opts, specs)
        if (opts['qos'] is None and config.storwize_svc_allow_tenant_qos
                and volume_metadata):
            qos = self._get_qos_from_volume_metadata(volume_metadata)
            if len(qos) != 0:
                opts['qos'] = qos

        self.check_vdisk_opts(state, opts)
        return opts
示例#36
0
    def update(self, req, type_id, id, body):
        context = req.environ['cinder.context']
        context.authorize(policy.UPDATE_POLICY)
        self._allow_update(context, type_id)

        self._check_type(context, type_id)
        if id not in body:
            expl = _('Request body and URI mismatch')
            raise webob.exc.HTTPBadRequest(explanation=expl)

        if 'image_service:store_id' in body:
            image_service_store_id = body['image_service:store_id']
            image_utils.validate_stores_id(context, image_service_store_id)

        db.volume_type_extra_specs_update_or_create(context, type_id, body)
        # Get created_at and updated_at for notification
        volume_type = volume_types.get_volume_type(context, type_id)
        notifier_info = dict(type_id=type_id,
                             id=id,
                             created_at=volume_type['created_at'],
                             updated_at=volume_type['updated_at'])
        notifier = rpc.get_notifier('volumeTypeExtraSpecs')
        notifier.info(context, 'volume_type_extra_specs.update', notifier_info)
        return body
示例#37
0
 def _check_type(self, context, type_id):
     try:
         volume_types.get_volume_type(context, type_id)
     except exception.NotFound as ex:
         raise webob.exc.HTTPNotFound(explanation=ex.msg)
示例#38
0
    def create(self, req, body):
        """Instruct Cinder to manage a storage object.

        Manages an existing backend storage object (e.g. a Linux logical
        volume or a SAN disk) by creating the Cinder objects required to manage
        it, and possibly renaming the backend storage object
        (driver dependent)

        From an API perspective, this operation behaves very much like a
        volume creation operation, except that properties such as image,
        snapshot and volume references don't make sense, because we are taking
        an existing storage object into Cinder management.

        Required HTTP Body:

        {
         'volume':
          {
           'host': <Cinder host on which the existing storage resides>,
           'ref':  <Driver-specific reference to the existing storage object>,
          }
        }

        See the appropriate Cinder drivers' implementations of the
        manage_volume method to find out the accepted format of 'ref'.

        This API call will return with an error if any of the above elements
        are missing from the request, or if the 'host' element refers to a
        cinder host that is not registered.

        The volume will later enter the error state if it is discovered that
        'ref' is bad.

        Optional elements to 'volume' are:
            name               A name for the new volume.
            description        A description for the new volume.
            volume_type        ID or name of a volume type to associate with
                               the new Cinder volume.  Does not necessarily
                               guarantee that the managed volume will have the
                               properties described in the volume_type.  The
                               driver may choose to fail if it identifies that
                               the specified volume_type is not compatible with
                               the backend storage object.
            metadata           Key/value pairs to be associated with the new
                               volume.
            availability_zone  The availability zone to associate with the new
                               volume.
            bootable           If set to True, marks the volume as bootable.
        """
        context = req.environ['cinder.context']
        authorize(context)

        self.assert_valid_body(body, 'volume')

        volume = body['volume']

        # Check that the required keys are present, return an error if they
        # are not.
        required_keys = set(['ref', 'host'])
        missing_keys = list(required_keys - set(volume.keys()))

        if missing_keys:
            msg = _("The following elements are required: %s") % \
                ', '.join(missing_keys)
            raise exc.HTTPBadRequest(explanation=msg)

        LOG.debug('Manage volume request body: %s', body)

        kwargs = {}
        req_volume_type = volume.get('volume_type', None)
        if req_volume_type:
            try:
                if not uuidutils.is_uuid_like(req_volume_type):
                    kwargs['volume_type'] = \
                        volume_types.get_volume_type_by_name(
                            context, req_volume_type)
                else:
                    kwargs['volume_type'] = volume_types.get_volume_type(
                        context, req_volume_type)
            except exception.VolumeTypeNotFound as error:
                raise exc.HTTPNotFound(explanation=error.msg)
        else:
            kwargs['volume_type'] = {}

        kwargs['name'] = volume.get('name', None)
        kwargs['description'] = volume.get('description', None)
        kwargs['metadata'] = volume.get('metadata', None)
        kwargs['availability_zone'] = volume.get('availability_zone', None)
        kwargs['bootable'] = volume.get('bootable', False)
        try:
            new_volume = self.volume_api.manage_existing(
                context, volume['host'], volume['ref'], **kwargs)
        except exception.ServiceNotFound:
            msg = _("Service not found.")
            raise exc.HTTPNotFound(explanation=msg)

        new_volume = dict(new_volume)
        utils.add_visible_admin_metadata(new_volume)

        return self._view_builder.detail(req, new_volume)
示例#39
0
    def _create_group_from_source_group(self, context, group, source_group_id):
        try:
            source_group = objects.Group.get_by_id(context, source_group_id)
            source_vols = objects.VolumeList.get_all_by_generic_group(
                context, source_group.id)

            if not source_vols:
                msg = _("Source Group is empty. No group " "will be created.")
                raise exception.InvalidGroup(reason=msg)

            for source_vol in source_vols:
                kwargs = {}
                kwargs['availability_zone'] = group.availability_zone
                kwargs['source_group'] = source_group
                kwargs['group'] = group
                kwargs['source_volume'] = source_vol
                volume_type_id = source_vol.volume_type_id
                if volume_type_id:
                    kwargs['volume_type'] = volume_types.get_volume_type(
                        context, volume_type_id)
                    # Create group volume_type mapping entries
                    try:
                        db.group_volume_type_mapping_create(
                            context, group.id, volume_type_id)
                    except exception.GroupVolumeTypeMappingExists:
                        # Only need to create one group volume_type mapping
                        # entry for the same combination, skipping.
                        LOG.info(
                            _LI("A mapping entry already exists for group"
                                " %(grp)s and volume type %(vol_type)s. "
                                "Do not need to create again."), {
                                    'grp': group.id,
                                    'vol_type': volume_type_id
                                })
                        pass

                # Since source_group is passed in, the following call will
                # create a db entry for the volume, but will not call the
                # volume manager to create a real volume in the backend yet.
                # If error happens, taskflow will handle rollback of quota
                # and removal of volume entry in the db.
                try:
                    self.volume_api.create(context, source_vol.size, None,
                                           None, **kwargs)
                except exception.CinderException:
                    with excutils.save_and_reraise_exception():
                        LOG.error(
                            _LE("Error occurred when creating cloned "
                                "volume in the process of creating "
                                "group %(group)s from "
                                "source group %(source_group)s."), {
                                    'group': group.id,
                                    'source_group': source_group.id
                                })
        except Exception:
            with excutils.save_and_reraise_exception():
                try:
                    group.destroy()
                finally:
                    LOG.error(
                        _LE("Error occurred when creating "
                            "group %(group)s from source group "
                            "%(source_group)s."), {
                                'group': group.id,
                                'source_group': source_group.id
                            })

        volumes = objects.VolumeList.get_all_by_generic_group(
            context, group.id)
        for vol in volumes:
            # Update the host field for the volume.
            vol.host = group.host
            vol.save()

        self.volume_rpcapi.create_group_from_src(context, group, None,
                                                 source_group)
示例#40
0
    def create(self, req, body):
        """Creates a new volume.

        :param req: the request
        :param body: the request body
        :returns: dict -- the new volume dictionary
        :raises: HTTPNotFound, HTTPBadRequest
        """
        self.assert_valid_body(body, 'volume')

        LOG.debug('Create volume request body: %s', body)
        context = req.environ['cinder.context']

        req_version = req.api_version_request
        # Remove group_id from body if max version is less than 3.13.
        if req_version.matches(None, "3.12"):
            # NOTE(xyang): The group_id is from a group created with a
            # group_type. So with this group_id, we've got a group_type
            # for this volume. Also if group_id is passed in, that means
            # we already know which backend is hosting the group and the
            # volume will be created on the same backend as well. So it
            # won't go through the scheduler again if a group_id is
            # passed in.
            try:
                body.get('volume', {}).pop('group_id', None)
            except AttributeError:
                msg = (_("Invalid body provided for creating volume. "
                         "Request API version: %s.") % req_version)
                raise exc.HTTPBadRequest(explanation=msg)

        volume = body['volume']
        kwargs = {}
        self.validate_name_and_description(volume)

        # NOTE(thingee): v2 API allows name instead of display_name
        if 'name' in volume:
            volume['display_name'] = volume.pop('name')

        # NOTE(thingee): v2 API allows description instead of
        #                display_description
        if 'description' in volume:
            volume['display_description'] = volume.pop('description')

        if 'image_id' in volume:
            volume['imageRef'] = volume.pop('image_id')

        req_volume_type = volume.get('volume_type', None)
        if req_volume_type:
            # Not found exception will be handled at the wsgi level
            if not uuidutils.is_uuid_like(req_volume_type):
                kwargs['volume_type'] = (volume_types.get_volume_type_by_name(
                    context, req_volume_type))
            else:
                kwargs['volume_type'] = volume_types.get_volume_type(
                    context, req_volume_type)

        kwargs['metadata'] = volume.get('metadata', None)

        snapshot_id = volume.get('snapshot_id')
        if snapshot_id is not None:
            # Not found exception will be handled at the wsgi level
            kwargs['snapshot'] = self.volume_api.get_snapshot(
                context, snapshot_id)
        else:
            kwargs['snapshot'] = None

        source_volid = volume.get('source_volid')
        if source_volid is not None:
            # Not found exception will be handled at the wsgi level
            kwargs['source_volume'] = (self.volume_api.get_volume(
                context, source_volid))
        else:
            kwargs['source_volume'] = None

        source_replica = volume.get('source_replica')
        if source_replica is not None:
            # Not found exception will be handled at the wsgi level
            src_vol = self.volume_api.get_volume(context, source_replica)
            if src_vol['replication_status'] == 'disabled':
                explanation = _('source volume id:%s is not'
                                ' replicated') % source_replica
                raise exc.HTTPBadRequest(explanation=explanation)
            kwargs['source_replica'] = src_vol
        else:
            kwargs['source_replica'] = None

        consistencygroup_id = volume.get('consistencygroup_id')
        if consistencygroup_id is not None:
            # Not found exception will be handled at the wsgi level
            kwargs['consistencygroup'] = (self.consistencygroup_api.get(
                context, consistencygroup_id))
        else:
            kwargs['consistencygroup'] = None

        # Get group_id if volume is in a group.
        group_id = volume.get('group_id')
        if group_id is not None:
            try:
                kwargs['group'] = self.group_api.get(context, group_id)
            except exception.GroupNotFound as error:
                raise exc.HTTPNotFound(explanation=error.msg)

        size = volume.get('size', None)
        if size is None and kwargs['snapshot'] is not None:
            size = kwargs['snapshot']['volume_size']
        elif size is None and kwargs['source_volume'] is not None:
            size = kwargs['source_volume']['size']
        elif size is None and kwargs['source_replica'] is not None:
            size = kwargs['source_replica']['size']

        LOG.info(_LI("Create volume of %s GB"), size)

        if self.ext_mgr.is_loaded('os-image-create'):
            image_ref = volume.get('imageRef')
            if image_ref is not None:
                image_uuid = self._image_uuid_from_ref(image_ref, context)
                kwargs['image_id'] = image_uuid

        kwargs['availability_zone'] = volume.get('availability_zone', None)
        kwargs['scheduler_hints'] = volume.get('scheduler_hints', None)
        multiattach = volume.get('multiattach', False)
        kwargs['multiattach'] = multiattach

        new_volume = self.volume_api.create(context, size,
                                            volume.get('display_name'),
                                            volume.get('display_description'),
                                            **kwargs)

        retval = self._view_builder.detail(req, new_volume)

        return retval
示例#41
0
    def _update(self, req, id, body):
        # Update description for a given volume type.
        context = req.environ['cinder.context']
        authorize(context)

        self.assert_valid_body(body, 'volume_type')

        vol_type = body['volume_type']
        description = vol_type.get('description')
        name = vol_type.get('name')
        is_public = vol_type.get('is_public')

        # Name and description can not be both None.
        # If name specified, name can not be empty.
        if name and len(name.strip()) == 0:
            msg = _("Volume type name can not be empty.")
            raise webob.exc.HTTPBadRequest(explanation=msg)

        if name is None and description is None and is_public is None:
            msg = _("Specify volume type name, description, is_public or "
                    "a combination thereof.")
            raise webob.exc.HTTPBadRequest(explanation=msg)

        if is_public is not None and not strutils.is_valid_boolstr(is_public):
            msg = _("Invalid value '%s' for is_public. Accepted values: "
                    "True or False.") % is_public
            raise webob.exc.HTTPBadRequest(explanation=msg)

        if name:
            utils.check_string_length(name, 'Type name',
                                      min_length=1, max_length=255)

        if description is not None:
            utils.check_string_length(description, 'Type description',
                                      min_length=0, max_length=255)

        try:
            volume_types.update(context, id, name, description,
                                is_public=is_public)
            # Get the updated
            vol_type = volume_types.get_volume_type(context, id)
            req.cache_resource(vol_type, name='types')
            self._notify_volume_type_info(
                context, 'volume_type.update', vol_type)

        except exception.VolumeTypeNotFound as err:
            self._notify_volume_type_error(
                context, 'volume_type.update', err, id=id)
            # Not found exception will be handled at the wsgi level
            raise
        except exception.VolumeTypeExists as err:
            self._notify_volume_type_error(
                context, 'volume_type.update', err, volume_type=vol_type)
            raise webob.exc.HTTPConflict(explanation=six.text_type(err))
        except exception.VolumeTypeUpdateFailed as err:
            self._notify_volume_type_error(
                context, 'volume_type.update', err, volume_type=vol_type)
            raise webob.exc.HTTPInternalServerError(
                explanation=six.text_type(err))

        return self._view_builder.show(req, vol_type)
示例#42
0
    def _create_cg_from_cgsnapshot(self, context, group, cgsnapshot):
        try:
            snapshots = objects.SnapshotList.get_all_for_cgsnapshot(
                context, cgsnapshot['id'])

            if not snapshots:
                msg = _("Cgsnahost is empty. No consistency group "
                        "will be created.")
                raise exception.InvalidConsistencyGroup(reason=msg)

            for snapshot in snapshots:
                kwargs = {}
                kwargs['availability_zone'] = group.get('availability_zone')
                kwargs['cgsnapshot'] = cgsnapshot
                kwargs['consistencygroup'] = group
                kwargs['snapshot'] = snapshot
                volume_type_id = snapshot.get('volume_type_id')
                if volume_type_id:
                    kwargs['volume_type'] = volume_types.get_volume_type(
                        context, volume_type_id)

                # Since cgsnapshot is passed in, the following call will
                # create a db entry for the volume, but will not call the
                # volume manager to create a real volume in the backend yet.
                # If error happens, taskflow will handle rollback of quota
                # and removal of volume entry in the db.
                try:
                    self.volume_api.create(context, snapshot['volume_size'],
                                           None, None, **kwargs)
                except exception.CinderException:
                    with excutils.save_and_reraise_exception():
                        LOG.error(
                            _LE("Error occurred when creating volume "
                                "entry from snapshot in the process of "
                                "creating consistency group %(group)s "
                                "from cgsnapshot %(cgsnap)s."), {
                                    'group': group['id'],
                                    'cgsnap': cgsnapshot['id']
                                })
        except Exception:
            with excutils.save_and_reraise_exception():
                try:
                    self.db.consistencygroup_destroy(context.elevated(),
                                                     group['id'])
                finally:
                    LOG.error(
                        _LE("Error occurred when creating consistency "
                            "group %(group)s from cgsnapshot "
                            "%(cgsnap)s."), {
                                'group': group['id'],
                                'cgsnap': cgsnapshot['id']
                            })

        volumes = self.db.volume_get_all_by_group(context, group['id'])
        for vol in volumes:
            # Update the host field for the volume.
            self.db.volume_update(context, vol['id'],
                                  {'host': group.get('host')})

        self.volume_rpcapi.create_consistencygroup_from_src(
            context, group, group['host'], cgsnapshot)
示例#43
0
    def retype(self, context, volume, new_type, migration_policy=None):
        """Attempt to modify the type associated with an existing volume."""
        if volume['status'] not in ['available', 'in-use']:
            msg = _('Unable to update type due to incorrect status '
                    'on volume: %s') % volume['id']
            LOG.error(msg)
            raise exception.InvalidVolume(reason=msg)

        if volume['migration_status'] is not None:
            msg = (_("Volume %s is already part of an active migration.") %
                   volume['id'])
            LOG.error(msg)
            raise exception.InvalidVolume(reason=msg)

        if migration_policy and migration_policy not in ['on-demand', 'never']:
            msg = _('migration_policy must be \'on-demand\' or \'never\', '
                    'passed: %s') % new_type
            LOG.error(msg)
            raise exception.InvalidInput(reason=msg)

        # Support specifying volume type by ID or name
        try:
            if uuidutils.is_uuid_like(new_type):
                vol_type = volume_types.get_volume_type(context, new_type)
            else:
                vol_type = volume_types.get_volume_type_by_name(
                    context, new_type)
        except exception.InvalidVolumeType:
            msg = _('Invalid volume_type passed: %s') % new_type
            LOG.error(msg)
            raise exception.InvalidInput(reason=msg)

        vol_type_id = vol_type['id']
        vol_type_qos_id = vol_type['qos_specs_id']

        old_vol_type = None
        old_vol_type_id = volume['volume_type_id']
        old_vol_type_qos_id = None

        # Error if the original and new type are the same
        if volume['volume_type_id'] == vol_type_id:
            msg = (_('New volume_type same as original: %s') % new_type)
            LOG.error(msg)
            raise exception.InvalidInput(reason=msg)

        if volume['volume_type_id']:
            old_vol_type = volume_types.get_volume_type(
                context, old_vol_type_id)
            old_vol_type_qos_id = old_vol_type['qos_specs_id']

        # We don't support changing encryption requirements yet
        old_enc = volume_types.get_volume_type_encryption(
            context, old_vol_type_id)
        new_enc = volume_types.get_volume_type_encryption(context, vol_type_id)
        if old_enc != new_enc:
            msg = _('Retype cannot change encryption requirements')
            raise exception.InvalidInput(reason=msg)

        # We don't support changing QoS at the front-end yet for in-use volumes
        # TODO(avishay): Call Nova to change QoS setting (libvirt has support
        # - virDomainSetBlockIoTune() - Nova does not have support yet).
        if (volume['status'] != 'available'
                and old_vol_type_qos_id != vol_type_qos_id):
            for qos_id in [old_vol_type_qos_id, vol_type_qos_id]:
                if qos_id:
                    specs = qos_specs.get_qos_specs(context.elevated(), qos_id)
                    if specs['qos_specs']['consumer'] != 'back-end':
                        msg = _('Retype cannot change front-end qos specs for '
                                'in-use volumes')
                        raise exception.InvalidInput(reason=msg)

        # We're checking here in so that we can report any quota issues as
        # early as possible, but won't commit until we change the type. We
        # pass the reservations onward in case we need to roll back.
        reservations = quota_utils.get_volume_type_reservation(
            context, volume, vol_type_id)

        self.update(context, volume, {'status': 'retyping'})

        request_spec = {
            'volume_properties': volume,
            'volume_id': volume['id'],
            'volume_type': vol_type,
            'migration_policy': migration_policy,
            'quota_reservations': reservations
        }

        self.scheduler_rpcapi.retype(context,
                                     CONF.volume_topic,
                                     volume['id'],
                                     request_spec=request_spec,
                                     filter_properties={})
示例#44
0
    def create(self, req, body):
        """Creates a new volume."""
        if not self.is_valid_body(body, 'volume'):
            raise exc.HTTPBadRequest()

        LOG.debug('Create volume request body: %s', body)
        context = req.environ['cinder.context']
        volume = body['volume']

        kwargs = {}

        # NOTE(thingee): v2 API allows name instead of display_name
        if volume.get('name'):
            volume['display_name'] = volume.get('name')
            del volume['name']

        # NOTE(thingee): v2 API allows description instead of description
        if volume.get('description'):
            volume['display_description'] = volume.get('description')
            del volume['description']

        req_volume_type = volume.get('volume_type', None)
        if req_volume_type:
            try:
                kwargs['volume_type'] = volume_types.get_volume_type(
                    context, req_volume_type)
            except exception.VolumeTypeNotFound:
                explanation = 'Volume type not found.'
                raise exc.HTTPNotFound(explanation=explanation)

        kwargs['metadata'] = volume.get('metadata', None)

        snapshot_id = volume.get('snapshot_id')
        if snapshot_id is not None:
            kwargs['snapshot'] = self.volume_api.get_snapshot(
                context, snapshot_id)
        else:
            kwargs['snapshot'] = None

        source_volid = volume.get('source_volid')
        if source_volid is not None:
            kwargs['source_volume'] = self.volume_api.get_volume(
                context, source_volid)
        else:
            kwargs['source_volume'] = None

        size = volume.get('size', None)
        if size is None and kwargs['snapshot'] is not None:
            size = kwargs['snapshot']['volume_size']
        elif size is None and kwargs['source_volume'] is not None:
            size = kwargs['source_volume']['size']

        LOG.audit(_("Create volume of %s GB"), size, context=context)

        image_href = None
        image_uuid = None
        if self.ext_mgr.is_loaded('os-image-create'):
            image_href = volume.get('imageRef')
            if image_href:
                image_uuid = self._image_uuid_from_href(image_href)
                kwargs['image_id'] = image_uuid

        kwargs['availability_zone'] = volume.get('availability_zone', None)
        kwargs['scheduler_hints'] = volume.get('scheduler_hints', None)

        new_volume = self.volume_api.create(context, size,
                                            volume.get('display_name'),
                                            volume.get('display_description'),
                                            **kwargs)

        # TODO(vish): Instance should be None at db layer instead of
        #             trying to lazy load, but for now we turn it into
        #             a dict to avoid an error.
        retval = self._view_builder.summary(req, dict(new_volume.iteritems()))

        return retval
示例#45
0
def _get_volume_type(volume):
    if volume.volume_type:
        return volume.volume_type
    if volume.volume_type_id:
        return volume_types.get_volume_type(None, volume.volume_type_id)
示例#46
0
    def _update(self, req, id, body):
        # Update description for a given volume type.
        context = req.environ['cinder.context']
        authorize(context)

        if not self.is_valid_body(body, 'volume_type'):
            raise webob.exc.HTTPBadRequest()

        vol_type = body['volume_type']
        description = vol_type.get('description')
        name = vol_type.get('name')

        # Name and description can not be both None.
        # If name specified, name can not be empty.
        if name and len(name.strip()) == 0:
            msg = _("Volume type name can not be empty.")
            raise webob.exc.HTTPBadRequest(explanation=msg)

        if name is None and description is None:
            msg = _("Specify either volume type name and/or description.")
            raise webob.exc.HTTPBadRequest(explanation=msg)

        if name:
            utils.check_string_length(name,
                                      'Type name',
                                      min_length=1,
                                      max_length=255)

        if description is not None:
            utils.check_string_length(description,
                                      'Type description',
                                      min_length=0,
                                      max_length=255)

        try:
            volume_types.update(context, id, name, description)
            # Get the updated
            vol_type = volume_types.get_volume_type(context, id)
            req.cache_resource(vol_type, name='types')
            self._notify_volume_type_info(context, 'volume_type.update',
                                          vol_type)

        except exception.VolumeTypeNotFound as err:
            self._notify_volume_type_error(context,
                                           'volume_type.update',
                                           err,
                                           id=id)
            raise webob.exc.HTTPNotFound(explanation=six.text_type(err))
        except exception.VolumeTypeExists as err:
            self._notify_volume_type_error(context,
                                           'volume_type.update',
                                           err,
                                           volume_type=vol_type)
            raise webob.exc.HTTPConflict(explanation=six.text_type(err))
        except exception.VolumeTypeUpdateFailed as err:
            self._notify_volume_type_error(context,
                                           'volume_type.update',
                                           err,
                                           volume_type=vol_type)
            raise webob.exc.HTTPInternalServerError(
                explanation=six.text_type(err))

        return self._view_builder.show(req, vol_type)
示例#47
0
    def _clone_image_2_2(self, context, volume, image_location, image_meta,
                         image_service):
        # We're not going to fast image clone if the feature is not enabled
        # and/or we can't reach the image being requested
        if (not self.image_cache
                or not self._image_accessible(context, volume, image_meta)):
            return None, False
        # Check to make sure we're working with a valid volume type
        try:
            found = volume_types.get_volume_type(context, self.image_type)
        except (exception.VolumeTypeNotFound, exception.InvalidVolumeType):
            found = None
        if not found:
            msg = "Invalid volume type: %s"
            LOG.error(msg, self.image_type)
            raise ValueError(
                _("Option datera_image_cache_volume_type_id must"
                  " be set to a valid volume_type id"))
        # Check image format
        fmt = image_meta.get('disk_format', '')
        if fmt.lower() != 'raw':
            LOG.debug(
                "Image format is not RAW, image requires conversion "
                "before clone.  Image format: [%s]", fmt)
            return None, False

        LOG.debug("Starting fast image clone")
        # TODO(_alastor_): determine if Datera is already an image backend
        # for this request and direct clone instead of caching

        # Dummy volume, untracked by Cinder
        src_vol = {
            'id': image_meta['id'],
            'volume_type_id': self.image_type,
            'size': volume['size'],
            'project_id': volume['project_id']
        }

        # Determine if we have a cached version of the image
        cached = self._vol_exists_2_2(src_vol)

        if cached:
            tenant = self.get_tenant(src_vol['project_id'])
            ai = self.cvol_to_ai(src_vol, tenant=tenant)
            metadata = ai.metadata.get(tenant=tenant)
            # Check to see if the master image has changed since we created
            # The cached version
            ts = self._get_vol_timestamp_2_2(src_vol)
            mts = time.mktime(image_meta['updated_at'].timetuple())
            LOG.debug("Original image timestamp: %s, cache timestamp %s", mts,
                      ts)
            # If the image is created by Glance, we'll trust that even if the
            # timestamps don't match up, the data is ok to clone as it's not
            # managed by this driver
            if metadata.get('type') == 'image':
                LOG.debug("Found Glance volume-backed image for %s",
                          src_vol['id'])
            # If the master image time is greater than the volume creation
            # time, we invalidate the cache and delete the volume.  The
            # exception is if the cached volume was created by Glance.  We
            # NEVER want to delete this volume.  It's annotated with
            # 'type': 'image' in the metadata, so we'll check for that
            elif mts > ts and metadata.get('type') != 'image':
                LOG.debug("Cache is older than original image, deleting cache")
                cached = False
                self._delete_volume_2_2(src_vol)

        # If we don't have the image, we'll cache it
        if not cached:
            LOG.debug("No image cache found for: %s, caching image",
                      image_meta['id'])
            self._cache_vol_2_2(context, src_vol, image_meta, image_service)

        # Now perform the clone of the found image or newly cached image
        self._create_cloned_volume_2_2(volume, src_vol)
        # Force volume resize
        vol_size = volume['size']
        volume['size'] = 0
        self._extend_volume_2_2(volume, vol_size)
        volume['size'] = vol_size
        # Determine if we need to retype the newly created volume
        vtype_id = volume.get('volume_type_id')
        if vtype_id and self.image_type and vtype_id != self.image_type:
            vtype = volume_types.get_volume_type(context, vtype_id)
            LOG.debug("Retyping newly cloned volume from type: %s to type: %s",
                      self.image_type, vtype_id)
            diff, discard = volume_types.volume_types_diff(
                context, self.image_type, vtype_id)
            host = {'capabilities': {'vendor_name': self.backend_name}}
            self._retype_2_2(context, volume, vtype, diff, host)
        return None, True
示例#48
0
    def create(self, req, body):
        """Creates a new volume."""
        if not self.is_valid_body(body, 'volume'):
            raise exc.HTTPUnprocessableEntity()

        LOG.debug('Create volume request body: %s', body)
        context = req.environ['cinder.context']
        volume = body['volume']

        kwargs = {}

        req_volume_type = volume.get('volume_type', None)
        if req_volume_type:
            try:
                if not uuidutils.is_uuid_like(req_volume_type):
                    kwargs['volume_type'] = \
                        volume_types.get_volume_type_by_name(
                            context, req_volume_type)
                else:
                    kwargs['volume_type'] = volume_types.get_volume_type(
                        context, req_volume_type)
            except exception.VolumeTypeNotFound:
                explanation = 'Volume type not found.'
                raise exc.HTTPNotFound(explanation=explanation)

        kwargs['metadata'] = volume.get('metadata', None)

        snapshot_id = volume.get('snapshot_id')
        if snapshot_id is not None:
            kwargs['snapshot'] = self.volume_api.get_snapshot(context,
                                                              snapshot_id)
        else:
            kwargs['snapshot'] = None

        source_volid = volume.get('source_volid')
        if source_volid is not None:
            kwargs['source_volume'] = self.volume_api.get_volume(context,
                                                                 source_volid)
        else:
            kwargs['source_volume'] = None

        size = volume.get('size', None)
        if size is None and kwargs['snapshot'] is not None:
            size = kwargs['snapshot']['volume_size']
        elif size is None and kwargs['source_volume'] is not None:
            size = kwargs['source_volume']['size']

        LOG.audit(_("Create volume of %s GB"), size, context=context)

        image_href = None
        image_uuid = None
        if self.ext_mgr.is_loaded('os-image-create'):
            # NOTE(jdg): misleading name "imageRef" as it's an image-id
            image_href = volume.get('imageRef')
            if image_href:
                image_uuid = self._image_uuid_from_href(image_href)
                kwargs['image_id'] = image_uuid

        kwargs['availability_zone'] = volume.get('availability_zone', None)

        new_volume = self.volume_api.create(context,
                                            size,
                                            volume.get('display_name'),
                                            volume.get('display_description'),
                                            **kwargs)

        # TODO(vish): Instance should be None at db layer instead of
        #             trying to lazy load, but for now we turn it into
        #             a dict to avoid an error.
        new_volume = dict(new_volume.iteritems())

        self._add_visible_admin_metadata(context, new_volume)

        retval = _translate_volume_detail_view(context, new_volume, image_uuid)

        return {'volume': retval}
示例#49
0
    def _create_cg_from_source_cg(self, context, group, source_cgid):
        try:
            source_cg = objects.ConsistencyGroup.get_by_id(
                context, source_cgid)
            source_vols = self.db.volume_get_all_by_group(
                context, source_cg.id)

            if not source_vols:
                msg = _("Source CG is empty. No consistency group "
                        "will be created.")
                raise exception.InvalidConsistencyGroup(reason=msg)

            for source_vol in source_vols:
                kwargs = {}
                kwargs['availability_zone'] = group.availability_zone
                kwargs['source_cg'] = source_cg
                kwargs['consistencygroup'] = group
                kwargs['source_volume'] = source_vol
                volume_type_id = source_vol.get('volume_type_id')
                if volume_type_id:
                    kwargs['volume_type'] = volume_types.get_volume_type(
                        context, volume_type_id)

                # Since source_cg is passed in, the following call will
                # create a db entry for the volume, but will not call the
                # volume manager to create a real volume in the backend yet.
                # If error happens, taskflow will handle rollback of quota
                # and removal of volume entry in the db.
                try:
                    self.volume_api.create(context, source_vol['size'], None,
                                           None, **kwargs)
                except exception.CinderException:
                    with excutils.save_and_reraise_exception():
                        LOG.error(
                            _LE("Error occurred when creating cloned "
                                "volume in the process of creating "
                                "consistency group %(group)s from "
                                "source CG %(source_cg)s."), {
                                    'group': group.id,
                                    'source_cg': source_cg.id
                                })
        except Exception:
            with excutils.save_and_reraise_exception():
                try:
                    group.destroy()
                finally:
                    LOG.error(
                        _LE("Error occurred when creating consistency "
                            "group %(group)s from source CG "
                            "%(source_cg)s."), {
                                'group': group.id,
                                'source_cg': source_cg.id
                            })

        volumes = self.db.volume_get_all_by_group(context, group.id)
        for vol in volumes:
            # Update the host field for the volume.
            self.db.volume_update(context, vol['id'], {'host': group.host})

        self.volume_rpcapi.create_consistencygroup_from_src(
            context, group, None, source_cg)
示例#50
0
    def create(self, req, body):
        """Creates a new volume."""
        self.assert_valid_body(body, 'volume')

        LOG.debug('Create volume request body: %s', body)
        context = req.environ['cinder.context']
        volume = body['volume']

        kwargs = {}

        # NOTE(thingee): v2 API allows name instead of display_name
        if volume.get('name'):
            volume['display_name'] = volume.get('name')
            del volume['name']

        # NOTE(thingee): v2 API allows description instead of
        #                display_description
        if volume.get('description'):
            volume['display_description'] = volume.get('description')
            del volume['description']

        if 'image_id' in volume:
            volume['imageRef'] = volume.get('image_id')
            del volume['image_id']

        req_volume_type = volume.get('volume_type', None)
        if req_volume_type:
            try:
                if not uuidutils.is_uuid_like(req_volume_type):
                    kwargs['volume_type'] = \
                        volume_types.get_volume_type_by_name(
                            context, req_volume_type)
                else:
                    kwargs['volume_type'] = volume_types.get_volume_type(
                        context, req_volume_type)
            except exception.VolumeTypeNotFound as error:
                raise exc.HTTPNotFound(explanation=error.msg)

        kwargs['metadata'] = volume.get('metadata', None)

        snapshot_id = volume.get('snapshot_id')
        if snapshot_id is not None:
            try:
                kwargs['snapshot'] = self.volume_api.get_snapshot(context,
                                                                  snapshot_id)
            except exception.SnapshotNotFound as error:
                raise exc.HTTPNotFound(explanation=error.msg)
        else:
            kwargs['snapshot'] = None

        source_volid = volume.get('source_volid')
        if source_volid is not None:
            try:
                kwargs['source_volume'] = \
                    self.volume_api.get_volume(context,
                                               source_volid)
            except exception.VolumeNotFound as error:
                raise exc.HTTPNotFound(explanation=error.msg)
        else:
            kwargs['source_volume'] = None

        source_replica = volume.get('source_replica')
        if source_replica is not None:
            try:
                src_vol = self.volume_api.get_volume(context,
                                                     source_replica)
                if src_vol['replication_status'] == 'disabled':
                    explanation = _('source volume id:%s is not'
                                    ' replicated') % source_volid
                    raise exc.HTTPBadRequest(explanation=explanation)
                kwargs['source_replica'] = src_vol
            except exception.VolumeNotFound as error:
                raise exc.HTTPNotFound(explanation=error.msg)
        else:
            kwargs['source_replica'] = None

        consistencygroup_id = volume.get('consistencygroup_id')
        if consistencygroup_id is not None:
            try:
                kwargs['consistencygroup'] = \
                    self.consistencygroup_api.get(context,
                                                  consistencygroup_id)
            except exception.ConsistencyGroupNotFound as error:
                raise exc.HTTPNotFound(explanation=error.msg)
        else:
            kwargs['consistencygroup'] = None

        size = volume.get('size', None)
        if size is None and kwargs['snapshot'] is not None:
            size = kwargs['snapshot']['volume_size']
        elif size is None and kwargs['source_volume'] is not None:
            size = kwargs['source_volume']['size']
        elif size is None and kwargs['source_replica'] is not None:
            size = kwargs['source_replica']['size']

        LOG.info(_LI("Create volume of %s GB"), size, context=context)

        if self.ext_mgr.is_loaded('os-image-create'):
            image_ref = volume.get('imageRef')
            if image_ref is not None:
                image_uuid = self._image_uuid_from_ref(image_ref, context)
                kwargs['image_id'] = image_uuid

        kwargs['availability_zone'] = volume.get('availability_zone', None)
        kwargs['scheduler_hints'] = volume.get('scheduler_hints', None)
        multiattach = volume.get('multiattach', False)
        kwargs['multiattach'] = multiattach

        new_volume = self.volume_api.create(context,
                                            size,
                                            volume.get('display_name'),
                                            volume.get('display_description'),
                                            **kwargs)

        # TODO(vish): Instance should be None at db layer instead of
        #             trying to lazy load, but for now we turn it into
        #             a dict to avoid an error.
        new_volume = dict(new_volume)
        retval = self._view_builder.detail(req, new_volume)

        return retval
示例#51
0
 def _check_type(self, context, type_id):
     # Not found exception will be handled at the wsgi level
     volume_types.get_volume_type(context, type_id)
示例#52
0
    def create(self, req, body):
        """Creates a new volume."""
        self.assert_valid_body(body, 'volume')

        LOG.debug('Create volume request body: %s', body)
        context = req.environ['cinder.context']
        volume = body['volume']

        kwargs = {}
        self.validate_name_and_description(volume)

        # NOTE(thingee): v2 API allows name instead of display_name
        if 'name' in volume:
            volume['display_name'] = volume.pop('name')

        # NOTE(thingee): v2 API allows description instead of
        #                display_description
        if 'description' in volume:
            volume['display_description'] = volume.pop('description')

        if 'image_id' in volume:
            volume['imageRef'] = volume.pop('image_id')

        req_volume_type = volume.get('volume_type', None)
        if req_volume_type:
            # Not found exception will be handled at the wsgi level
            if not uuidutils.is_uuid_like(req_volume_type):
                kwargs['volume_type'] = \
                    volume_types.get_volume_type_by_name(
                        context, req_volume_type)
            else:
                kwargs['volume_type'] = volume_types.get_volume_type(
                    context, req_volume_type)

        kwargs['metadata'] = volume.get('metadata', None)

        snapshot_id = volume.get('snapshot_id')
        if snapshot_id is not None:
            # Not found exception will be handled at the wsgi level
            kwargs['snapshot'] = self.volume_api.get_snapshot(
                context, snapshot_id)
        else:
            kwargs['snapshot'] = None

        source_volid = volume.get('source_volid')
        if source_volid is not None:
            # Not found exception will be handled at the wsgi level
            kwargs['source_volume'] = \
                self.volume_api.get_volume(context,
                                           source_volid)
        else:
            kwargs['source_volume'] = None

        source_replica = volume.get('source_replica')
        if source_replica is not None:
            # Not found exception will be handled at the wsgi level
            src_vol = self.volume_api.get_volume(context, source_replica)
            if src_vol['replication_status'] == 'disabled':
                explanation = _('source volume id:%s is not'
                                ' replicated') % source_replica
                raise exc.HTTPBadRequest(explanation=explanation)
            kwargs['source_replica'] = src_vol
        else:
            kwargs['source_replica'] = None

        consistencygroup_id = volume.get('consistencygroup_id')
        if consistencygroup_id is not None:
            # Not found exception will be handled at the wsgi level
            kwargs['consistencygroup'] = \
                self.consistencygroup_api.get(context,
                                              consistencygroup_id)
        else:
            kwargs['consistencygroup'] = None

        size = volume.get('size', None)
        if size is None and kwargs['snapshot'] is not None:
            size = kwargs['snapshot']['volume_size']
        elif size is None and kwargs['source_volume'] is not None:
            size = kwargs['source_volume']['size']
        elif size is None and kwargs['source_replica'] is not None:
            size = kwargs['source_replica']['size']

        LOG.info(_LI("Create volume of %s GB"), size)

        if self.ext_mgr.is_loaded('os-image-create'):
            image_ref = volume.get('imageRef')
            if image_ref is not None:
                image_uuid = self._image_uuid_from_ref(image_ref, context)
                kwargs['image_id'] = image_uuid

        kwargs['availability_zone'] = volume.get('availability_zone', None)
        kwargs['scheduler_hints'] = volume.get('scheduler_hints', None)
        multiattach = volume.get('multiattach', False)
        kwargs['multiattach'] = multiattach

        new_volume = self.volume_api.create(context, size,
                                            volume.get('display_name'),
                                            volume.get('display_description'),
                                            **kwargs)

        retval = self._view_builder.detail(req, new_volume)

        return retval
示例#53
0
    def create(self, req, body):
        """Creates a new volume."""
        if not self.is_valid_body(body, 'volume'):
            raise exc.HTTPUnprocessableEntity()

        LOG.debug('Create volume request body: %s', body)
        context = req.environ['cinder.context']
        volume = body['volume']

        kwargs = {}

        req_volume_type = volume.get('volume_type', None)
        if req_volume_type:
            try:
                if not uuidutils.is_uuid_like(req_volume_type):
                    kwargs['volume_type'] = \
                        volume_types.get_volume_type_by_name(
                            context, req_volume_type)
                else:
                    kwargs['volume_type'] = volume_types.get_volume_type(
                        context, req_volume_type)
            except exception.VolumeTypeNotFound:
                explanation = 'Volume type not found.'
                raise exc.HTTPNotFound(explanation=explanation)

        kwargs['metadata'] = volume.get('metadata', None)

        snapshot_id = volume.get('snapshot_id')
        if snapshot_id is not None:
            try:
                kwargs['snapshot'] = self.volume_api.get_snapshot(
                    context, snapshot_id)
            except exception.NotFound:
                explanation = _('snapshot id:%s not found') % snapshot_id
                raise exc.HTTPNotFound(explanation=explanation)

        else:
            kwargs['snapshot'] = None

        source_volid = volume.get('source_volid')
        if source_volid is not None:
            try:
                kwargs['source_volume'] = \
                    self.volume_api.get_volume(context,
                                               source_volid)
            except exception.NotFound:
                explanation = _('source vol id:%s not found') % source_volid
                raise exc.HTTPNotFound(explanation=explanation)
        else:
            kwargs['source_volume'] = None

        size = volume.get('size', None)
        if size is None and kwargs['snapshot'] is not None:
            size = kwargs['snapshot']['volume_size']
        elif size is None and kwargs['source_volume'] is not None:
            size = kwargs['source_volume']['size']

        LOG.info(_LI("Create volume of %s GB"), size, context=context)
        multiattach = volume.get('multiattach', False)
        kwargs['multiattach'] = multiattach

        image_href = None
        image_uuid = None
        if self.ext_mgr.is_loaded('os-image-create'):
            # NOTE(jdg): misleading name "imageRef" as it's an image-id
            image_href = volume.get('imageRef')
            if image_href is not None:
                image_uuid = self._image_uuid_from_href(image_href)
                kwargs['image_id'] = image_uuid

        kwargs['availability_zone'] = volume.get('availability_zone', None)

        new_volume = self.volume_api.create(context, size,
                                            volume.get('display_name'),
                                            volume.get('display_description'),
                                            **kwargs)

        retval = _translate_volume_detail_view(context, new_volume, image_uuid)

        return {'volume': retval}
示例#54
0
 def _get_volume_type(self, type_id):
     ctxt = context.get_admin_context()
     return volume_types.get_volume_type(ctxt, type_id)