def disassociate_all(self, req, id): """Disassociate a qos specs from all volume types.""" context = req.environ['cinder.context'] authorize(context) LOG.debug("Disassociate qos_spec: %s from all." % id) try: qos_specs.get_qos_specs(context, id) qos_specs.disassociate_all(context, id) notifier_info = dict(id=id) notifier_api.notify(context, 'QoSSpecs', 'qos_specs.disassociate_all', notifier_api.INFO, notifier_info) except exception.QoSSpecsNotFound as err: notifier_err = dict(id=id, error_message=str(err)) self._notify_qos_specs_error(context, 'qos_specs.disassociate_all', notifier_err) raise webob.exc.HTTPNotFound(explanation=str(err)) except exception.QoSSpecsDisassociateFailed as err: notifier_err = dict(id=id, error_message=str(err)) self._notify_qos_specs_error(context, 'qos_specs.disassociate_all', notifier_err) raise webob.exc.HTTPInternalServerError(explanation=str(err)) return webob.Response(status_int=202)
def delete(self, req, id): """Deletes an existing qos specs.""" context = req.environ['cinder.context'] authorize(context) force = req.params.get('force', None) LOG.debug("Delete qos_spec: %(id)s, force: %(force)s" % {'id': id, 'force': force}) try: qos_specs.get_qos_specs(context, id) qos_specs.delete(context, id, force) notifier_info = dict(id=id) notifier_api.notify(context, 'QoSSpecs', 'qos_specs.delete', notifier_api.INFO, notifier_info) except exception.QoSSpecsNotFound as err: notifier_err = dict(id=id, error_message=str(err)) self._notify_qos_specs_error(context, 'qos_specs.delete', notifier_err) raise webob.exc.HTTPNotFound(explanation=str(err)) except exception.QoSSpecsInUse as err: notifier_err = dict(id=id, error_message=str(err)) self._notify_qos_specs_error(context, 'qos_specs.delete', notifier_err) if force: msg = _('Failed to disassociate qos specs.') raise webob.exc.HTTPInternalServerError(explanation=msg) msg = _('Qos specs still in use.') raise webob.exc.HTTPBadRequest(explanation=msg) return webob.Response(status_int=202)
def get_qos_by_volume_type(volume_type): # We prefer the qos_specs association # and override any existing extra-specs settings # if present. if not volume_type: return {} qos_specs_id = volume_type.get('qos_specs_id') if not qos_specs_id: return {} qos = {} ctxt = context.get_admin_context() consumer = qos_specs.get_qos_specs(ctxt, qos_specs_id)['consumer'] if consumer == 'front-end': return kvs = qos_specs.get_qos_specs(ctxt, qos_specs_id)['specs'] LOG.info('The QoS sepcs is: %s.', kvs) for k, v in kvs.items(): if k not in constants.QOS_SPEC_KEYS: msg = _('Invalid QoS %s specification.') % k LOG.error(msg) raise exception.InvalidInput(reason=msg) if k != 'IOType' and int(v) <= 0: msg = _('QoS config is wrong. %s must > 0.') % k LOG.error(msg) raise exception.InvalidInput(reason=msg) qos[k.upper()] = v if 'IOTYPE' not in qos or qos['IOTYPE'] not in constants.QOS_IOTYPES: msg = _('IOType value must be in %(valid)s.') % { 'valid': constants.QOS_IOTYPES } LOG.error(msg) raise exception.InvalidInput(reason=msg) if len(qos) < 2: msg = _('QoS policy must specify IOType and one of QoS specs.') LOG.error(msg) raise exception.InvalidInput(reason=msg) for upper_limit in constants.UPPER_LIMIT_KEYS: for lower_limit in constants.LOWER_LIMIT_KEYS: if upper_limit in qos and lower_limit in qos: msg = (_('QoS policy upper_limit and lower_limit ' 'conflict, QoS policy: %(qos_policy)s.') % { 'qos_policy': qos }) LOG.error(msg) raise exception.InvalidInput(reason=msg) return qos
def test_create(self): input = {"key1": "value1", "key2": "value2", "key3": "value3"} ref = qos_specs.create(self.ctxt, "FakeName", input) specs_obj = qos_specs.get_qos_specs(self.ctxt, ref["id"]) specs_obj_dic = { "consumer": specs_obj["consumer"], "id": specs_obj["id"], "name": specs_obj["name"], "specs": specs_obj["specs"], } expected = {"consumer": "back-end", "id": ref["id"], "name": "FakeName", "specs": input} self.assertDictMatch(expected, specs_obj_dic) # qos specs must have unique name self.assertRaises(exception.QoSSpecsExists, qos_specs.create, self.ctxt, "FakeName", input) # consumer must be one of: front-end, back-end, both input["consumer"] = "fake" self.assertRaises(exception.InvalidQoSSpecs, qos_specs.create, self.ctxt, "QoSName", input) del input["consumer"] self.mock_object(db, "qos_specs_create", fake_db_qos_specs_create) # able to catch DBError self.assertRaises(exception.QoSSpecsCreateFailed, qos_specs.create, self.ctxt, "FailQoSName", input)
def test_get_qos_specs(self): one_time_value = str(int(time.time())) specs = {"key1": one_time_value, "key2": "value2", "key3": "value3"} qos_id = self._create_qos_specs("Specs1", "both", specs) specs = qos_specs.get_qos_specs(self.ctxt, qos_id) self.assertEqual(one_time_value, specs["specs"]["key1"]) self.assertRaises(exception.InvalidQoSSpecs, qos_specs.get_qos_specs, self.ctxt, None)
def test_delete_keys(self): def fake_db_qos_delete_key(context, id, key): if key == "NotFound": raise exception.QoSSpecsKeyNotFound(specs_id=id, specs_key=key) else: pass value = {"foo": "Foo", "bar": "Bar", "zoo": "tiger"} name = "QoSName" consumer = "front-end" specs_id = self._create_qos_specs(name, consumer, value) qos_specs.delete_keys(self.ctxt, specs_id, ["foo", "bar"]) del value["foo"] del value["bar"] expected = {"name": name, "id": specs_id, "consumer": consumer, "specs": value} specs = qos_specs.get_qos_specs(self.ctxt, specs_id) specs_dic = {"consumer": specs["consumer"], "id": specs["id"], "name": specs["name"], "specs": specs["specs"]} self.assertDictMatch(expected, specs_dic) self.mock_object(db, "qos_specs_item_delete", fake_db_qos_delete_key) self.assertRaises(exception.InvalidQoSSpecs, qos_specs.delete_keys, self.ctxt, None, []) self.assertRaises(exception.QoSSpecsNotFound, qos_specs.delete_keys, self.ctxt, "NotFound", []) self.assertRaises(exception.QoSSpecsKeyNotFound, qos_specs.delete_keys, self.ctxt, specs_id, ["NotFound"]) self.assertRaises( exception.QoSSpecsKeyNotFound, qos_specs.delete_keys, self.ctxt, specs_id, ["foo", "bar", "NotFound"] )
def test_create(self): input = {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'} ref = qos_specs.create(self.ctxt, 'FakeName', input) specs_obj = qos_specs.get_qos_specs(self.ctxt, ref['id']) specs_obj_dic = {'consumer': specs_obj['consumer'], 'id': specs_obj['id'], 'name': specs_obj['name'], 'specs': specs_obj['specs']} expected = {'consumer': 'back-end', 'id': ref['id'], 'name': 'FakeName', 'specs': input} self.assertDictEqual(expected, specs_obj_dic) # qos specs must have unique name self.assertRaises(exception.QoSSpecsExists, qos_specs.create, self.ctxt, 'FakeName', input) # consumer must be one of: front-end, back-end, both input['consumer'] = 'fake' self.assertRaises(exception.InvalidQoSSpecs, qos_specs.create, self.ctxt, 'QoSName', input) del input['consumer'] self.mock_object(db, 'qos_specs_create', fake_db_qos_specs_create) # able to catch DBError self.assertRaises(exception.QoSSpecsCreateFailed, qos_specs.create, self.ctxt, 'FailQoSName', input)
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 associations(self, req, id): """List all associations of given qos specs.""" context = req.environ['cinder.context'] context.authorize(policy.GET_ALL_POLICY) LOG.debug("Get associations for qos_spec id: %s", id) try: spec = qos_specs.get_qos_specs(context, id) associates = qos_specs.get_associations(context, id) notifier_info = dict(id=id, created_at=spec.created_at) rpc.get_notifier('QoSSpecs').info(context, 'qos_specs.associations', notifier_info) except exception.QoSSpecsNotFound as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.associations', notifier_err) # Not found exception will be handled at the wsgi level raise except exception.CinderException as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.associations', notifier_err) raise webob.exc.HTTPInternalServerError( explanation=six.text_type(err)) return self._view_builder.associations(req, associates)
def get_qos_by_volume_type(volume_type): qos = {} qos_specs_id = volume_type.get('qos_specs_id') # We prefer the qos_specs association # and override any existing extra-specs settings # if present. if qos_specs_id is not None: kvs = qos_specs.get_qos_specs(context.get_admin_context(), qos_specs_id)['specs'] else: return qos LOG.info(_LI('The QoS sepcs is: %s.'), kvs) for key, value in kvs.items(): if key in constants.HUAWEI_VALID_KEYS: if (key.upper() != 'IOTYPE') and (int(value) <= 0): err_msg = (_('Qos config is wrong. %(key)s' ' must be set greater than 0.') % {'key': key}) LOG.error(err_msg) raise exception.VolumeBackendAPIException(data=err_msg) elif (key.upper() == 'IOTYPE') and (value not in ['0', '1', '2']): raise exception.InvalidInput( reason=(_('Illegal value specified for IOTYPE: ' 'set to either 0, 1, or 2.'))) else: qos[key.upper()] = value return qos
def test_create(self): input = {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'} ref = qos_specs.create(self.ctxt, 'FakeName', input) specs_obj = qos_specs.get_qos_specs(self.ctxt, ref['id']) specs_obj_dic = { 'consumer': specs_obj['consumer'], 'id': specs_obj['id'], 'name': specs_obj['name'], 'specs': specs_obj['specs'] } expected = { 'consumer': 'back-end', 'id': ref['id'], 'name': 'FakeName', 'specs': input } self.assertDictMatch(expected, specs_obj_dic) # qos specs must have unique name self.assertRaises(exception.QoSSpecsExists, qos_specs.create, self.ctxt, 'FakeName', input) # consumer must be one of: front-end, back-end, both input['consumer'] = 'fake' self.assertRaises(exception.InvalidQoSSpecs, qos_specs.create, self.ctxt, 'QoSName', input) del input['consumer'] self.stubs.Set(db, 'qos_specs_create', fake_db_qos_specs_create) # able to catch DBError self.assertRaises(exception.QoSSpecsCreateFailed, qos_specs.create, self.ctxt, 'FailQoSName', input)
def disassociate_all(self, req, id): """Disassociate a qos specs from all volume types.""" context = req.environ['cinder.context'] context.authorize(policy.UPDATE_POLICY) LOG.debug("Disassociate qos_spec: %s from all.", id) try: spec = qos_specs.get_qos_specs(context, id) qos_specs.disassociate_all(context, id) notifier_info = dict(id=id, created_at=spec.created_at) rpc.get_notifier('QoSSpecs').info(context, 'qos_specs.disassociate_all', notifier_info) except exception.QoSSpecsNotFound as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.disassociate_all', notifier_err) # Not found exception will be handled at the wsgi level raise except exception.QoSSpecsDisassociateFailed as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.disassociate_all', notifier_err) raise webob.exc.HTTPInternalServerError( explanation=six.text_type(err)) return webob.Response(status_int=http_client.ACCEPTED)
def test_update(self): def fake_db_update(context, specs_id, values): raise db_exc.DBError() input = {'key1': 'value1', 'consumer': 'WrongPlace'} # consumer must be one of: front-end, back-end, both self.assertRaises(exception.InvalidQoSSpecs, qos_specs.update, self.ctxt, 'fake_id', input) input['consumer'] = 'front-end' # qos specs must exists self.assertRaises(exception.QoSSpecsNotFound, qos_specs.update, self.ctxt, 'fake_id', input) specs_id = self._create_qos_specs('Name', input) qos_specs.update(self.ctxt, specs_id, { 'key1': 'newvalue1', 'key2': 'value2' }) specs = qos_specs.get_qos_specs(self.ctxt, specs_id) self.assertEqual(specs['specs']['key1'], 'newvalue1') self.assertEqual(specs['specs']['key2'], 'value2') self.stubs.Set(db, 'qos_specs_update', fake_db_update) self.assertRaises(exception.QoSSpecsUpdateFailed, qos_specs.update, self.ctxt, 'fake_id', input)
def test_create(self): input = {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'} ref = qos_specs.create(self.ctxt, 'FakeName', input) specs = qos_specs.get_qos_specs(self.ctxt, ref['id']) expected = (dict(consumer='back-end')) expected.update(dict(id=ref['id'])) expected.update(dict(name='FakeName')) del input['consumer'] expected.update(dict(specs=input)) self.assertDictMatch(expected, specs) self.stubs.Set(db, 'qos_specs_create', fake_db_qos_specs_create) # qos specs must have unique name self.assertRaises(exception.QoSSpecsExists, qos_specs.create, self.ctxt, 'DupQoSName', input) input.update({'consumer': 'FakeConsumer'}) # consumer must be one of: front-end, back-end, both self.assertRaises(exception.InvalidQoSSpecs, qos_specs.create, self.ctxt, 'QoSName', input) del input['consumer'] # able to catch DBError self.assertRaises(exception.QoSSpecsCreateFailed, qos_specs.create, self.ctxt, 'FailQoSName', input)
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
def test_create(self): input = {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'} ref = qos_specs.create(self.ctxt, 'FakeName', input) specs = qos_specs.get_qos_specs(self.ctxt, ref['id']) expected = (dict(consumer='back-end')) expected.update(dict(id=ref['id'])) expected.update(dict(name='FakeName')) del input['consumer'] expected.update(dict(specs=input)) self.assertDictMatch(specs, expected) self.stubs.Set(db, 'qos_specs_create', fake_db_qos_specs_create) # qos specs must have unique name self.assertRaises(exception.QoSSpecsExists, qos_specs.create, self.ctxt, 'DupQoSName', input) input.update({'consumer': 'FakeConsumer'}) # consumer must be one of: front-end, back-end, both self.assertRaises(exception.InvalidQoSSpecs, qos_specs.create, self.ctxt, 'QoSName', input) del input['consumer'] # able to catch DBError self.assertRaises(exception.QoSSpecsCreateFailed, qos_specs.create, self.ctxt, 'FailQoSName', input)
def test_update(self): def fake_db_update(context, specs_id, values): raise db_exc.DBError() qos = {'consumer': 'back-end', 'specs': {'key1': 'value1'}} # qos specs must exists self.assertRaises(exception.QoSSpecsNotFound, qos_specs.update, self.ctxt, 'fake_id', qos['specs']) specs_id = self._create_qos_specs('Name', qos['consumer'], qos['specs']) qos_specs.update(self.ctxt, specs_id, {'key1': 'newvalue1', 'key2': 'value2'}) specs = qos_specs.get_qos_specs(self.ctxt, specs_id) self.assertEqual('newvalue1', specs['specs']['key1']) self.assertEqual('value2', specs['specs']['key2']) # consumer must be one of: front-end, back-end, both self.assertRaises(exception.InvalidQoSSpecs, qos_specs.update, self.ctxt, specs_id, {'consumer': 'not-real'}) self.mock_object(db, 'qos_specs_update', fake_db_update) self.assertRaises(exception.QoSSpecsUpdateFailed, qos_specs.update, self.ctxt, specs_id, {'key': 'new_key'})
def get_qos_by_volume_type(volume_type): # We prefer the qos_specs association # and override any existing extra-specs settings # if present. if not volume_type: return {} qos_specs_id = volume_type.get('qos_specs_id') if not qos_specs_id: return {} qos = {} ctxt = context.get_admin_context() kvs = qos_specs.get_qos_specs(ctxt, qos_specs_id)['specs'] LOG.info(_LI('The QoS sepcs is: %s.'), kvs) for k, v in kvs.items(): if k not in constants.HUAWEI_VALID_KEYS: continue if k.upper() != 'IOTYPE' and int(v) <= 0: msg = _('QoS config is wrong. %s must > 0.') % k LOG.error(msg) raise exception.InvalidInput(reason=msg) elif k.upper() == 'IOTYPE' and v not in ['0', '1', '2']: msg = _('Illegal value specified for IOTYPE: 0, 1, or 2.') LOG.error(msg) raise exception.InvalidInput(reason=msg) else: qos[k.upper()] = v return qos
def delete_keys(self, req, id, body): """Deletes specified keys in qos specs.""" context = req.environ['cinder.context'] context.authorize(policy.DELETE_POLICY) if not (body and 'keys' in body and isinstance(body.get('keys'), list)): raise webob.exc.HTTPBadRequest() keys = body['keys'] LOG.debug("Delete_key spec: %(id)s, keys: %(keys)s", { 'id': id, 'keys': keys }) try: qos_specs.delete_keys(context, id, keys) spec = qos_specs.get_qos_specs(context, id) notifier_info = dict(id=id, created_at=spec.created_at, updated_at=spec.updated_at) rpc.get_notifier('QoSSpecs').info(context, 'qos_specs.delete_keys', notifier_info) except exception.NotFound as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.delete_keys', notifier_err) # Not found exception will be handled at the wsgi level raise return webob.Response(status_int=http_client.ACCEPTED)
def update(self, req, id, body=None): context = req.environ['cinder.context'] context.authorize(policy.UPDATE_POLICY) specs = body['qos_specs'] try: spec = qos_specs.get_qos_specs(context, id) qos_specs.update(context, id, specs) notifier_info = dict(id=id, created_at=spec.created_at, updated_at=timeutils.utcnow(), specs=specs) rpc.get_notifier('QoSSpecs').info(context, 'qos_specs.update', notifier_info) except (exception.QoSSpecsNotFound, exception.InvalidQoSSpecs) as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.update', notifier_err) # Not found exception will be handled at the wsgi level raise except exception.QoSSpecsUpdateFailed as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.update', notifier_err) raise webob.exc.HTTPInternalServerError( explanation=six.text_type(err)) return body
def delete_keys(self, req, id, body): """Deletes specified keys in qos specs.""" context = req.environ['cinder.context'] context.authorize(policy.DELETE_POLICY) keys = body['keys'] LOG.debug("Delete_key spec: %(id)s, keys: %(keys)s", {'id': id, 'keys': keys}) try: qos_specs.delete_keys(context, id, keys) spec = qos_specs.get_qos_specs(context, id) notifier_info = dict(id=id, created_at=spec.created_at, updated_at=spec.updated_at) rpc.get_notifier('QoSSpecs').info(context, 'qos_specs.delete_keys', notifier_info) except exception.NotFound as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.delete_keys', notifier_err) # Not found exception will be handled at the wsgi level raise return webob.Response(status_int=http_client.ACCEPTED)
def test_update(self): def fake_db_update(context, specs_id, values): raise db_exc.DBError() qos = {'consumer': 'back-end', 'specs': {'key1': 'value1'}} # qos specs must exists self.assertRaises(exception.QoSSpecsNotFound, qos_specs.update, self.ctxt, 'fake_id', qos) specs_id = self._create_qos_specs('Name', qos['consumer'], qos['specs']) qos_specs.update(self.ctxt, specs_id, { 'key1': 'newvalue1', 'key2': 'value2' }) specs = qos_specs.get_qos_specs(self.ctxt, specs_id) self.assertEqual('newvalue1', specs['specs']['key1']) self.assertEqual('value2', specs['specs']['key2']) # consumer must be one of: front-end, back-end, both self.assertRaises(exception.InvalidQoSSpecs, qos_specs.update, self.ctxt, specs_id, {'consumer': 'not-real'}) self.stubs.Set(db, 'qos_specs_update', fake_db_update) self.assertRaises(exception.QoSSpecsUpdateFailed, qos_specs.update, self.ctxt, specs_id, {'key': 'new_key'})
def test_update(self): def fake_db_update(context, specs_id, values): raise db_exc.DBError() input = {'key1': 'value1', 'consumer': 'WrongPlace'} # consumer must be one of: front-end, back-end, both self.assertRaises(exception.InvalidQoSSpecs, qos_specs.update, self.ctxt, 'fake_id', input) input['consumer'] = 'front-end' # qos specs must exists self.assertRaises(exception.QoSSpecsNotFound, qos_specs.update, self.ctxt, 'fake_id', input) specs_id = self._create_qos_specs('Name', input) qos_specs.update(self.ctxt, specs_id, {'key1': 'newvalue1', 'key2': 'value2'}) specs = qos_specs.get_qos_specs(self.ctxt, specs_id) self.assertEqual('newvalue1', specs['specs']['key1']) self.assertEqual('value2', specs['specs']['key2']) self.stubs.Set(db, 'qos_specs_update', fake_db_update) self.assertRaises(exception.QoSSpecsUpdateFailed, qos_specs.update, self.ctxt, 'fake_id', input)
def update(self, req, id, body=None): context = req.environ['cinder.context'] context.authorize(policy.UPDATE_POLICY) self.assert_valid_body(body, 'qos_specs') specs = body['qos_specs'] try: spec = qos_specs.get_qos_specs(context, id) qos_specs.update(context, id, specs) notifier_info = dict(id=id, created_at=spec.created_at, updated_at=timeutils.utcnow(), specs=specs) rpc.get_notifier('QoSSpecs').info(context, 'qos_specs.update', notifier_info) except (exception.QoSSpecsNotFound, exception.InvalidQoSSpecs) as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.update', notifier_err) # Not found exception will be handled at the wsgi level raise except exception.QoSSpecsUpdateFailed as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.update', notifier_err) raise webob.exc.HTTPInternalServerError( explanation=six.text_type(err)) return body
def test_get_qos_specs(self): one_time_value = str(int(time.time())) specs = {'key1': one_time_value, 'key2': 'value2', 'key3': 'value3'} qos_id = self._create_qos_specs('Specs1', 'both', specs) specs = qos_specs.get_qos_specs(self.ctxt, qos_id) self.assertEqual(one_time_value, specs['specs']['key1']) self.assertRaises(exception.InvalidQoSSpecs, qos_specs.get_qos_specs, self.ctxt, None)
def show(self, req, id): """Return a single qos spec item.""" context = req.environ['cinder.context'] authorize(context) # Not found exception will be handled at the wsgi level spec = qos_specs.get_qos_specs(context, id) return self._view_builder.detail(req, spec)
def get_qos_by_volume_type(volume_type): # We prefer the qos_specs association # and override any existing extra-specs settings # if present. if not volume_type: return {} qos_specs_id = volume_type.get('qos_specs_id') if not qos_specs_id: return {} qos = {} io_type_flag = None ctxt = context.get_admin_context() kvs = qos_specs.get_qos_specs(ctxt, qos_specs_id)['specs'] LOG.info(_LI('The QoS sepcs is: %s.'), kvs) for k, v in kvs.items(): if k not in constants.HUAWEI_VALID_KEYS: continue if k != 'IOType' and int(v) <= 0: msg = _('QoS config is wrong. %s must > 0.') % k LOG.error(msg) raise exception.InvalidInput(reason=msg) if k == 'IOType': if v not in ['0', '1', '2']: msg = _('Illegal value specified for IOTYPE: 0, 1, or 2.') LOG.error(msg) raise exception.InvalidInput(reason=msg) io_type_flag = 1 qos[k.upper()] = v else: qos[k.upper()] = v if not io_type_flag: msg = (_('QoS policy must specify for IOTYPE: 0, 1, or 2, ' 'QoS policy: %(qos_policy)s ') % {'qos_policy': qos}) LOG.error(msg) raise exception.InvalidInput(reason=msg) # QoS policy must specify for IOTYPE and another qos_specs. if len(qos) < 2: msg = (_('QoS policy must specify for IOTYPE and another ' 'qos_specs, QoS policy: %(qos_policy)s.') % {'qos_policy': qos}) LOG.error(msg) raise exception.InvalidInput(reason=msg) for upper_limit in constants.UPPER_LIMIT_KEYS: for lower_limit in constants.LOWER_LIMIT_KEYS: if upper_limit in qos and lower_limit in qos: msg = (_('QoS policy upper_limit and lower_limit ' 'conflict, QoS policy: %(qos_policy)s.') % {'qos_policy': qos}) LOG.error(msg) raise exception.InvalidInput(reason=msg) return qos
def test_get_qos_specs(self): one_time_value = str(int(time.time())) input = {'key1': one_time_value, 'key2': 'value2', 'key3': 'value3'} id = self._create_qos_specs('Specs1', input) specs = qos_specs.get_qos_specs(self.ctxt, id) self.assertEquals(specs['Specs1']['key1'], one_time_value) self.assertRaises(exception.InvalidQoSSpecs, qos_specs.get_qos_specs, self.ctxt, None)
def disassociate(self, req, id): """Disassociate a qos specs from a volume type.""" context = req.environ['cinder.context'] authorize(context) type_id = req.params.get('vol_type_id', None) if not type_id: msg = _('Volume Type id must not be None.') notifier_err = dict(id=id, error_message=msg) self._notify_qos_specs_error(context, 'qos_specs.delete', notifier_err) raise webob.exc.HTTPBadRequest(explanation=msg) LOG.debug("Disassociate qos_spec: %(id)s from type: %(type_id)s" % {'id': id, 'type_id': type_id}) try: qos_specs.get_qos_specs(context, id) qos_specs.disassociate_qos_specs(context, id, type_id) notifier_info = dict(id=id, type_id=type_id) notifier_api.notify(context, 'QoSSpecs', 'qos_specs.disassociate', notifier_api.INFO, notifier_info) except exception.VolumeTypeNotFound as err: notifier_err = dict(id=id, error_message=str(err)) self._notify_qos_specs_error(context, 'qos_specs.disassociate', notifier_err) raise webob.exc.HTTPNotFound(explanation=str(err)) except exception.QoSSpecsNotFound as err: notifier_err = dict(id=id, error_message=str(err)) self._notify_qos_specs_error(context, 'qos_specs.disassociate', notifier_err) raise webob.exc.HTTPNotFound(explanation=str(err)) except exception.QoSSpecsDisassociateFailed as err: notifier_err = dict(id=id, error_message=str(err)) self._notify_qos_specs_error(context, 'qos_specs.disassociate', notifier_err) raise webob.exc.HTTPInternalServerError(explanation=str(err)) return webob.Response(status_int=202)
def _retrieve_qos_info(self, ctxt, type_id): qosspec = {} volume_type = volume_types.get_volume_type(ctxt, type_id) qos_specs_id = volume_type.get('qos_specs_id') voltype = volume_type.get('extra_specs') if qos_specs_id is not None: qosspec = qos_specs.get_qos_specs(ctxt, qos_specs_id)['specs'] return voltype, qosspec
def show(self, req, id): """Return a single qos spec item.""" context = req.environ['cinder.context'] authorize(context) try: spec = qos_specs.get_qos_specs(context, id) except exception.NotFound: raise webob.exc.HTTPNotFound() return spec
def show(self, req, id): """Return a single qos spec item.""" context = req.environ['cinder.context'] authorize(context) try: spec = qos_specs.get_qos_specs(context, id) except exception.QoSSpecsNotFound as err: raise webob.exc.HTTPNotFound(explanation=str(err)) return self._view_builder.detail(req, spec)
def show(self, req, id): """Return a single qos spec item.""" context = req.environ["cinder.context"] authorize(context) try: spec = qos_specs.get_qos_specs(context, id) except exception.QoSSpecsNotFound as err: raise webob.exc.HTTPNotFound(explanation=str(err)) return self._view_builder.detail(req, spec)
def get_backend_qos_spec_from_volume_type(volume_type): qos_specs_id = volume_type.get('qos_specs_id') if qos_specs_id is None: return None ctxt = context.get_admin_context() qos_spec = qos_specs.get_qos_specs(ctxt, qos_specs_id) if qos_spec is None: return None consumer = qos_spec['consumer'] # Front end QoS specs are handled by libvirt and we ignore them here. if consumer not in BACKEND_QOS_CONSUMERS: return None return qos_spec['specs']
def associate(self, req, id): """Associate a qos specs with a volume type.""" context = req.environ['cinder.context'] context.authorize(policy.UPDATE_POLICY) type_id = req.params.get('vol_type_id', None) if not type_id: msg = _('Volume Type id must not be None.') notifier_err = dict(id=id, error_message=msg) self._notify_qos_specs_error(context, 'qos_specs.delete', notifier_err) raise webob.exc.HTTPBadRequest(explanation=msg) LOG.debug("Associate qos_spec: %(id)s with type: %(type_id)s", {'id': id, 'type_id': type_id}) try: spec = qos_specs.get_qos_specs(context, id) qos_specs.associate_qos_with_type(context, id, type_id) notifier_info = dict(id=id, type_id=type_id, created_at=spec.created_at) rpc.get_notifier('QoSSpecs').info(context, 'qos_specs.associate', notifier_info) except exception.NotFound as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.associate', notifier_err) # Not found exception will be handled at the wsgi level raise except exception.InvalidVolumeType as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.associate', notifier_err) self._notify_qos_specs_error(context, 'qos_specs.associate', notifier_err) raise webob.exc.HTTPBadRequest(explanation=six.text_type(err)) except exception.QoSSpecsAssociateFailed as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.associate', notifier_err) raise webob.exc.HTTPInternalServerError( explanation=six.text_type(err)) return webob.Response(status_int=http_client.ACCEPTED)
def get_backend_qos_spec_from_volume_type(volume_type): qos_specs_id = volume_type.get('qos_specs_id') if qos_specs_id is None: return None ctxt = context.get_admin_context() qos_spec = qos_specs.get_qos_specs(ctxt, qos_specs_id) if qos_spec is None: return None consumer = qos_spec['consumer'] # Front end QoS specs are handled by libvirt and we ignore them here. if consumer not in BACKEND_QOS_CONSUMERS: return None spec_key_values = qos_spec['specs'] return spec_key_values
def _get_qos_specs(qos_specs_id): ctxt = context.get_admin_context() specs = qos_specs.get_qos_specs(ctxt, qos_specs_id) if specs is None: return {} if specs.get('consumer') == 'front-end': return {} kvs = specs.get('specs', {}) LOG.info('The QoS specs is: %s.', kvs) qos = {'IOTYPE': kvs.pop('IOType', None)} if qos['IOTYPE'] not in constants.QOS_IOTYPES: msg = _('IOType must be in %(types)s.') % { 'types': constants.QOS_IOTYPES } LOG.error(msg) raise exception.InvalidInput(reason=msg) for k, v in kvs.items(): if k not in constants.QOS_SPEC_KEYS: msg = _('QoS key %s is not valid.') % k LOG.error(msg) raise exception.InvalidInput(reason=msg) if int(v) <= 0: msg = _('QoS value for %s must > 0.') % k LOG.error(msg) raise exception.InvalidInput(reason=msg) qos[k.upper()] = v if len(qos) < 2: msg = _('QoS policy must specify both IOType and one another ' 'qos spec, got policy: %s.') % qos LOG.error(msg) raise exception.InvalidInput(reason=msg) qos_keys = set(qos.keys()) if (qos_keys & set(constants.UPPER_LIMIT_KEYS) and qos_keys & set(constants.LOWER_LIMIT_KEYS)): msg = _('QoS policy upper limit and lower limit ' 'conflict, QoS policy: %s.') % qos LOG.error(msg) raise exception.InvalidInput(reason=msg) return qos
def _get_volumetype_qos(self, volume): qos = {} ctxt = context.get_admin_context() type_id = volume['volume_type_id'] if type_id: volume_type = volume_types.get_volume_type(ctxt, type_id) qos_specs_id = volume_type.get('qos_specs_id') if qos_specs_id is not None: specs = qos_specs.get_qos_specs(ctxt, qos_specs_id)['specs'] else: specs = {} for key, value in specs.items(): if key in self.scaleio_qos_keys: qos[key] = value return qos
def associate(self, req, id): """Associate a qos specs with a volume type.""" context = req.environ['cinder.context'] context.authorize(policy.UPDATE_POLICY) type_id = req.params.get('vol_type_id', None) if not type_id: msg = _('Volume Type id must not be None.') notifier_err = dict(id=id, error_message=msg) self._notify_qos_specs_error(context, 'qos_specs.delete', notifier_err) raise webob.exc.HTTPBadRequest(explanation=msg) LOG.debug("Associate qos_spec: %(id)s with type: %(type_id)s", { 'id': id, 'type_id': type_id }) try: spec = qos_specs.get_qos_specs(context, id) qos_specs.associate_qos_with_type(context, id, type_id) notifier_info = dict(id=id, type_id=type_id, created_at=spec.created_at) rpc.get_notifier('QoSSpecs').info(context, 'qos_specs.associate', notifier_info) except exception.NotFound as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.associate', notifier_err) # Not found exception will be handled at the wsgi level raise except exception.InvalidVolumeType as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.associate', notifier_err) self._notify_qos_specs_error(context, 'qos_specs.associate', notifier_err) raise webob.exc.HTTPBadRequest(explanation=six.text_type(err)) except exception.QoSSpecsAssociateFailed as err: notifier_err = dict(id=id, error_message=err) self._notify_qos_specs_error(context, 'qos_specs.associate', notifier_err) raise webob.exc.HTTPInternalServerError( explanation=six.text_type(err)) return webob.Response(status_int=http_client.ACCEPTED)
def _set_qos_by_volume_type(self, type_id): valid_presets = self.fio_qos_dict.keys() volume_type = volume_types.get_volume_type(ctxt=None, id=type_id) qos_specs_id = volume_type.get('qos_specs_id') specs = volume_type.get('extra_specs') if qos_specs_id is not None: kvs = qos_specs.get_qos_specs(ctxt=None, id=qos_specs_id)['specs'] else: kvs = specs for key, value in kvs.iteritems(): if ':' in key: fields = key.split(':') key = fields[1] if 'fio-qos' in key: if value in valid_presets: return self.fio_qos_dict[value]
def _set_qos_by_volume_type(self, type_id): valid_presets = self.fio_qos_dict.keys() volume_type = volume_types.get_volume_type(ctxt=None, id=type_id) qos_specs_id = volume_type.get("qos_specs_id") specs = volume_type.get("extra_specs") if qos_specs_id is not None: kvs = qos_specs.get_qos_specs(ctxt=None, id=qos_specs_id)["specs"] else: kvs = specs for key, value in kvs.iteritems(): if ":" in key: fields = key.split(":") key = fields[1] if "fio-qos" in key: if value in valid_presets: return self.fio_qos_dict[value]
def _get_policies_for_resource(self, resource): """Get extra_specs and qos_specs of a volume_type. This fetches the scoped keys from the volume type. Anything set from qos_specs will override key/values set from extra_specs. """ type_id = resource.get('volume_type_id', None) # Handle case of volume with no type. We still want the # specified defaults from above if type_id: ctxt = context.get_admin_context() volume_type = volume_types.get_volume_type(ctxt, type_id) specs = volume_type.get('extra_specs') else: volume_type = None specs = {} # Set defaults: policies = {k.lstrip('DF:'): str(v['default']) for (k, v) in self._init_vendor_properties()[0].items()} if volume_type: # Populate updated value for key, value in specs.items(): if ':' in key: fields = key.split(':') key = fields[1] policies[key] = value qos_specs_id = volume_type.get('qos_specs_id') if qos_specs_id is not None: qos_kvs = qos_specs.get_qos_specs(ctxt, qos_specs_id)['specs'] if qos_kvs: policies.update(qos_kvs) # Cast everything except booleans int that can be cast for k, v in policies.items(): # Handle String Boolean case if v == 'True' or v == 'False': policies[k] = policies[k] == 'True' continue # Int cast try: policies[k] = int(v) except ValueError: pass return policies
def _get_policies_for_resource(driver, resource): """Get extra_specs and qos_specs of a volume_type. This fetches the scoped keys from the volume type. Anything set from qos_specs will override key/values set from extra_specs. """ volume_type = driver._get_volume_type_obj(resource) # Handle case of volume with no type. We still want the # specified defaults from above if volume_type: specs = volume_type.get('extra_specs') else: specs = {} # Set defaults: policies = { k.lstrip('DF:'): str(v['default']) for (k, v) in driver._init_vendor_properties()[0].items() } if volume_type: # Populate updated value for key, value in specs.items(): if ':' in key: fields = key.split(':') key = fields[1] policies[key] = value qos_specs_id = volume_type.get('qos_specs_id') if qos_specs_id is not None: ctxt = context.get_admin_context() qos_kvs = qos_specs.get_qos_specs(ctxt, qos_specs_id)['specs'] if qos_kvs: policies.update(qos_kvs) # Cast everything except booleans int that can be cast for k, v in policies.items(): # Handle String Boolean case if v == 'True' or v == 'False': policies[k] = policies[k] == 'True' continue # Int cast try: policies[k] = int(v) except ValueError: pass return policies
def test_delete_keys(self): def fake_db_qos_delete_key(context, id, key): if key == 'NotFound': raise exception.QoSSpecsKeyNotFound(specs_id=id, specs_key=key) else: pass def fake_qos_specs_get(context, id): if id == 'NotFound': raise exception.QoSSpecsNotFound(specs_id=id) else: pass value = {'foo': 'Foo', 'bar': 'Bar', 'zoo': 'tiger'} name = 'QoSName' consumer = 'front-end' specs_id = self._create_qos_specs(name, consumer, value) qos_specs.delete_keys(self.ctxt, specs_id, ['foo', 'bar']) del value['foo'] del value['bar'] expected = { 'name': name, 'id': specs_id, 'consumer': consumer, 'specs': value } specs = qos_specs.get_qos_specs(self.ctxt, specs_id) specs_dic = { 'consumer': specs['consumer'], 'id': specs['id'], 'name': specs['name'], 'specs': specs['specs'] } self.assertDictMatch(expected, specs_dic) self.stubs.Set(db, 'qos_specs_item_delete', fake_db_qos_delete_key) self.assertRaises(exception.InvalidQoSSpecs, qos_specs.delete_keys, self.ctxt, None, []) self.assertRaises(exception.QoSSpecsNotFound, qos_specs.delete_keys, self.ctxt, 'NotFound', []) self.assertRaises(exception.QoSSpecsKeyNotFound, qos_specs.delete_keys, self.ctxt, specs_id, ['NotFound']) self.assertRaises(exception.QoSSpecsKeyNotFound, qos_specs.delete_keys, self.ctxt, specs_id, ['foo', 'bar', 'NotFound'])
def _get_qos_by_volume_type(self, ctxt, type_id): qos = {} # NOTE(bardia): we only honor qos_specs if type_id: volume_type = volume_types.get_volume_type(ctxt, type_id) qos_specs_id = volume_type.get('qos_specs_id') if qos_specs_id is not None: kvs = qos_specs.get_qos_specs(ctxt, qos_specs_id)['specs'] qos['uuid'] = qos_specs_id else: kvs = {} for key, value in kvs.items(): if key in self.COHO_QOS_KEYS: qos[key] = int(value) return qos
def _get_qos_specs(qos_specs_id, client): ctxt = context.get_admin_context() specs = qos_specs.get_qos_specs(ctxt, qos_specs_id) if specs is None: return {} if specs.get('consumer') == 'front-end': return {} kvs = specs.get('specs', {}) LOG.info('The QoS specs is: %s.', kvs) qos = dict() for k, v in kvs.items(): if k not in constants.QOS_KEYS + constants.QOS_SCHEDULER_KEYS: msg = _('QoS key %s is not valid.') % k LOG.error(msg) raise exception.InvalidInput(reason=msg) if k in constants.QOS_KEYS: if int(v) <= 0: msg = _('QoS value for %s must > 0.') % k LOG.error(msg) raise exception.InvalidInput(reason=msg) qos[k] = int(v.encode("utf-8")) elif k in constants.QOS_SCHEDULER_KEYS: qos[k] = v.strip() for item in constants.QOS_MUST_SET: if qos.get(item) is None: msg = _('maxIOPS and maxMBPS must be set for QoS: %s') % qos LOG.error(msg) raise exception.InvalidInput(reason=msg) if qos.get(constants.QOS_SCHEDULER_KEYS[0]): if client.get_fsm_version() >= constants.QOS_SUPPORT_SCHEDULE_VERSION: qos = _check_and_convert_qos(qos, client) else: msg = _('FusionStorage Version is not suitable for QoS: %s') % qos LOG.error(msg) raise exception.InvalidInput(reason=msg) return qos