def _from_db_object(cls, context, type, db_type, expected_attrs=None): if expected_attrs is None: expected_attrs = ['extra_specs', 'projects'] for name, field in type.fields.items(): if name in cls.OPTIONAL_FIELDS: continue value = db_type[name] if isinstance(field, fields.IntegerField): value = value or 0 type[name] = value # Get data from db_type object that was queried by joined query # from DB if 'extra_specs' in expected_attrs: type.extra_specs = {} specs = db_type.get('extra_specs') if specs and isinstance(specs, list): type.extra_specs = {item['key']: item['value'] for item in specs} elif specs and isinstance(specs, dict): type.extra_specs = specs if 'projects' in expected_attrs: type.projects = db_type.get('projects', []) if 'qos_specs' in expected_attrs: qos_specs = objects.QualityOfServiceSpecs(context) qos_specs._from_db_object(context, qos_specs, db_type['qos_specs']) type.qos_specs = qos_specs type._context = context type.obj_reset_changes() return type
def create(context, name, specs=None): """Creates qos_specs. :param specs: Dictionary that contains specifications for QoS Expected format of the input parameter: .. code-block:: python { 'consumer': 'front-end', 'total_iops_sec': 1000, 'total_bytes_sec': 1024000 } """ # Validate the key-value pairs in the qos spec. utils.validate_dictionary_string_length(specs) consumer = specs.get('consumer') if consumer: # If we need to modify specs, copy so we don't cause unintended # consequences for the caller specs = specs.copy() del specs['consumer'] values = dict(name=name, consumer=consumer, specs=specs) LOG.debug("Dict for qos_specs: %s", values) qos_spec = objects.QualityOfServiceSpecs(context, **values) qos_spec.create() return qos_spec
def test_save(self, qos_fake_update, qos_fake_delete): qos_dict = fake_qos.copy() qos_dict['specs']['key_to_remove1'] = 'val' qos_dict['specs']['key_to_remove2'] = 'val' qos_object = objects.QualityOfServiceSpecs._from_db_object( self.context, objects.QualityOfServiceSpecs(), qos_dict) qos_object.specs['key1'] = 'val1' qos_object.save() # No values have changed so no updates should be made self.assertFalse(qos_fake_update.called) qos_object.consumer = 'back-end' qos_object.specs['key1'] = 'val2' qos_object.specs['new_key'] = 'val3' del qos_object.specs['key_to_remove1'] del qos_object.specs['key_to_remove2'] qos_object.save() qos_fake_update.assert_called_once_with(self.context, fake.OBJECT_ID, { 'specs': { 'key1': 'val2', 'new_key': 'val3' }, 'consumer': 'back-end' }) qos_fake_delete.assert_has_calls([ mock.call(self.context, fake.OBJECT_ID, 'key_to_remove1'), mock.call(self.context, fake.OBJECT_ID, 'key_to_remove2') ], any_order=True)
def __init__(self, backend_or_vol, pool_name=None, **kwargs): # Accept backend name for convenience if isinstance(backend_or_vol, six.string_types): backend_name = backend_or_vol backend_or_vol = self._get_backend(backend_or_vol) elif isinstance(backend_or_vol, self.backend_class): backend_name = backend_or_vol.id elif isinstance(backend_or_vol, Volume): backend_name, pool = backend_or_vol._ovo.host.split('#') pool_name = pool_name or pool for key in backend_or_vol._ovo.fields: if (backend_or_vol._ovo.obj_attr_is_set(key) and key not in self._ignore_keys): kwargs.setdefault(key, getattr(backend_or_vol._ovo, key)) backend_or_vol = backend_or_vol.backend if '__ovo' not in kwargs: kwargs[CONNECTIONS_OVO_FIELD] = ( volume_cmd.objects.VolumeAttachmentList(context=self.CONTEXT)) kwargs['snapshots'] = ( volume_cmd.objects.SnapshotList(context=self.CONTEXT)) self._snapshots = [] self._connections = [] qos_specs = kwargs.pop('qos_specs', None) extra_specs = kwargs.pop('extra_specs', {}) super(Volume, self).__init__(backend_or_vol, **kwargs) self._populate_data() self.local_attach = None # If we overwrote the host, then we ignore pool_name and don't set a # default value or copy the one from the source either. if 'host' not in kwargs and '__ovo' not in kwargs: pool_name = pool_name or backend_or_vol.pool_names[0] self._ovo.host = ('%s@%s#%s' % (CONFIGURED_HOST, backend_name, pool_name)) if qos_specs or extra_specs: if qos_specs: qos_specs = cinder_objs.QualityOfServiceSpecs( id=self.id, name=self.id, consumer='back-end', specs=qos_specs) qos_specs_id = self.id else: qos_specs = qos_specs_id = None self._ovo.volume_type = cinder_objs.VolumeType( context=self.CONTEXT, is_public=True, id=self.id, name=self.id, qos_specs_id=qos_specs_id, extra_specs=extra_specs, qos_specs=qos_specs) self._ovo.volume_type_id = self.id
def test_create(self, qos_fake_create): qos_object = objects.QualityOfServiceSpecs(self.context, **fake_qos_no_id) qos_object.create() self._compare(self, fake_qos, qos_object) # Fail to create a second time self.assertRaises(exception.ObjectActionError, qos_object.create) self.assertEqual(1, len(qos_fake_create.mock_calls))
def test_lazy_loading_qos(self, get_mock, qos_get_mock): qos_get_mock.return_value = objects.QualityOfServiceSpecs( id=fake.QOS_SPEC_ID) vol_type = fake_volume.fake_db_volume_type( qos_specs_id=fake.QOS_SPEC_ID) get_mock.return_value = vol_type volume_type = objects.VolumeType.get_by_id(self.context, vol_type['id']) self._compare(self, qos_get_mock.return_value, volume_type.qos_specs) qos_get_mock.assert_called_once_with(self.context, fake.QOS_SPEC_ID)
def stub_qos_specs(id): res = dict(name='qos_specs_' + str(id)) res.update(dict(consumer='back-end')) res.update(dict(id=str(id))) specs = {"key1": "value1", "key2": "value2", "key3": "value3", "key4": "value4", "key5": "value5"} res.update(dict(specs=specs)) return objects.QualityOfServiceSpecs(**res)
def return_qos_specs_create(context, name, specs): if name == 'qos_spec_%s' % fake.ALREADY_EXISTS_ID: raise exception.QoSSpecsExists(specs_id=name) elif name == 'qos_spec_%s' % fake.ACTION_FAILED_ID: raise exception.QoSSpecsCreateFailed(name=id, qos_specs=specs) elif name == 'qos_spec_%s' % fake.INVALID_ID: raise exception.InvalidQoSSpecs(reason=name) return objects.QualityOfServiceSpecs(name=name, specs=specs, consumer='back-end', id=fake.QOS_SPEC_ID)
def test_destroy_with_vol_types(self, fake_get_vol_types, qos_fake_disassociate, qos_fake_delete): qos_object = objects.QualityOfServiceSpecs._from_db_object( self.context, objects.QualityOfServiceSpecs(), fake_qos) fake_get_vol_types.return_value = objects.VolumeTypeList( objects=[objects.VolumeType(id=fake.VOLUME_TYPE_ID)]) self.assertRaises(exception.QoSSpecsInUse, qos_object.destroy) qos_object.destroy(force=True) qos_fake_delete.assert_called_once_with(mock.ANY, fake_qos['id']) qos_fake_disassociate.assert_called_once_with(self.context, fake_qos['id'])
def test_destroy_no_vol_types(self, qos_fake_delete, fake_get_vol_types, utcnow_mock): qos_fake_delete.return_value = { 'deleted': True, 'deleted_at': utcnow_mock.return_value } qos_object = objects.QualityOfServiceSpecs._from_db_object( self.context, objects.QualityOfServiceSpecs(), fake_qos) qos_object.destroy() qos_fake_delete.assert_called_once_with(mock.ANY, fake_qos['id']) self.assertTrue(qos_object.deleted) self.assertEqual(utcnow_mock.return_value.replace(tzinfo=pytz.UTC), qos_object.deleted_at)
def create(context, name, specs=None): """Creates qos_specs. :param specs dictionary that contains specifications for QoS e.g. {'consumer': 'front-end', 'total_iops_sec': 1000, 'total_bytes_sec': 1024000} """ consumer = specs.get('consumer') if consumer: # If we need to modify specs, copy so we don't cause unintended # consequences for the caller specs = specs.copy() del specs['consumer'] values = dict(name=name, consumer=consumer, specs=specs) LOG.debug("Dict for qos_specs: %s", values) qos_spec = objects.QualityOfServiceSpecs(context, **values) qos_spec.create() return qos_spec
def _from_db_object(cls, context, type, db_type, expected_attrs=None): if expected_attrs is None: expected_attrs = ['extra_specs', 'projects'] for name, field in type.fields.items(): if name in cls.OPTIONAL_FIELDS: continue value = db_type[name] if isinstance(field, fields.IntegerField): value = value or 0 type[name] = value # Get data from db_type object that was queried by joined query # from DB if 'extra_specs' in expected_attrs: type.extra_specs = {} specs = db_type.get('extra_specs') if specs and isinstance(specs, list): type.extra_specs = { item['key']: item['value'] for item in specs } elif specs and isinstance(specs, dict): type.extra_specs = specs if 'projects' in expected_attrs: # NOTE(geguileo): Until projects stops being a polymorphic value we # have to do a conversion here for VolumeTypeProjects ORM instance # lists. projects = db_type.get('projects', []) if projects and not isinstance(projects[0], str): projects = [p.project_id for p in projects] type.projects = projects if 'qos_specs' in expected_attrs: qos_specs = objects.QualityOfServiceSpecs(context) qos_specs._from_db_object(context, qos_specs, db_type['qos_specs']) type.qos_specs = qos_specs type._context = context type.obj_reset_changes() return type