Add standard attributes to qospolicy
This adds the standard attributes relationship to QoSPolicy. This has the advantage of providing created_at and updated_at, however, the primary reason is to ensure it has a revision number so QoSPolicy objects can be safely used in push notifications. Partially-Implements: blueprint push-notifications Change-Id: I8c0c33eef5d53c704b609e5bc503f46f5caad1bb
This commit is contained in:
parent
ff44cb825d
commit
f3f90027b1
|
@ -1 +1 @@
|
|||
3b935b28e7a0
|
||||
b12a3ef66e62
|
||||
|
|
|
@ -1 +1 @@
|
|||
0f5bef0f87d4
|
||||
67daae611b6e
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
"""add standardattr to qos policies
|
||||
|
||||
Revision ID: b12a3ef66e62
|
||||
Revises: 3b935b28e7a0
|
||||
Create Date: 2016-08-18 14:10:30.021055
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'b12a3ef66e62'
|
||||
down_revision = '3b935b28e7a0'
|
||||
depends_on = ('67daae611b6e',)
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# basic model of the tables with required field for migration
|
||||
TABLE = 'qos_policies'
|
||||
|
||||
|
||||
TABLE_MODEL = sa.Table(TABLE, sa.MetaData(),
|
||||
sa.Column('id', sa.String(length=36), nullable=False),
|
||||
sa.Column('description', sa.String(length=255),
|
||||
nullable=True),
|
||||
sa.Column('standard_attr_id', sa.BigInteger(),
|
||||
nullable=True))
|
||||
|
||||
standardattrs = sa.Table(
|
||||
'standardattributes', sa.MetaData(),
|
||||
sa.Column('id', sa.BigInteger(), primary_key=True, autoincrement=True),
|
||||
sa.Column('resource_type', sa.String(length=255), nullable=False),
|
||||
sa.Column('description', sa.String(length=255), nullable=True))
|
||||
|
||||
|
||||
def upgrade():
|
||||
generate_records_for_existing()
|
||||
# add the constraint now that everything is populated on that table
|
||||
op.create_foreign_key(
|
||||
constraint_name=None, source_table=TABLE,
|
||||
referent_table='standardattributes',
|
||||
local_cols=['standard_attr_id'], remote_cols=['id'],
|
||||
ondelete='CASCADE')
|
||||
op.alter_column(TABLE, 'standard_attr_id', nullable=False,
|
||||
existing_type=sa.BigInteger(), existing_nullable=True,
|
||||
existing_server_default=False)
|
||||
op.create_unique_constraint(
|
||||
constraint_name='uniq_%s0standard_attr_id' % TABLE,
|
||||
table_name=TABLE, columns=['standard_attr_id'])
|
||||
op.drop_column(TABLE, 'description')
|
||||
|
||||
|
||||
def generate_records_for_existing():
|
||||
session = sa.orm.Session(bind=op.get_bind())
|
||||
values = []
|
||||
with session.begin(subtransactions=True):
|
||||
for row in session.query(TABLE_MODEL):
|
||||
# NOTE(kevinbenton): without this disabled, pylint complains
|
||||
# about a missing 'dml' argument.
|
||||
#pylint: disable=no-value-for-parameter
|
||||
res = session.execute(
|
||||
standardattrs.insert().values(resource_type=TABLE,
|
||||
description=row[1])
|
||||
)
|
||||
session.execute(
|
||||
TABLE_MODEL.update().values(
|
||||
standard_attr_id=res.inserted_primary_key[0]).where(
|
||||
TABLE_MODEL.c.id == row[0])
|
||||
)
|
||||
# this commit is necessary to allow further operations
|
||||
session.commit()
|
||||
return values
|
|
@ -0,0 +1,35 @@
|
|||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
"""add standardattr to qos policies
|
||||
|
||||
Revision ID: 67daae611b6e
|
||||
Revises: a5648cfeeadf
|
||||
Create Date: 2016-08-18 14:10:30.021015
|
||||
|
||||
"""
|
||||
|
||||
revision = '67daae611b6e'
|
||||
down_revision = '0f5bef0f87d4'
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
TABLE = 'qos_policies'
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.add_column(TABLE, sa.Column('standard_attr_id', sa.BigInteger(),
|
||||
nullable=True))
|
|
@ -20,12 +20,13 @@ from neutron.common import constants
|
|||
from neutron.db import model_base
|
||||
from neutron.db import models_v2
|
||||
from neutron.db import rbac_db_models
|
||||
from neutron.db import standard_attr
|
||||
|
||||
|
||||
class QosPolicy(model_base.BASEV2, model_base.HasId, model_base.HasProject):
|
||||
class QosPolicy(standard_attr.HasStandardAttributes, model_base.BASEV2,
|
||||
model_base.HasId, model_base.HasProject):
|
||||
__tablename__ = 'qos_policies'
|
||||
name = sa.Column(sa.String(attrs.NAME_MAX_LEN))
|
||||
description = sa.Column(sa.String(attrs.DESCRIPTION_MAX_LEN))
|
||||
rbac_entries = sa.orm.relationship(rbac_db_models.QosPolicyRBAC,
|
||||
backref='qos_policy', lazy='joined',
|
||||
cascade='all, delete, delete-orphan')
|
||||
|
@ -78,6 +79,8 @@ class QosBandwidthLimitRule(model_base.HasId, model_base.BASEV2):
|
|||
unique=True)
|
||||
max_kbps = sa.Column(sa.Integer)
|
||||
max_burst_kbps = sa.Column(sa.Integer)
|
||||
revises_on_change = ('qos_policy', )
|
||||
qos_policy = sa.orm.relationship(QosPolicy)
|
||||
|
||||
|
||||
class QosDscpMarkingRule(models_v2.HasId, model_base.BASEV2):
|
||||
|
@ -88,6 +91,8 @@ class QosDscpMarkingRule(models_v2.HasId, model_base.BASEV2):
|
|||
nullable=False,
|
||||
unique=True)
|
||||
dscp_mark = sa.Column(sa.Integer)
|
||||
revises_on_change = ('qos_policy', )
|
||||
qos_policy = sa.orm.relationship(QosPolicy)
|
||||
|
||||
|
||||
class QosMinimumBandwidthRule(models_v2.HasId, model_base.BASEV2):
|
||||
|
@ -103,6 +108,9 @@ class QosMinimumBandwidthRule(models_v2.HasId, model_base.BASEV2):
|
|||
name='directions'),
|
||||
nullable=False,
|
||||
server_default=constants.EGRESS_DIRECTION)
|
||||
revises_on_change = ('qos_policy', )
|
||||
qos_policy = sa.orm.relationship(QosPolicy)
|
||||
|
||||
__table_args__ = (
|
||||
sa.UniqueConstraint(
|
||||
qos_policy_id, direction,
|
||||
|
|
|
@ -17,6 +17,7 @@ import itertools
|
|||
|
||||
from oslo_utils import versionutils
|
||||
from oslo_versionedobjects import base as obj_base
|
||||
from oslo_versionedobjects import exception
|
||||
from oslo_versionedobjects import fields as obj_fields
|
||||
from six import add_metaclass
|
||||
|
||||
|
@ -39,7 +40,8 @@ class QosPolicy(base.NeutronDbObject):
|
|||
# Version 1.0: Initial version
|
||||
# Version 1.1: QosDscpMarkingRule introduced
|
||||
# Version 1.2: Added QosMinimumBandwidthRule
|
||||
VERSION = '1.2'
|
||||
# Version 1.3: Added standard attributes (created_at, revision, etc)
|
||||
VERSION = '1.3'
|
||||
|
||||
# required by RbacNeutronMetaclass
|
||||
rbac_db_model = QosPolicyRBAC
|
||||
|
@ -52,7 +54,6 @@ class QosPolicy(base.NeutronDbObject):
|
|||
'id': obj_fields.UUIDField(),
|
||||
'tenant_id': obj_fields.StringField(),
|
||||
'name': obj_fields.StringField(),
|
||||
'description': obj_fields.StringField(),
|
||||
'shared': obj_fields.BooleanField(default=False),
|
||||
'rules': obj_fields.ListOfObjectsField('QosRule', subclasses=True),
|
||||
}
|
||||
|
@ -225,3 +226,12 @@ class QosPolicy(base.NeutronDbObject):
|
|||
names.append(rule_obj_impl.QosDscpMarkingRule.obj_name())
|
||||
if 'rules' in primitive and names:
|
||||
primitive['rules'] = filter_rules(names, primitive['rules'])
|
||||
|
||||
if _target_version < (1, 3):
|
||||
standard_fields = ['revision_number', 'created_at', 'updated_at']
|
||||
for f in standard_fields:
|
||||
primitive.pop(f)
|
||||
if primitive['description'] is None:
|
||||
# description was not nullable before
|
||||
raise exception.IncompatibleObjectVersion(
|
||||
objver=target_version, objname='QoSPolicy')
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
#
|
||||
# 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_db.sqlalchemy import utils as db_utils
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from neutron.tests.functional.db import test_migrations
|
||||
|
||||
|
||||
class QosStandardAttrMixin(object):
|
||||
"""Validates qos standard attr migration."""
|
||||
|
||||
def _create_qos_pol(self, pol_id, description):
|
||||
otable = db_utils.get_table(self.engine, 'qos_policies')
|
||||
values = {'id': pol_id, 'description': description}
|
||||
self.engine.execute(otable.insert().values(values))
|
||||
|
||||
def _create_policies_with_descriptions(self, engine):
|
||||
for i in range(10):
|
||||
pol_id = uuidutils.generate_uuid()
|
||||
self._create_qos_pol(pol_id, 'description-%s' % pol_id)
|
||||
|
||||
def _pre_upgrade_b12a3ef66e62(self, engine):
|
||||
self._create_policies_with_descriptions(engine)
|
||||
return True # return True so check function is invoked after migrate
|
||||
|
||||
def _check_b12a3ef66e62(self, engine, data):
|
||||
qp = db_utils.get_table(engine, 'qos_policies')
|
||||
sa = db_utils.get_table(engine, 'standardattributes')
|
||||
for qos_pol in engine.execute(qp.select()).fetchall():
|
||||
# ensure standard attributes model was created
|
||||
standard_id = qos_pol.standard_attr_id
|
||||
rows = engine.execute(
|
||||
sa.select().where(sa.c.id == standard_id)).fetchall()
|
||||
self.assertEqual(1, len(rows))
|
||||
# ensure description got moved over
|
||||
self.assertEqual('description-%s' % qos_pol.id,
|
||||
rows[0].description)
|
||||
|
||||
|
||||
class TestQosStandardAttrMysql(QosStandardAttrMixin,
|
||||
test_migrations.TestWalkMigrationsMysql):
|
||||
pass
|
||||
|
||||
|
||||
class TestQosStandardAttrPsql(QosStandardAttrMixin,
|
||||
test_migrations.TestWalkMigrationsPsql):
|
||||
pass
|
|
@ -11,6 +11,8 @@
|
|||
# under the License.
|
||||
|
||||
import mock
|
||||
from oslo_versionedobjects import exception
|
||||
import testtools
|
||||
|
||||
from neutron.common import exceptions as n_exc
|
||||
from neutron.db import models_v2
|
||||
|
@ -389,12 +391,19 @@ class QosPolicyDbObjectTestCase(test_base.BaseDbObjectTestCase,
|
|||
policy_obj, rule_objs = self._create_test_policy_with_rules(
|
||||
RULE_OBJ_CLS.keys(), reload_rules=True)
|
||||
|
||||
policy_obj_v1_2 = self._policy_through_version(policy_obj, '1.2')
|
||||
policy_obj_v1_2 = self._policy_through_version(
|
||||
policy_obj, policy.QosPolicy.VERSION)
|
||||
|
||||
for rule_obj in rule_objs:
|
||||
self.assertIn(rule_obj, policy_obj_v1_2.rules)
|
||||
|
||||
def test_object_version_degradation_1_1_to_1_0(self):
|
||||
def test_object_version_degradation_1_3_to_1_2_null_description(self):
|
||||
policy_obj = self._create_test_policy()
|
||||
policy_obj.description = None
|
||||
with testtools.ExpectedException(exception.IncompatibleObjectVersion):
|
||||
policy_obj.obj_to_primitive('1.2')
|
||||
|
||||
def test_object_version_degradation_to_1_0(self):
|
||||
#NOTE(mangelajo): we should not check .VERSION, since that's the
|
||||
# local version on the class definition
|
||||
policy_obj, rule_objs = self._create_test_policy_with_rules(
|
||||
|
|
|
@ -39,7 +39,7 @@ object_data = {
|
|||
'QosDscpMarkingRule': '1.2-0313c6554b34fd10c753cb63d638256c',
|
||||
'QosMinimumBandwidthRule': '1.2-314c3419f4799067cc31cc319080adff',
|
||||
'QosRuleType': '1.2-e6fd08fcca152c339cbd5e9b94b1b8e7',
|
||||
'QosPolicy': '1.2-7c5659e1c1f64395223592d3d3293e22',
|
||||
'QosPolicy': '1.3-2eb3494f990acae59cb51381e7f99443',
|
||||
'Route': '1.0-a9883a63b416126f9e345523ec09483b',
|
||||
'SecurityGroup': '1.0-e26b90c409b31fd2e3c6fcec402ac0b9',
|
||||
'SecurityGroupRule': '1.0-e9b8dace9d48b936c62ad40fe1f339d5',
|
||||
|
|
Loading…
Reference in New Issue