From: Ihar Hrachyshka Date: Tue, 30 Jun 2015 10:32:27 +0000 (+0300) Subject: First QoS versioned objects, ever X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=e90b28662eb769e26f2f6c202a71910819c3ff41;p=openstack-build%2Fneutron-build.git First QoS versioned objects, ever Well, first versioned objects in the tree. Binding to networks and ports is not implemented. No tests. Checked manually. blueprint quantum-qos-api Co-Authored-By: vikram.choudhary Change-Id: I9b6cacfda4f40230d746222bed5b6c490be63743 --- diff --git a/neutron/db/api.py b/neutron/db/api.py index 0b68bd331..b74f56e7b 100644 --- a/neutron/db/api.py +++ b/neutron/db/api.py @@ -19,9 +19,12 @@ import six from oslo_config import cfg from oslo_db import exception as os_db_exception from oslo_db.sqlalchemy import session +from oslo_utils import uuidutils from sqlalchemy import exc from sqlalchemy import orm +from neutron.db import common_db_mixin + _FACADE = None @@ -85,3 +88,39 @@ class convert_db_exception_to_retry(object): except self.to_catch as e: raise os_db_exception.RetryRequest(e) return wrapper + + +# Common database operation implementations +def get_object(context, model, id): + with context.session.begin(subtransactions=True): + return (common_db_mixin.model_query(context, model) + .filter_by(id=id) + .one()) + + +def get_objects(context, model): + with context.session.begin(subtransactions=True): + return common_db_mixin.model_query(context, model).all() + + +def create_object(context, model, values): + with context.session.begin(subtransactions=True): + if 'id' not in values: + values['id'] = uuidutils.generate_uuid() + db_obj = model(**values) + context.session.add(db_obj) + return db_obj.__dict__ + + +def update_object(context, model, id, values): + with context.session.begin(subtransactions=True): + db_obj = get_object(context, model, id) + db_obj.update(values) + db_obj.save(session=context.session) + return db_obj.__dict__ + + +def delete_object(context, model, id): + with context.session.begin(subtransactions=True): + db_obj = get_object(context, model, id) + db_obj.delete() diff --git a/neutron/objects/__init__.py b/neutron/objects/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/neutron/objects/base.py b/neutron/objects/base.py new file mode 100644 index 000000000..b7198692e --- /dev/null +++ b/neutron/objects/base.py @@ -0,0 +1,62 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import abc + +from oslo_versionedobjects import base as obj_base +import six + +from neutron.db import api as db_api + + +# TODO(QoS): revisit dict compatibility and how we can isolate dict behavior + + +@six.add_metaclass(abc.ABCMeta) +class NeutronObject(obj_base.VersionedObject, + obj_base.VersionedObjectDictCompat): + + # should be overridden for all persistent objects + db_model = None + + def from_db_object(self, *objs): + for field in self.fields: + for db_obj in objs: + if field in db_obj: + setattr(self, field, db_obj[field]) + break + self.obj_reset_changes() + + @classmethod + def get_by_id(cls, context, id): + db_obj = db_api.get_object(context, cls.db_model, id) + return cls(context, **db_obj) + + @classmethod + def get_objects(cls, context): + db_objs = db_api.get_objects(context, cls.db_model) + objs = [cls(context, **db_obj) for db_obj in db_objs] + return objs + + def create(self): + fields = self.obj_get_changes() + db_obj = db_api.create_object(self._context, self.db_model, fields) + self.from_db_object(db_obj) + + def update(self): + updates = self.obj_get_changes() + db_obj = db_api.update_object(self._context, self.db_model, + self.id, updates) + self.from_db_object(self, db_obj) + + def delete(self): + db_api.delete_object(self._context, self.db_model, self.id) diff --git a/neutron/objects/qos/__init__.py b/neutron/objects/qos/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/neutron/objects/qos/policy.py b/neutron/objects/qos/policy.py new file mode 100644 index 000000000..2352673cc --- /dev/null +++ b/neutron/objects/qos/policy.py @@ -0,0 +1,38 @@ +# Copyright 2015 Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from oslo_versionedobjects import base as obj_base +from oslo_versionedobjects import fields as obj_fields + +from neutron.db.qos import models as qos_db_model +from neutron.objects import base + + +# TODO(QoS): add rule lists to object fields +# TODO(QoS): implement something for binding networks and ports with policies + + +@obj_base.VersionedObjectRegistry.register +class QosPolicy(base.NeutronObject): + + db_model = qos_db_model.QosPolicy + + fields = { + 'id': obj_fields.UUIDField(), + 'tenant_id': obj_fields.UUIDField(), + 'name': obj_fields.StringField(), + 'description': obj_fields.StringField(), + 'shared': obj_fields.BooleanField() + } diff --git a/neutron/objects/qos/rule.py b/neutron/objects/qos/rule.py new file mode 100644 index 000000000..297fddad7 --- /dev/null +++ b/neutron/objects/qos/rule.py @@ -0,0 +1,110 @@ +# Copyright 2015 Huawei Technologies India Pvt Ltd, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import abc + +from oslo_versionedobjects import base as obj_base +from oslo_versionedobjects import fields as obj_fields +import six + +from neutron.db import api as db_api +from neutron.db.qos import models as qos_db_model +from neutron.objects import base + + +@six.add_metaclass(abc.ABCMeta) +class QosRule(base.NeutronObject): + + base_db_model = qos_db_model.QosRule + + fields = { + 'id': obj_fields.UUIDField(), + 'tenant_id': obj_fields.UUIDField(), + 'type': obj_fields.StringField(), + 'qos_policy_id': obj_fields.UUIDField() + } + + _core_fields = list(fields.keys()) + + @classmethod + def _is_core_field(cls, field): + return field in cls._core_fields + + @staticmethod + def _filter_fields(fields, func): + return { + key: val for key, val in fields.items() + if func(key) + } + + # TODO(QoS): reimplement get_by_id to merge both core and addn fields + + def _get_changed_core_fields(self): + fields = self.obj_get_changes() + return self._filter_fields(fields, self._is_core_field) + + def _get_changed_addn_fields(self): + fields = self.obj_get_changes() + return self._filter_fields( + fields, lambda key: not self._is_core_field(key)) + + # TODO(QoS): create and update are not transactional safe + def create(self): + + # create base qos_rule + core_fields = self._get_changed_core_fields() + base_db_obj = db_api.create_object( + self._context, self.base_db_model, core_fields) + + # create type specific qos_..._rule + addn_fields = self._get_changed_addn_fields() + addn_fields['qos_rule_id'] = base_db_obj.id + addn_db_obj = db_api.create_object( + self._context, self.db_model, addn_fields) + + # merge two db objects into single neutron one + self.from_db_object(self._context, self, base_db_obj, addn_db_obj) + + def update(self): + updated_db_objs = [] + + # update base qos_rule, if needed + core_fields = self._get_changed_core_fields() + if core_fields: + base_db_obj = db_api.create_object( + self._context, self.base_db_model, core_fields) + updated_db_objs.append(base_db_obj) + + addn_fields = self._get_changed_addn_fields() + if addn_fields: + addn_db_obj = db_api.update_object( + self._context, self.base_db_model, self.id, addn_fields) + updated_db_objs.append(addn_db_obj) + + # update neutron object with values from both database objects + self.from_db_object(self._context, self, *updated_db_objs) + + # delete is the same, additional rule object cleanup is done thru cascading + + +@obj_base.VersionedObjectRegistry.register +class QosBandwidthLimitRule(QosRule): + + db_model = qos_db_model.QosBandwidthLimitRule + + fields = { + 'max_kbps': obj_fields.IntegerField(), + 'max_burst_kbps': obj_fields.IntegerField() + } diff --git a/requirements.txt b/requirements.txt index 8d5041c38..2e7a8452f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -35,6 +35,7 @@ oslo.rootwrap>=2.0.0 # Apache-2.0 oslo.serialization>=1.4.0 # Apache-2.0 oslo.service>=0.1.0 # Apache-2.0 oslo.utils>=1.6.0 # Apache-2.0 +oslo.versionedobjects>=0.3.0,!=0.5.0 python-novaclient>=2.22.0