Add "default" behaviour to QoS policies
This patch implements the "default" behaviour for QoS policies. If this flag is enabled for a QoS policy in a project, all new networks created will have this QoS policy assigned by default. If a new QoS policy is created or updated with this flag and another QoS policy in the same project is set as the default policy, the new one won't be created or updated. To set another QoS policy as default, the current one must be unset. DocImpact: A "default" flag is introduced for QoS policies. If this flag is enabled in a QoS policy (attached to a project), then all networks created in this project would have this QoS policy assigned, unless an explicit policy is specified. APIImpact Closes-Bug: #1639220 Change-Id: If5ff2b00fa828f93aa089e275ddbd1ff542b79d4
This commit is contained in:
parent
e137e63db3
commit
9d69822e43
@ -31,6 +31,15 @@ class QosRuleNotFound(e.NotFound):
|
|||||||
"could not be found.")
|
"could not be found.")
|
||||||
|
|
||||||
|
|
||||||
|
class QoSPolicyDefaultAlreadyExists(e.Conflict):
|
||||||
|
message = _("A default QoS policy exists for project %(project_id)s.")
|
||||||
|
|
||||||
|
|
||||||
|
class QoSPolicyDefaultNotFound(e.Conflict):
|
||||||
|
message = _("Default QoS policy for project %(project_id)s could not be "
|
||||||
|
"found.")
|
||||||
|
|
||||||
|
|
||||||
class PortQosBindingNotFound(e.NotFound):
|
class PortQosBindingNotFound(e.NotFound):
|
||||||
message = _("QoS binding for port %(port_id)s and policy %(policy_id)s "
|
message = _("QoS binding for port %(port_id)s and policy %(policy_id)s "
|
||||||
"could not be found.")
|
"could not be found.")
|
||||||
|
@ -20,6 +20,8 @@ import six
|
|||||||
|
|
||||||
NETWORK = 'network'
|
NETWORK = 'network'
|
||||||
PORT = 'port'
|
PORT = 'port'
|
||||||
|
EVENT_CREATE = 'create'
|
||||||
|
EVENT_UPDATE = 'update'
|
||||||
|
|
||||||
|
|
||||||
CORE_RESOURCES = [NETWORK, PORT]
|
CORE_RESOURCES = [NETWORK, PORT]
|
||||||
@ -29,12 +31,14 @@ CORE_RESOURCES = [NETWORK, PORT]
|
|||||||
class CoreResourceExtension(object):
|
class CoreResourceExtension(object):
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def process_fields(self, context, resource_type,
|
def process_fields(self, context, resource_type, event_type,
|
||||||
requested_resource, actual_resource):
|
requested_resource, actual_resource):
|
||||||
"""Process extension fields.
|
"""Process extension fields.
|
||||||
|
|
||||||
:param context: neutron api request context
|
:param context: neutron api request context
|
||||||
:param resource_type: core resource type (one of CORE_RESOURCES)
|
:param resource_type: core resource type (one of CORE_RESOURCES)
|
||||||
|
:param event_type: kind of event triggering this action (update,
|
||||||
|
create)
|
||||||
:param requested_resource: resource dict that contains extension fields
|
:param requested_resource: resource dict that contains extension fields
|
||||||
:param actual_resource: actual resource dict known to plugin
|
:param actual_resource: actual resource dict known to plugin
|
||||||
"""
|
"""
|
||||||
|
@ -63,6 +63,17 @@ class QosCoreResourceExtension(base.CoreResourceExtension):
|
|||||||
policy.attach_port(port['id'])
|
policy.attach_port(port['id'])
|
||||||
port[qos_consts.QOS_POLICY_ID] = qos_policy_id
|
port[qos_consts.QOS_POLICY_ID] = qos_policy_id
|
||||||
|
|
||||||
|
def _create_network_policy(self, context, network, network_changes):
|
||||||
|
qos_policy_id = network_changes.get(qos_consts.QOS_POLICY_ID)
|
||||||
|
if not qos_policy_id:
|
||||||
|
qos_policy_id = policy_object.QosPolicyDefault.get_object(
|
||||||
|
context, project_id=network['project_id'])
|
||||||
|
|
||||||
|
if qos_policy_id is not None:
|
||||||
|
policy = self._get_policy_obj(context, qos_policy_id)
|
||||||
|
policy.attach_network(network['id'])
|
||||||
|
network[qos_consts.QOS_POLICY_ID] = qos_policy_id
|
||||||
|
|
||||||
def _update_network_policy(self, context, network, network_changes):
|
def _update_network_policy(self, context, network, network_changes):
|
||||||
old_policy = policy_object.QosPolicy.get_network_policy(
|
old_policy = policy_object.QosPolicy.get_network_policy(
|
||||||
context.elevated(), network['id'])
|
context.elevated(), network['id'])
|
||||||
@ -80,11 +91,13 @@ class QosCoreResourceExtension(base.CoreResourceExtension):
|
|||||||
with db_api.autonested_transaction(context.session):
|
with db_api.autonested_transaction(context.session):
|
||||||
return getattr(self, method_name)(context=context, **kwargs)
|
return getattr(self, method_name)(context=context, **kwargs)
|
||||||
|
|
||||||
def process_fields(self, context, resource_type,
|
def process_fields(self, context, resource_type, event_type,
|
||||||
requested_resource, actual_resource):
|
requested_resource, actual_resource):
|
||||||
if (qos_consts.QOS_POLICY_ID in requested_resource and
|
if (qos_consts.QOS_POLICY_ID in requested_resource and
|
||||||
self.plugin_loaded):
|
self.plugin_loaded):
|
||||||
self._exec('_update_%s_policy' % resource_type, context,
|
method_name = ('_%(event)s_%(resource)s_policy' %
|
||||||
|
{'event': event_type, 'resource': resource_type})
|
||||||
|
self._exec(method_name, context,
|
||||||
{resource_type: actual_resource,
|
{resource_type: actual_resource,
|
||||||
"%s_changes" % resource_type: requested_resource})
|
"%s_changes" % resource_type: requested_resource})
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
2b42d90729da
|
62c781cb6192
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
# Copyright 2017 Intel Corporation
|
||||||
|
#
|
||||||
|
# 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 is default to qos policies
|
||||||
|
|
||||||
|
Revision ID: 62c781cb6192
|
||||||
|
Revises: 2b42d90729da
|
||||||
|
Create Date: 2017-02-07 13:28:35.894357
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '62c781cb6192'
|
||||||
|
down_revision = '2b42d90729da'
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
op.create_table(
|
||||||
|
'qos_policies_default',
|
||||||
|
sa.Column('qos_policy_id',
|
||||||
|
sa.String(length=36),
|
||||||
|
sa.ForeignKey('qos_policies.id', ondelete='CASCADE'),
|
||||||
|
nullable=False),
|
||||||
|
sa.Column('project_id',
|
||||||
|
sa.String(length=255),
|
||||||
|
nullable=False,
|
||||||
|
index=True,
|
||||||
|
primary_key=True),
|
||||||
|
)
|
@ -73,6 +73,16 @@ class QosPortPolicyBinding(model_base.BASEV2):
|
|||||||
cascade='delete', lazy='joined'))
|
cascade='delete', lazy='joined'))
|
||||||
|
|
||||||
|
|
||||||
|
class QosPolicyDefault(model_base.BASEV2,
|
||||||
|
model_base.HasProjectPrimaryKeyIndex):
|
||||||
|
__tablename__ = 'qos_policies_default'
|
||||||
|
qos_policy_id = sa.Column(sa.String(36),
|
||||||
|
sa.ForeignKey('qos_policies.id',
|
||||||
|
ondelete='CASCADE'),
|
||||||
|
nullable=False)
|
||||||
|
revises_on_change = ('qos_policy',)
|
||||||
|
|
||||||
|
|
||||||
class QosBandwidthLimitRule(model_base.HasId, model_base.BASEV2):
|
class QosBandwidthLimitRule(model_base.HasId, model_base.BASEV2):
|
||||||
__tablename__ = 'qos_bandwidth_limit_rules'
|
__tablename__ = 'qos_bandwidth_limit_rules'
|
||||||
qos_policy_id = sa.Column(sa.String(36),
|
qos_policy_id = sa.Column(sa.String(36),
|
||||||
|
@ -32,8 +32,10 @@ from neutron.objects.qos import rule as rule_object
|
|||||||
from neutron.plugins.common import constants
|
from neutron.plugins.common import constants
|
||||||
from neutron.services.qos import qos_consts
|
from neutron.services.qos import qos_consts
|
||||||
|
|
||||||
|
|
||||||
ALIAS = "qos"
|
ALIAS = "qos"
|
||||||
QOS_PREFIX = "/qos"
|
QOS_PREFIX = "/qos"
|
||||||
|
COLLECTION_NAME = 'policies'
|
||||||
|
|
||||||
# Attribute Map
|
# Attribute Map
|
||||||
QOS_RULE_COMMON_FIELDS = {
|
QOS_RULE_COMMON_FIELDS = {
|
||||||
@ -47,7 +49,7 @@ QOS_RULE_COMMON_FIELDS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RESOURCE_ATTRIBUTE_MAP = {
|
RESOURCE_ATTRIBUTE_MAP = {
|
||||||
'policies': {
|
COLLECTION_NAME: {
|
||||||
'id': {'allow_post': False, 'allow_put': False,
|
'id': {'allow_post': False, 'allow_put': False,
|
||||||
'validate': {'type:uuid': None},
|
'validate': {'type:uuid': None},
|
||||||
'is_visible': True, 'primary_key': True},
|
'is_visible': True, 'primary_key': True},
|
||||||
|
80
neutron/extensions/qos_default.py
Normal file
80
neutron/extensions/qos_default.py
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
# Copyright (c) 2017 Intel Corporation.
|
||||||
|
# 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 neutron_lib.api import converters
|
||||||
|
from neutron_lib.api import extensions
|
||||||
|
|
||||||
|
from neutron.extensions import qos
|
||||||
|
|
||||||
|
|
||||||
|
# The alias of the extension.
|
||||||
|
ALIAS = 'qos-default'
|
||||||
|
|
||||||
|
# The name of the extension.
|
||||||
|
NAME = 'QoS default policy'
|
||||||
|
|
||||||
|
# The description of the extension.
|
||||||
|
DESCRIPTION = 'Expose the QoS default policy per project'
|
||||||
|
|
||||||
|
# A timestamp of when the extension was introduced.
|
||||||
|
TIMESTAMP = '2017-041-06T10:00:00-00:00'
|
||||||
|
|
||||||
|
# The list of required extensions.
|
||||||
|
REQUIRED_EXTENSIONS = [qos.ALIAS]
|
||||||
|
|
||||||
|
# The list of optional extensions.
|
||||||
|
OPTIONAL_EXTENSIONS = None
|
||||||
|
|
||||||
|
# The resource attribute map for the extension.
|
||||||
|
RESOURCE_ATTRIBUTE_MAP = {
|
||||||
|
qos.COLLECTION_NAME: {
|
||||||
|
'is_default': {'allow_post': True,
|
||||||
|
'allow_put': True,
|
||||||
|
'default': False,
|
||||||
|
'convert_to': converters.convert_to_boolean,
|
||||||
|
'is_visible': True}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Qos_default(extensions.ExtensionDescriptor):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_name(cls):
|
||||||
|
return NAME
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_alias(cls):
|
||||||
|
return ALIAS
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_description(cls):
|
||||||
|
return DESCRIPTION
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_updated(cls):
|
||||||
|
return TIMESTAMP
|
||||||
|
|
||||||
|
def get_required_extensions(self):
|
||||||
|
return REQUIRED_EXTENSIONS or []
|
||||||
|
|
||||||
|
def get_optional_extensions(self):
|
||||||
|
return OPTIONAL_EXTENSIONS or []
|
||||||
|
|
||||||
|
def get_extended_resources(self, version):
|
||||||
|
if version == "2.0":
|
||||||
|
return RESOURCE_ATTRIBUTE_MAP
|
||||||
|
else:
|
||||||
|
return {}
|
@ -20,7 +20,6 @@ from oslo_versionedobjects import base as obj_base
|
|||||||
from oslo_versionedobjects import exception
|
from oslo_versionedobjects import exception
|
||||||
from oslo_versionedobjects import fields as obj_fields
|
from oslo_versionedobjects import fields as obj_fields
|
||||||
|
|
||||||
from neutron._i18n import _
|
|
||||||
from neutron.common import constants as n_const
|
from neutron.common import constants as n_const
|
||||||
from neutron.common import exceptions
|
from neutron.common import exceptions
|
||||||
from neutron.db import api as db_api
|
from neutron.db import api as db_api
|
||||||
@ -28,6 +27,7 @@ from neutron.db import models_v2
|
|||||||
from neutron.db.qos import api as qos_db_api
|
from neutron.db.qos import api as qos_db_api
|
||||||
from neutron.db.qos import models as qos_db_model
|
from neutron.db.qos import models as qos_db_model
|
||||||
from neutron.db.rbac_db_models import QosPolicyRBAC
|
from neutron.db.rbac_db_models import QosPolicyRBAC
|
||||||
|
from neutron.objects import base as base_db
|
||||||
from neutron.objects import common_types
|
from neutron.objects import common_types
|
||||||
from neutron.objects.db import api as obj_db_api
|
from neutron.objects.db import api as obj_db_api
|
||||||
from neutron.objects.qos import rule as rule_obj_impl
|
from neutron.objects.qos import rule as rule_obj_impl
|
||||||
@ -42,7 +42,8 @@ class QosPolicy(rbac_db.NeutronRbacObject):
|
|||||||
# Version 1.3: Added standard attributes (created_at, revision, etc)
|
# Version 1.3: Added standard attributes (created_at, revision, etc)
|
||||||
# Version 1.4: Changed tenant_id to project_id
|
# Version 1.4: Changed tenant_id to project_id
|
||||||
# Version 1.5: Direction for bandwidth limit rule added
|
# Version 1.5: Direction for bandwidth limit rule added
|
||||||
VERSION = '1.5'
|
# Version 1.6: Added "is_default" field
|
||||||
|
VERSION = '1.6'
|
||||||
|
|
||||||
# required by RbacNeutronMetaclass
|
# required by RbacNeutronMetaclass
|
||||||
rbac_db_model = QosPolicyRBAC
|
rbac_db_model = QosPolicyRBAC
|
||||||
@ -57,32 +58,37 @@ class QosPolicy(rbac_db.NeutronRbacObject):
|
|||||||
'name': obj_fields.StringField(),
|
'name': obj_fields.StringField(),
|
||||||
'shared': obj_fields.BooleanField(default=False),
|
'shared': obj_fields.BooleanField(default=False),
|
||||||
'rules': obj_fields.ListOfObjectsField('QosRule', subclasses=True),
|
'rules': obj_fields.ListOfObjectsField('QosRule', subclasses=True),
|
||||||
|
'is_default': obj_fields.BooleanField(default=False),
|
||||||
}
|
}
|
||||||
|
|
||||||
fields_no_update = ['id', 'project_id']
|
fields_no_update = ['id', 'project_id']
|
||||||
|
|
||||||
synthetic_fields = ['rules']
|
synthetic_fields = ['rules', 'is_default']
|
||||||
|
|
||||||
|
extra_filter_names = {'is_default'}
|
||||||
|
|
||||||
binding_models = {'network': network_binding_model,
|
binding_models = {'network': network_binding_model,
|
||||||
'port': port_binding_model}
|
'port': port_binding_model}
|
||||||
|
|
||||||
def obj_load_attr(self, attrname):
|
def obj_load_attr(self, attrname):
|
||||||
if attrname == 'project_id':
|
if attrname == 'rules':
|
||||||
return super(QosPolicy, self).obj_load_attr(attrname)
|
return self._reload_rules()
|
||||||
|
elif attrname == 'is_default':
|
||||||
|
return self._reload_is_default()
|
||||||
|
return super(QosPolicy, self).obj_load_attr(attrname)
|
||||||
|
|
||||||
if attrname != 'rules':
|
def _reload_rules(self):
|
||||||
raise exceptions.ObjectActionError(
|
|
||||||
action='obj_load_attr',
|
|
||||||
reason=_('unable to load %s') % attrname)
|
|
||||||
|
|
||||||
if not hasattr(self, attrname):
|
|
||||||
self.reload_rules()
|
|
||||||
|
|
||||||
def reload_rules(self):
|
|
||||||
rules = rule_obj_impl.get_rules(self.obj_context, self.id)
|
rules = rule_obj_impl.get_rules(self.obj_context, self.id)
|
||||||
setattr(self, 'rules', rules)
|
setattr(self, 'rules', rules)
|
||||||
self.obj_reset_changes(['rules'])
|
self.obj_reset_changes(['rules'])
|
||||||
|
|
||||||
|
def _reload_is_default(self):
|
||||||
|
if self.get_default() == self.id:
|
||||||
|
setattr(self, 'is_default', True)
|
||||||
|
else:
|
||||||
|
setattr(self, 'is_default', False)
|
||||||
|
self.obj_reset_changes(['is_default'])
|
||||||
|
|
||||||
def get_rule_by_id(self, rule_id):
|
def get_rule_by_id(self, rule_id):
|
||||||
"""Return rule specified by rule_id.
|
"""Return rule specified by rule_id.
|
||||||
|
|
||||||
@ -107,7 +113,8 @@ class QosPolicy(rbac_db.NeutronRbacObject):
|
|||||||
not cls.is_accessible(context, policy_obj)):
|
not cls.is_accessible(context, policy_obj)):
|
||||||
return
|
return
|
||||||
|
|
||||||
policy_obj.reload_rules()
|
policy_obj.obj_load_attr('rules')
|
||||||
|
policy_obj.obj_load_attr('is_default')
|
||||||
return policy_obj
|
return policy_obj
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -124,7 +131,8 @@ class QosPolicy(rbac_db.NeutronRbacObject):
|
|||||||
for obj in objs:
|
for obj in objs:
|
||||||
if not cls.is_accessible(context, obj):
|
if not cls.is_accessible(context, obj):
|
||||||
continue
|
continue
|
||||||
obj.reload_rules()
|
obj.obj_load_attr('rules')
|
||||||
|
obj.obj_load_attr('is_default')
|
||||||
result.append(obj)
|
result.append(obj)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@ -149,7 +157,18 @@ class QosPolicy(rbac_db.NeutronRbacObject):
|
|||||||
def create(self):
|
def create(self):
|
||||||
with db_api.autonested_transaction(self.obj_context.session):
|
with db_api.autonested_transaction(self.obj_context.session):
|
||||||
super(QosPolicy, self).create()
|
super(QosPolicy, self).create()
|
||||||
self.reload_rules()
|
if self.is_default:
|
||||||
|
self.set_default()
|
||||||
|
self.obj_load_attr('rules')
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
with db_api.autonested_transaction(self.obj_context.session):
|
||||||
|
if 'is_default' in self.obj_what_changed():
|
||||||
|
if self.is_default:
|
||||||
|
self.set_default()
|
||||||
|
else:
|
||||||
|
self.unset_default()
|
||||||
|
super(QosPolicy, self).update()
|
||||||
|
|
||||||
def delete(self):
|
def delete(self):
|
||||||
with db_api.autonested_transaction(self.obj_context.session):
|
with db_api.autonested_transaction(self.obj_context.session):
|
||||||
@ -184,6 +203,28 @@ class QosPolicy(rbac_db.NeutronRbacObject):
|
|||||||
policy_id=self.id,
|
policy_id=self.id,
|
||||||
port_id=port_id)
|
port_id=port_id)
|
||||||
|
|
||||||
|
def set_default(self):
|
||||||
|
if not self.get_default():
|
||||||
|
qos_default_policy = QosPolicyDefault(self.obj_context,
|
||||||
|
qos_policy_id=self.id,
|
||||||
|
project_id=self.project_id)
|
||||||
|
qos_default_policy.create()
|
||||||
|
elif self.get_default() != self.id:
|
||||||
|
raise exceptions.QoSPolicyDefaultAlreadyExists(
|
||||||
|
project_id=self.project_id)
|
||||||
|
|
||||||
|
def unset_default(self):
|
||||||
|
if self.get_default() == self.id:
|
||||||
|
qos_default_policy = QosPolicyDefault.get_object(
|
||||||
|
self.obj_context, project_id=self.project_id)
|
||||||
|
qos_default_policy.delete()
|
||||||
|
|
||||||
|
def get_default(self):
|
||||||
|
qos_default_policy = QosPolicyDefault.get_object(
|
||||||
|
self.obj_context, project_id=self.project_id)
|
||||||
|
if qos_default_policy:
|
||||||
|
return qos_default_policy.qos_policy_id
|
||||||
|
|
||||||
def get_bound_networks(self):
|
def get_bound_networks(self):
|
||||||
return qos_db_api.get_network_ids_by_network_policy_binding(
|
return qos_db_api.get_network_ids_by_network_policy_binding(
|
||||||
self.obj_context, self.id)
|
self.obj_context, self.id)
|
||||||
@ -264,3 +305,21 @@ class QosPolicy(rbac_db.NeutronRbacObject):
|
|||||||
if 'rules' in primitive:
|
if 'rules' in primitive:
|
||||||
primitive['rules'] = filter_ingress_bandwidth_limit_rules(
|
primitive['rules'] = filter_ingress_bandwidth_limit_rules(
|
||||||
primitive['rules'])
|
primitive['rules'])
|
||||||
|
|
||||||
|
if _target_version < (1, 6):
|
||||||
|
primitive.pop('is_default', None)
|
||||||
|
|
||||||
|
|
||||||
|
@obj_base.VersionedObjectRegistry.register
|
||||||
|
class QosPolicyDefault(base_db.NeutronDbObject):
|
||||||
|
# Version 1.0: Initial version
|
||||||
|
VERSION = '1.0'
|
||||||
|
|
||||||
|
db_model = qos_db_model.QosPolicyDefault
|
||||||
|
|
||||||
|
fields = {
|
||||||
|
'qos_policy_id': common_types.UUIDField(),
|
||||||
|
'project_id': obj_fields.StringField(),
|
||||||
|
}
|
||||||
|
|
||||||
|
primary_keys = ['project_id']
|
||||||
|
@ -32,13 +32,15 @@ class QosExtensionDriver(api.ExtensionDriver):
|
|||||||
|
|
||||||
def process_create_network(self, context, data, result):
|
def process_create_network(self, context, data, result):
|
||||||
self.core_ext_handler.process_fields(
|
self.core_ext_handler.process_fields(
|
||||||
context, base_core.NETWORK, data, result)
|
context, base_core.NETWORK, base_core.EVENT_CREATE, data, result)
|
||||||
|
|
||||||
process_update_network = process_create_network
|
def process_update_network(self, context, data, result):
|
||||||
|
self.core_ext_handler.process_fields(
|
||||||
|
context, base_core.NETWORK, base_core.EVENT_UPDATE, data, result)
|
||||||
|
|
||||||
def process_create_port(self, context, data, result):
|
def process_create_port(self, context, data, result):
|
||||||
self.core_ext_handler.process_fields(
|
self.core_ext_handler.process_fields(
|
||||||
context, base_core.PORT, data, result)
|
context, base_core.PORT, base_core.EVENT_UPDATE, data, result)
|
||||||
|
|
||||||
process_update_port = process_create_port
|
process_update_port = process_create_port
|
||||||
|
|
||||||
|
@ -38,7 +38,9 @@ class QoSPlugin(qos.QoSPluginBase):
|
|||||||
service parameters over ports and networks.
|
service parameters over ports and networks.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
supported_extension_aliases = ['qos', 'qos-bw-limit-direction']
|
supported_extension_aliases = ['qos',
|
||||||
|
'qos-bw-limit-direction',
|
||||||
|
'qos-default']
|
||||||
|
|
||||||
__native_pagination_support = True
|
__native_pagination_support = True
|
||||||
__native_sorting_support = True
|
__native_sorting_support = True
|
||||||
@ -299,7 +301,7 @@ class QoSPlugin(qos.QoSPluginBase):
|
|||||||
checker.check_bandwidth_rule_conflict(policy, rule_data)
|
checker.check_bandwidth_rule_conflict(policy, rule_data)
|
||||||
rule = rule_cls(context, qos_policy_id=policy_id, **rule_data)
|
rule = rule_cls(context, qos_policy_id=policy_id, **rule_data)
|
||||||
rule.create()
|
rule.create()
|
||||||
policy.reload_rules()
|
policy.obj_load_attr('rules')
|
||||||
self.validate_policy(context, policy)
|
self.validate_policy(context, policy)
|
||||||
self.driver_manager.call(qos_consts.UPDATE_POLICY_PRECOMMIT,
|
self.driver_manager.call(qos_consts.UPDATE_POLICY_PRECOMMIT,
|
||||||
context, policy)
|
context, policy)
|
||||||
@ -338,7 +340,7 @@ class QoSPlugin(qos.QoSPluginBase):
|
|||||||
rule = rule_cls(context, id=rule_id)
|
rule = rule_cls(context, id=rule_id)
|
||||||
rule.update_fields(rule_data, reset_changes=True)
|
rule.update_fields(rule_data, reset_changes=True)
|
||||||
rule.update()
|
rule.update()
|
||||||
policy.reload_rules()
|
policy.obj_load_attr('rules')
|
||||||
self.validate_policy(context, policy)
|
self.validate_policy(context, policy)
|
||||||
self.driver_manager.call(qos_consts.UPDATE_POLICY_PRECOMMIT,
|
self.driver_manager.call(qos_consts.UPDATE_POLICY_PRECOMMIT,
|
||||||
context, policy)
|
context, policy)
|
||||||
@ -366,7 +368,7 @@ class QoSPlugin(qos.QoSPluginBase):
|
|||||||
policy = self._get_policy_obj(context, policy_id)
|
policy = self._get_policy_obj(context, policy_id)
|
||||||
rule = policy.get_rule_by_id(rule_id)
|
rule = policy.get_rule_by_id(rule_id)
|
||||||
rule.delete()
|
rule.delete()
|
||||||
policy.reload_rules()
|
policy.obj_load_attr('rules')
|
||||||
self.driver_manager.call(qos_consts.UPDATE_POLICY_PRECOMMIT,
|
self.driver_manager.call(qos_consts.UPDATE_POLICY_PRECOMMIT,
|
||||||
context, policy)
|
context, policy)
|
||||||
|
|
||||||
|
@ -132,12 +132,14 @@ class ClientFixture(fixtures.Fixture):
|
|||||||
router=router_id, body=body)
|
router=router_id, body=body)
|
||||||
return router_interface_info
|
return router_interface_info
|
||||||
|
|
||||||
def create_qos_policy(self, tenant_id, name, description, shared):
|
def create_qos_policy(self, tenant_id, name, description, shared,
|
||||||
|
is_default):
|
||||||
policy = self.client.create_qos_policy(
|
policy = self.client.create_qos_policy(
|
||||||
body={'policy': {'name': name,
|
body={'policy': {'name': name,
|
||||||
'description': description,
|
'description': description,
|
||||||
'shared': shared,
|
'shared': shared,
|
||||||
'tenant_id': tenant_id}})
|
'tenant_id': tenant_id,
|
||||||
|
'is_default': is_default}})
|
||||||
|
|
||||||
def detach_and_delete_policy():
|
def detach_and_delete_policy():
|
||||||
qos_policy_id = policy['policy']['id']
|
qos_policy_id = policy['policy']['id']
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
import functools
|
import functools
|
||||||
|
|
||||||
from neutron_lib import constants
|
from neutron_lib import constants
|
||||||
|
from neutronclient.common import exceptions
|
||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
|
|
||||||
from neutron.agent.linux import tc_lib
|
from neutron.agent.linux import tc_lib
|
||||||
@ -72,7 +73,7 @@ class BaseQoSRuleTestCase(object):
|
|||||||
def _create_qos_policy(self):
|
def _create_qos_policy(self):
|
||||||
return self.safe_client.create_qos_policy(
|
return self.safe_client.create_qos_policy(
|
||||||
self.tenant_id, 'fs_policy', 'Fullstack testing policy',
|
self.tenant_id, 'fs_policy', 'Fullstack testing policy',
|
||||||
shared='False')
|
shared='False', is_default='False')
|
||||||
|
|
||||||
def _prepare_vm_with_qos_policy(self, rule_add_functions):
|
def _prepare_vm_with_qos_policy(self, rule_add_functions):
|
||||||
qos_policy = self._create_qos_policy()
|
qos_policy = self._create_qos_policy()
|
||||||
@ -282,3 +283,60 @@ class TestQoSWithL2Population(base.BaseFullStackTestCase):
|
|||||||
rule_types = {t['type'] for t in res['rule_types']}
|
rule_types = {t['type'] for t in res['rule_types']}
|
||||||
expected_rules = set(ovs_drv.SUPPORTED_RULES)
|
expected_rules = set(ovs_drv.SUPPORTED_RULES)
|
||||||
self.assertEqual(expected_rules, rule_types)
|
self.assertEqual(expected_rules, rule_types)
|
||||||
|
|
||||||
|
|
||||||
|
class TestQoSPolicyIsDefault(base.BaseFullStackTestCase):
|
||||||
|
|
||||||
|
NAME = 'fs_policy'
|
||||||
|
DESCRIPTION = 'Fullstack testing policy'
|
||||||
|
SHARED = True
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
host_desc = [] # No need to register agents for this test case
|
||||||
|
env_desc = environment.EnvironmentDescription(qos=True)
|
||||||
|
env = environment.Environment(env_desc, host_desc)
|
||||||
|
super(TestQoSPolicyIsDefault, self).setUp(env)
|
||||||
|
|
||||||
|
def _create_qos_policy(self, project_id, is_default):
|
||||||
|
return self.safe_client.create_qos_policy(
|
||||||
|
project_id, self.NAME, self.DESCRIPTION, shared=self.SHARED,
|
||||||
|
is_default=is_default)
|
||||||
|
|
||||||
|
def _update_qos_policy(self, qos_policy_id, is_default):
|
||||||
|
return self.client.update_qos_policy(
|
||||||
|
qos_policy_id, body={'policy': {'is_default': is_default}})
|
||||||
|
|
||||||
|
def test_create_one_default_qos_policy_per_project(self):
|
||||||
|
project_ids = [uuidutils.generate_uuid(), uuidutils.generate_uuid()]
|
||||||
|
for project_id in project_ids:
|
||||||
|
qos_policy = self._create_qos_policy(project_id, True)
|
||||||
|
self.assertTrue(qos_policy['is_default'])
|
||||||
|
self.assertEqual(project_id, qos_policy['project_id'])
|
||||||
|
qos_policy = self._create_qos_policy(project_id, False)
|
||||||
|
self.assertFalse(qos_policy['is_default'])
|
||||||
|
self.assertEqual(project_id, qos_policy['project_id'])
|
||||||
|
|
||||||
|
def test_create_two_default_qos_policies_per_project(self):
|
||||||
|
project_id = uuidutils.generate_uuid()
|
||||||
|
qos_policy = self._create_qos_policy(project_id, True)
|
||||||
|
self.assertTrue(qos_policy['is_default'])
|
||||||
|
self.assertEqual(project_id, qos_policy['project_id'])
|
||||||
|
self.assertRaises(exceptions.Conflict,
|
||||||
|
self._create_qos_policy, project_id, True)
|
||||||
|
|
||||||
|
def test_update_default_status(self):
|
||||||
|
project_ids = [uuidutils.generate_uuid(), uuidutils.generate_uuid()]
|
||||||
|
for project_id in project_ids:
|
||||||
|
qos_policy = self._create_qos_policy(project_id, True)
|
||||||
|
self.assertTrue(qos_policy['is_default'])
|
||||||
|
qos_policy = self._update_qos_policy(qos_policy['id'], False)
|
||||||
|
self.assertTrue(qos_policy['policy']['is_default'])
|
||||||
|
|
||||||
|
def test_update_default_status_conflict(self):
|
||||||
|
project_id = uuidutils.generate_uuid()
|
||||||
|
qos_policy_1 = self._create_qos_policy(project_id, True)
|
||||||
|
self.assertTrue(qos_policy_1['is_default'])
|
||||||
|
qos_policy_2 = self._create_qos_policy(project_id, False)
|
||||||
|
self.assertFalse(qos_policy_2['is_default'])
|
||||||
|
self.assertRaises(exceptions.Conflict,
|
||||||
|
self._update_qos_policy, qos_policy_2['id'], True)
|
||||||
|
@ -82,7 +82,8 @@ class QosTestJSON(base.BaseAdminNetworkTest):
|
|||||||
def test_policy_update(self):
|
def test_policy_update(self):
|
||||||
policy = self.create_qos_policy(name='test-policy',
|
policy = self.create_qos_policy(name='test-policy',
|
||||||
description='',
|
description='',
|
||||||
shared=False)
|
shared=False,
|
||||||
|
tenant_id=self.admin_client.tenant_id)
|
||||||
self.admin_client.update_qos_policy(policy['id'],
|
self.admin_client.update_qos_policy(policy['id'],
|
||||||
description='test policy desc2',
|
description='test policy desc2',
|
||||||
shared=True)
|
shared=True)
|
||||||
@ -119,7 +120,8 @@ class QosTestJSON(base.BaseAdminNetworkTest):
|
|||||||
def test_shared_policy_update(self):
|
def test_shared_policy_update(self):
|
||||||
policy = self.create_qos_policy(name='test-policy',
|
policy = self.create_qos_policy(name='test-policy',
|
||||||
description='',
|
description='',
|
||||||
shared=True)
|
shared=True,
|
||||||
|
tenant_id=self.admin_client.tenant_id)
|
||||||
|
|
||||||
self.admin_client.update_qos_policy(policy['id'],
|
self.admin_client.update_qos_policy(policy['id'],
|
||||||
description='test policy desc2')
|
description='test policy desc2')
|
||||||
@ -606,7 +608,8 @@ class RbacSharedQosPoliciesTest(base.BaseAdminNetworkTest):
|
|||||||
def test_policy_sharing_with_wildcard(self):
|
def test_policy_sharing_with_wildcard(self):
|
||||||
qos_pol = self.create_qos_policy(
|
qos_pol = self.create_qos_policy(
|
||||||
name=data_utils.rand_name('test-policy'),
|
name=data_utils.rand_name('test-policy'),
|
||||||
description='test-shared-policy', shared=False)
|
description='test-shared-policy', shared=False,
|
||||||
|
tenant_id=self.admin_client.tenant_id)
|
||||||
self.assertNotIn(qos_pol, self.client2.list_qos_policies()['policies'])
|
self.assertNotIn(qos_pol, self.client2.list_qos_policies()['policies'])
|
||||||
|
|
||||||
# test update shared False -> True
|
# test update shared False -> True
|
||||||
|
@ -19,6 +19,7 @@ from neutron_lib import context
|
|||||||
from neutron.common import exceptions as n_exc
|
from neutron.common import exceptions as n_exc
|
||||||
from neutron.core_extensions import base as base_core
|
from neutron.core_extensions import base as base_core
|
||||||
from neutron.core_extensions import qos as qos_core
|
from neutron.core_extensions import qos as qos_core
|
||||||
|
from neutron.objects.qos import policy
|
||||||
from neutron.plugins.common import constants as plugin_constants
|
from neutron.plugins.common import constants as plugin_constants
|
||||||
from neutron.services.qos import qos_consts
|
from neutron.services.qos import qos_consts
|
||||||
from neutron.tests import base
|
from neutron.tests import base
|
||||||
@ -41,7 +42,7 @@ class QosCoreResourceExtensionTestCase(base.BaseTestCase):
|
|||||||
|
|
||||||
def test_process_fields_no_qos_policy_id(self):
|
def test_process_fields_no_qos_policy_id(self):
|
||||||
self.core_extension.process_fields(
|
self.core_extension.process_fields(
|
||||||
self.context, base_core.PORT, {}, None)
|
self.context, base_core.PORT, mock.ANY, {}, None)
|
||||||
self.assertFalse(self.policy_m.called)
|
self.assertFalse(self.policy_m.called)
|
||||||
|
|
||||||
def _mock_plugin_loaded(self, plugin_loaded):
|
def _mock_plugin_loaded(self, plugin_loaded):
|
||||||
@ -54,7 +55,7 @@ class QosCoreResourceExtensionTestCase(base.BaseTestCase):
|
|||||||
def test_process_fields_no_qos_plugin_loaded(self):
|
def test_process_fields_no_qos_plugin_loaded(self):
|
||||||
with self._mock_plugin_loaded(False):
|
with self._mock_plugin_loaded(False):
|
||||||
self.core_extension.process_fields(
|
self.core_extension.process_fields(
|
||||||
self.context, base_core.PORT,
|
self.context, base_core.PORT, mock.ANY,
|
||||||
{qos_consts.QOS_POLICY_ID: None}, None)
|
{qos_consts.QOS_POLICY_ID: None}, None)
|
||||||
self.assertFalse(self.policy_m.called)
|
self.assertFalse(self.policy_m.called)
|
||||||
|
|
||||||
@ -66,7 +67,7 @@ class QosCoreResourceExtensionTestCase(base.BaseTestCase):
|
|||||||
qos_policy = mock.MagicMock()
|
qos_policy = mock.MagicMock()
|
||||||
self.policy_m.get_object = mock.Mock(return_value=qos_policy)
|
self.policy_m.get_object = mock.Mock(return_value=qos_policy)
|
||||||
self.core_extension.process_fields(
|
self.core_extension.process_fields(
|
||||||
self.context, base_core.PORT,
|
self.context, base_core.PORT, base_core.EVENT_UPDATE,
|
||||||
{qos_consts.QOS_POLICY_ID: qos_policy_id},
|
{qos_consts.QOS_POLICY_ID: qos_policy_id},
|
||||||
actual_port)
|
actual_port)
|
||||||
|
|
||||||
@ -85,7 +86,7 @@ class QosCoreResourceExtensionTestCase(base.BaseTestCase):
|
|||||||
new_qos_policy = mock.MagicMock()
|
new_qos_policy = mock.MagicMock()
|
||||||
self.policy_m.get_object = mock.Mock(return_value=new_qos_policy)
|
self.policy_m.get_object = mock.Mock(return_value=new_qos_policy)
|
||||||
self.core_extension.process_fields(
|
self.core_extension.process_fields(
|
||||||
self.context, base_core.PORT,
|
self.context, base_core.PORT, base_core.EVENT_UPDATE,
|
||||||
{qos_consts.QOS_POLICY_ID: qos_policy2_id},
|
{qos_consts.QOS_POLICY_ID: qos_policy2_id},
|
||||||
actual_port)
|
actual_port)
|
||||||
|
|
||||||
@ -105,7 +106,7 @@ class QosCoreResourceExtensionTestCase(base.BaseTestCase):
|
|||||||
new_qos_policy = mock.MagicMock()
|
new_qos_policy = mock.MagicMock()
|
||||||
self.policy_m.get_object = mock.Mock(return_value=new_qos_policy)
|
self.policy_m.get_object = mock.Mock(return_value=new_qos_policy)
|
||||||
self.core_extension.process_fields(
|
self.core_extension.process_fields(
|
||||||
self.context, base_core.PORT,
|
self.context, base_core.PORT, base_core.EVENT_UPDATE,
|
||||||
{qos_consts.QOS_POLICY_ID: None},
|
{qos_consts.QOS_POLICY_ID: None},
|
||||||
actual_port)
|
actual_port)
|
||||||
|
|
||||||
@ -125,7 +126,7 @@ class QosCoreResourceExtensionTestCase(base.BaseTestCase):
|
|||||||
self.policy_m.get_port_policy = mock.Mock(
|
self.policy_m.get_port_policy = mock.Mock(
|
||||||
return_value=old_qos_policy)
|
return_value=old_qos_policy)
|
||||||
self.core_extension.process_fields(
|
self.core_extension.process_fields(
|
||||||
context, base_core.PORT,
|
context, base_core.PORT, base_core.EVENT_UPDATE,
|
||||||
{qos_consts.QOS_POLICY_ID: None},
|
{qos_consts.QOS_POLICY_ID: None},
|
||||||
actual_port)
|
actual_port)
|
||||||
|
|
||||||
@ -157,7 +158,7 @@ class QosCoreResourceExtensionTestCase(base.BaseTestCase):
|
|||||||
shared=False,
|
shared=False,
|
||||||
policy_tenant_id=self.context.tenant_id)
|
policy_tenant_id=self.context.tenant_id)
|
||||||
|
|
||||||
def test_process_resource_network_updated_no_policy(self):
|
def test_process_resource_update_network_updated_no_policy(self):
|
||||||
with self._mock_plugin_loaded(True):
|
with self._mock_plugin_loaded(True):
|
||||||
network_id = mock.Mock()
|
network_id = mock.Mock()
|
||||||
qos_policy_id = mock.Mock()
|
qos_policy_id = mock.Mock()
|
||||||
@ -169,14 +170,14 @@ class QosCoreResourceExtensionTestCase(base.BaseTestCase):
|
|||||||
new_qos_policy = mock.MagicMock()
|
new_qos_policy = mock.MagicMock()
|
||||||
self.policy_m.get_object = mock.Mock(return_value=new_qos_policy)
|
self.policy_m.get_object = mock.Mock(return_value=new_qos_policy)
|
||||||
self.core_extension.process_fields(
|
self.core_extension.process_fields(
|
||||||
self.context, base_core.NETWORK,
|
self.context, base_core.NETWORK, base_core.EVENT_UPDATE,
|
||||||
{qos_consts.QOS_POLICY_ID: None},
|
{qos_consts.QOS_POLICY_ID: None},
|
||||||
actual_network)
|
actual_network)
|
||||||
|
|
||||||
old_qos_policy.detach_network.assert_called_once_with(network_id)
|
old_qos_policy.detach_network.assert_called_once_with(network_id)
|
||||||
self.assertIsNone(actual_network['qos_policy_id'])
|
self.assertIsNone(actual_network['qos_policy_id'])
|
||||||
|
|
||||||
def test_process_fields_network_new_policy(self):
|
def test_process_fields_update_network_new_policy(self):
|
||||||
with self._mock_plugin_loaded(True):
|
with self._mock_plugin_loaded(True):
|
||||||
qos_policy_id = mock.Mock()
|
qos_policy_id = mock.Mock()
|
||||||
actual_network = {'id': mock.Mock(),
|
actual_network = {'id': mock.Mock(),
|
||||||
@ -184,13 +185,13 @@ class QosCoreResourceExtensionTestCase(base.BaseTestCase):
|
|||||||
qos_policy = mock.MagicMock()
|
qos_policy = mock.MagicMock()
|
||||||
self.policy_m.get_object = mock.Mock(return_value=qos_policy)
|
self.policy_m.get_object = mock.Mock(return_value=qos_policy)
|
||||||
self.core_extension.process_fields(
|
self.core_extension.process_fields(
|
||||||
self.context, base_core.NETWORK,
|
self.context, base_core.NETWORK, base_core.EVENT_UPDATE,
|
||||||
{qos_consts.QOS_POLICY_ID: qos_policy_id}, actual_network)
|
{qos_consts.QOS_POLICY_ID: qos_policy_id}, actual_network)
|
||||||
|
|
||||||
qos_policy.attach_network.assert_called_once_with(
|
qos_policy.attach_network.assert_called_once_with(
|
||||||
actual_network['id'])
|
actual_network['id'])
|
||||||
|
|
||||||
def test_process_fields_network_updated_policy(self):
|
def test_process_fields_update_network_updated_policy(self):
|
||||||
with self._mock_plugin_loaded(True):
|
with self._mock_plugin_loaded(True):
|
||||||
qos_policy_id = mock.Mock()
|
qos_policy_id = mock.Mock()
|
||||||
network_id = mock.Mock()
|
network_id = mock.Mock()
|
||||||
@ -202,7 +203,7 @@ class QosCoreResourceExtensionTestCase(base.BaseTestCase):
|
|||||||
new_qos_policy = mock.MagicMock()
|
new_qos_policy = mock.MagicMock()
|
||||||
self.policy_m.get_object = mock.Mock(return_value=new_qos_policy)
|
self.policy_m.get_object = mock.Mock(return_value=new_qos_policy)
|
||||||
self.core_extension.process_fields(
|
self.core_extension.process_fields(
|
||||||
self.context, base_core.NETWORK,
|
self.context, base_core.NETWORK, base_core.EVENT_UPDATE,
|
||||||
{qos_consts.QOS_POLICY_ID: qos_policy_id}, actual_network)
|
{qos_consts.QOS_POLICY_ID: qos_policy_id}, actual_network)
|
||||||
|
|
||||||
old_qos_policy.detach_network.assert_called_once_with(network_id)
|
old_qos_policy.detach_network.assert_called_once_with(network_id)
|
||||||
@ -220,12 +221,12 @@ class QosCoreResourceExtensionTestCase(base.BaseTestCase):
|
|||||||
old_qos_policy.tenant_id = policy_tenant_id
|
old_qos_policy.tenant_id = policy_tenant_id
|
||||||
self.policy_m.get_network_policy.return_value = old_qos_policy
|
self.policy_m.get_network_policy.return_value = old_qos_policy
|
||||||
self.core_extension.process_fields(
|
self.core_extension.process_fields(
|
||||||
context, base_core.NETWORK,
|
context, base_core.NETWORK, base_core.EVENT_UPDATE,
|
||||||
{qos_consts.QOS_POLICY_ID: None}, actual_network)
|
{qos_consts.QOS_POLICY_ID: None}, actual_network)
|
||||||
|
|
||||||
old_qos_policy.detach_network.assert_called_once_with(network_id)
|
old_qos_policy.detach_network.assert_called_once_with(network_id)
|
||||||
|
|
||||||
def test_process_fields_network_updated_remove_shared_policy(self):
|
def test_process_fields_update_network_updated_remove_shared_policy(self):
|
||||||
self._process_network_updated_policy(
|
self._process_network_updated_policy(
|
||||||
context=self.non_admin_context,
|
context=self.non_admin_context,
|
||||||
shared=True,
|
shared=True,
|
||||||
@ -237,13 +238,13 @@ class QosCoreResourceExtensionTestCase(base.BaseTestCase):
|
|||||||
shared=True,
|
shared=True,
|
||||||
policy_tenant_id=self.non_admin_context.tenant_id)
|
policy_tenant_id=self.non_admin_context.tenant_id)
|
||||||
|
|
||||||
def test_process_fields_network_updated_admin_remove_provided_policy(self):
|
def test_process_fields_update_network_admin_remove_provided_policy(self):
|
||||||
self._process_network_updated_policy(
|
self._process_network_updated_policy(
|
||||||
context=self.context,
|
context=self.context,
|
||||||
shared=True,
|
shared=True,
|
||||||
policy_tenant_id=self.non_admin_context.tenant_id)
|
policy_tenant_id=self.non_admin_context.tenant_id)
|
||||||
|
|
||||||
def test_process_fields_network_updated_remove_provided_policy(self):
|
def test_process_fields_update_network_remove_provided_policy(self):
|
||||||
self.policy_m.is_accessible.return_value = False
|
self.policy_m.is_accessible.return_value = False
|
||||||
self.assertRaises(n_exc.PolicyRemoveAuthorizationError,
|
self.assertRaises(n_exc.PolicyRemoveAuthorizationError,
|
||||||
self._process_network_updated_policy,
|
self._process_network_updated_policy,
|
||||||
@ -251,6 +252,58 @@ class QosCoreResourceExtensionTestCase(base.BaseTestCase):
|
|||||||
shared=False,
|
shared=False,
|
||||||
policy_tenant_id=self.context.tenant_id)
|
policy_tenant_id=self.context.tenant_id)
|
||||||
|
|
||||||
|
def test_process_fields_create_network(self):
|
||||||
|
with self._mock_plugin_loaded(True):
|
||||||
|
qos_policy_id = mock.Mock()
|
||||||
|
network_id = mock.Mock()
|
||||||
|
actual_network = {'id': network_id,
|
||||||
|
qos_consts.QOS_POLICY_ID: qos_policy_id}
|
||||||
|
self.policy_m.get_network_policy = mock.Mock(
|
||||||
|
return_value=qos_policy_id)
|
||||||
|
qos_policy = mock.MagicMock()
|
||||||
|
self.policy_m.get_object = mock.Mock(return_value=qos_policy)
|
||||||
|
self.core_extension.process_fields(
|
||||||
|
self.context, base_core.NETWORK, base_core.EVENT_CREATE,
|
||||||
|
actual_network, actual_network)
|
||||||
|
qos_policy.attach_network.assert_called_once_with(network_id)
|
||||||
|
|
||||||
|
def test_process_fields_create_network_no_policy(self):
|
||||||
|
with self._mock_plugin_loaded(True):
|
||||||
|
project_id = mock.Mock()
|
||||||
|
network_id = mock.Mock()
|
||||||
|
actual_network = {'project_id': project_id,
|
||||||
|
'id': network_id,
|
||||||
|
qos_consts.QOS_POLICY_ID: None}
|
||||||
|
qos_policy_id = mock.Mock()
|
||||||
|
qos_policy = mock.MagicMock()
|
||||||
|
with mock.patch.object(policy.QosPolicyDefault, "get_object",
|
||||||
|
return_value=qos_policy_id) as mock_get_default_policy_id:
|
||||||
|
self.policy_m.get_object = mock.Mock(return_value=qos_policy)
|
||||||
|
self.core_extension.process_fields(
|
||||||
|
self.context, base_core.NETWORK, base_core.EVENT_CREATE,
|
||||||
|
actual_network, actual_network)
|
||||||
|
qos_policy.attach_network.assert_called_once_with(network_id)
|
||||||
|
mock_get_default_policy_id.assert_called_once_with(
|
||||||
|
self.context, project_id=project_id)
|
||||||
|
|
||||||
|
def test_process_fields_create_network_no_default_policy(self):
|
||||||
|
with self._mock_plugin_loaded(True):
|
||||||
|
project_id = mock.Mock()
|
||||||
|
network_id = mock.Mock()
|
||||||
|
actual_network = {'project_id': project_id,
|
||||||
|
'id': network_id,
|
||||||
|
qos_consts.QOS_POLICY_ID: None}
|
||||||
|
qos_policy = mock.MagicMock()
|
||||||
|
with mock.patch.object(policy.QosPolicyDefault, "get_object",
|
||||||
|
return_value=None) as mock_get_default_policy_id:
|
||||||
|
self.policy_m.get_object = mock.Mock(return_value=qos_policy)
|
||||||
|
self.core_extension.process_fields(
|
||||||
|
self.context, base_core.NETWORK, base_core.EVENT_CREATE,
|
||||||
|
actual_network, actual_network)
|
||||||
|
qos_policy.attach_network.assert_not_called()
|
||||||
|
mock_get_default_policy_id.assert_called_once_with(
|
||||||
|
self.context, project_id=project_id)
|
||||||
|
|
||||||
def test_extract_fields_plugin_not_loaded(self):
|
def test_extract_fields_plugin_not_loaded(self):
|
||||||
with self._mock_plugin_loaded(False):
|
with self._mock_plugin_loaded(False):
|
||||||
fields = self.core_extension.extract_fields(None, None)
|
fields = self.core_extension.extract_fields(None, None)
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
|
from oslo_utils import uuidutils
|
||||||
from oslo_versionedobjects import exception
|
from oslo_versionedobjects import exception
|
||||||
import testtools
|
import testtools
|
||||||
|
|
||||||
@ -39,6 +40,8 @@ class QosPolicyObjectTestCase(test_base.BaseObjectIfaceTestCase):
|
|||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(QosPolicyObjectTestCase, self).setUp()
|
super(QosPolicyObjectTestCase, self).setUp()
|
||||||
|
mock.patch.object(policy.QosPolicy, 'get_default').start()
|
||||||
|
|
||||||
# qos_policy_ids will be incorrect, but we don't care in this test
|
# qos_policy_ids will be incorrect, but we don't care in this test
|
||||||
self.db_qos_bandwidth_rules = [
|
self.db_qos_bandwidth_rules = [
|
||||||
self.get_random_db_fields(rule.QosBandwidthLimitRule)
|
self.get_random_db_fields(rule.QosBandwidthLimitRule)
|
||||||
@ -98,18 +101,16 @@ class QosPolicyObjectTestCase(test_base.BaseObjectIfaceTestCase):
|
|||||||
|
|
||||||
def test_get_object(self):
|
def test_get_object(self):
|
||||||
admin_context = self.context.elevated()
|
admin_context = self.context.elevated()
|
||||||
with mock.patch.object(
|
with mock.patch.object(db_api, 'get_object',
|
||||||
db_api, 'get_object',
|
return_value=self.db_objs[0]) as get_object_mock, \
|
||||||
return_value=self.db_objs[0]) as get_object_mock:
|
mock.patch.object(self.context, 'elevated',
|
||||||
with mock.patch.object(self.context,
|
return_value=admin_context) as context_mock:
|
||||||
'elevated',
|
obj = self._test_class.get_object(self.context, id='fake_id')
|
||||||
return_value=admin_context) as context_mock:
|
self.assertTrue(self._is_test_class(obj))
|
||||||
obj = self._test_class.get_object(self.context, id='fake_id')
|
self._check_equal(self.objs[0], obj)
|
||||||
self.assertTrue(self._is_test_class(obj))
|
context_mock.assert_called_once_with()
|
||||||
self._check_equal(self.objs[0], obj)
|
get_object_mock.assert_called_once_with(
|
||||||
context_mock.assert_called_once_with()
|
admin_context, self._test_class.db_model, id='fake_id')
|
||||||
get_object_mock.assert_called_once_with(
|
|
||||||
admin_context, self._test_class.db_model, id='fake_id')
|
|
||||||
|
|
||||||
def test_to_dict_makes_primitive_field_value(self):
|
def test_to_dict_makes_primitive_field_value(self):
|
||||||
# is_shared_with_tenant requires DB
|
# is_shared_with_tenant requires DB
|
||||||
@ -149,7 +150,7 @@ class QosPolicyDbObjectTestCase(test_base.BaseDbObjectTestCase,
|
|||||||
rules.append(rule_obj)
|
rules.append(rule_obj)
|
||||||
|
|
||||||
if reload_rules:
|
if reload_rules:
|
||||||
policy_obj.reload_rules()
|
policy_obj.obj_load_attr('rules')
|
||||||
return policy_obj, rules
|
return policy_obj, rules
|
||||||
|
|
||||||
def test_attach_network_get_network_policy(self):
|
def test_attach_network_get_network_policy(self):
|
||||||
@ -303,6 +304,42 @@ class QosPolicyDbObjectTestCase(test_base.BaseDbObjectTestCase,
|
|||||||
self.assertRaises(n_exc.NetworkQosBindingNotFound,
|
self.assertRaises(n_exc.NetworkQosBindingNotFound,
|
||||||
policy_obj.detach_network, self._network_id)
|
policy_obj.detach_network, self._network_id)
|
||||||
|
|
||||||
|
@mock.patch.object(policy.QosPolicyDefault, 'create')
|
||||||
|
def test_set_default_no_default_policy_exists(self, mock_default_create):
|
||||||
|
obj = self._create_test_policy()
|
||||||
|
with mock.patch.object(obj, 'get_default', return_value=None):
|
||||||
|
obj.set_default()
|
||||||
|
mock_default_create.assert_called_once_with()
|
||||||
|
|
||||||
|
def test_set_default_default_policy_exists(self):
|
||||||
|
obj = self._create_test_policy()
|
||||||
|
with mock.patch.object(obj, 'get_default', return_value=mock.Mock()):
|
||||||
|
self.assertRaises(n_exc.QoSPolicyDefaultAlreadyExists,
|
||||||
|
obj.set_default)
|
||||||
|
|
||||||
|
def test_set_default_is_default_policy(self):
|
||||||
|
obj = self._create_test_policy()
|
||||||
|
with mock.patch.object(obj, 'get_default', return_value=obj.id), \
|
||||||
|
mock.patch.object(obj, 'set_default'):
|
||||||
|
obj.set_default()
|
||||||
|
|
||||||
|
@mock.patch.object(policy.QosPolicyDefault, 'get_object')
|
||||||
|
@mock.patch.object(policy.QosPolicyDefault, 'delete')
|
||||||
|
def test_unset_default_default_policy_exists(self, mock_default_delete,
|
||||||
|
mock_default_get):
|
||||||
|
obj = self._create_test_policy()
|
||||||
|
with mock.patch.object(obj, 'get_default', return_value=obj.id):
|
||||||
|
mock_default_get.return_value = policy.QosPolicyDefault()
|
||||||
|
obj.unset_default()
|
||||||
|
mock_default_get.assert_called_once_with(obj.obj_context,
|
||||||
|
project_id=obj.project_id)
|
||||||
|
mock_default_delete.assert_called_once_with()
|
||||||
|
|
||||||
|
def test_unset_default_no_default_policy_exists(self):
|
||||||
|
obj = self._create_test_policy()
|
||||||
|
with mock.patch.object(obj, 'get_default', return_value=None):
|
||||||
|
obj.unset_default()
|
||||||
|
|
||||||
def test_synthetic_rule_fields(self):
|
def test_synthetic_rule_fields(self):
|
||||||
policy_obj, rule_obj = self._create_test_policy_with_rules(
|
policy_obj, rule_obj = self._create_test_policy_with_rules(
|
||||||
[qos_consts.RULE_TYPE_BANDWIDTH_LIMIT])
|
[qos_consts.RULE_TYPE_BANDWIDTH_LIMIT])
|
||||||
@ -363,9 +400,16 @@ class QosPolicyDbObjectTestCase(test_base.BaseDbObjectTestCase,
|
|||||||
[qos_consts.RULE_TYPE_BANDWIDTH_LIMIT])
|
[qos_consts.RULE_TYPE_BANDWIDTH_LIMIT])
|
||||||
self.assertEqual([], policy_obj.rules)
|
self.assertEqual([], policy_obj.rules)
|
||||||
|
|
||||||
policy_obj.reload_rules()
|
policy_obj._reload_rules()
|
||||||
self.assertEqual(rule_obj, policy_obj.rules)
|
self.assertEqual(rule_obj, policy_obj.rules)
|
||||||
|
|
||||||
|
def test_reload_is_default(self):
|
||||||
|
policy_obj = self._create_test_policy()
|
||||||
|
self.assertFalse(policy_obj.is_default)
|
||||||
|
policy_obj.set_default()
|
||||||
|
policy_obj._reload_is_default()
|
||||||
|
self.assertTrue(policy_obj.is_default)
|
||||||
|
|
||||||
def test_get_bound_tenant_ids_returns_set_of_tenant_ids(self):
|
def test_get_bound_tenant_ids_returns_set_of_tenant_ids(self):
|
||||||
obj = self._create_test_policy()
|
obj = self._create_test_policy()
|
||||||
obj.attach_port(self._port['id'])
|
obj.attach_port(self._port['id'])
|
||||||
@ -475,13 +519,23 @@ class QosPolicyDbObjectTestCase(test_base.BaseDbObjectTestCase,
|
|||||||
self.assertIn(rule_objs[1], policy_obj_v1_4.rules)
|
self.assertIn(rule_objs[1], policy_obj_v1_4.rules)
|
||||||
self.assertIn(rule_objs[2], policy_obj_v1_4.rules)
|
self.assertIn(rule_objs[2], policy_obj_v1_4.rules)
|
||||||
|
|
||||||
def test_filter_by_shared(self):
|
def test_v1_6_to_v1_5_drops_is_default(self):
|
||||||
|
policy_new = self._create_test_policy()
|
||||||
|
|
||||||
|
policy_v1_5 = policy_new.obj_to_primitive(target_version='1.5')
|
||||||
|
self.assertNotIn('is_default', policy_v1_5['versioned_object.data'])
|
||||||
|
|
||||||
|
@mock.patch.object(policy.QosPolicy, 'unset_default')
|
||||||
|
def test_filter_by_shared(self, *mocks):
|
||||||
|
project_id = uuidutils.generate_uuid()
|
||||||
policy_obj = policy.QosPolicy(
|
policy_obj = policy.QosPolicy(
|
||||||
self.context, name='shared-policy', shared=True)
|
self.context, name='shared-policy', shared=True,
|
||||||
|
project_id=project_id, is_default=False)
|
||||||
policy_obj.create()
|
policy_obj.create()
|
||||||
|
|
||||||
policy_obj = policy.QosPolicy(
|
policy_obj = policy.QosPolicy(
|
||||||
self.context, name='private-policy', shared=False)
|
self.context, name='private-policy', shared=False,
|
||||||
|
project_id=project_id)
|
||||||
policy_obj.create()
|
policy_obj.create()
|
||||||
|
|
||||||
shared_policies = policy.QosPolicy.get_objects(
|
shared_policies = policy.QosPolicy.get_objects(
|
||||||
@ -499,3 +553,8 @@ class QosPolicyDbObjectTestCase(test_base.BaseDbObjectTestCase,
|
|||||||
# QoSPolicy currently cannot be loaded using constant queries number.
|
# QoSPolicy currently cannot be loaded using constant queries number.
|
||||||
# It can be reworked in follow-up patch.
|
# It can be reworked in follow-up patch.
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class QosPolicyDefaultObjectTestCase(test_base.BaseObjectIfaceTestCase):
|
||||||
|
|
||||||
|
_test_class = policy.QosPolicyDefault
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
from neutron_lib import constants
|
from neutron_lib import constants
|
||||||
|
|
||||||
|
from oslo_utils import uuidutils
|
||||||
from oslo_versionedobjects import exception
|
from oslo_versionedobjects import exception
|
||||||
|
|
||||||
from neutron.common import constants as n_const
|
from neutron.common import constants as n_const
|
||||||
@ -150,7 +151,8 @@ class QosBandwidthLimitRuleDbObjectTestCase(test_base.BaseDbObjectTestCase,
|
|||||||
for obj in self.db_objs:
|
for obj in self.db_objs:
|
||||||
generated_qos_policy_id = obj['qos_policy_id']
|
generated_qos_policy_id = obj['qos_policy_id']
|
||||||
policy_obj = policy.QosPolicy(self.context,
|
policy_obj = policy.QosPolicy(self.context,
|
||||||
id=generated_qos_policy_id)
|
id=generated_qos_policy_id,
|
||||||
|
project_id=uuidutils.generate_uuid())
|
||||||
policy_obj.create()
|
policy_obj.create()
|
||||||
|
|
||||||
|
|
||||||
@ -176,7 +178,8 @@ class QosDscpMarkingRuleDbObjectTestCase(test_base.BaseDbObjectTestCase,
|
|||||||
for obj in self.db_objs:
|
for obj in self.db_objs:
|
||||||
generated_qos_policy_id = obj['qos_policy_id']
|
generated_qos_policy_id = obj['qos_policy_id']
|
||||||
policy_obj = policy.QosPolicy(self.context,
|
policy_obj = policy.QosPolicy(self.context,
|
||||||
id=generated_qos_policy_id)
|
id=generated_qos_policy_id,
|
||||||
|
project_id=uuidutils.generate_uuid())
|
||||||
policy_obj.create()
|
policy_obj.create()
|
||||||
|
|
||||||
|
|
||||||
@ -203,5 +206,6 @@ class QosMinimumBandwidthRuleDbObjectTestCase(test_base.BaseDbObjectTestCase,
|
|||||||
for obj in self.db_objs:
|
for obj in self.db_objs:
|
||||||
generated_qos_policy_id = obj['qos_policy_id']
|
generated_qos_policy_id = obj['qos_policy_id']
|
||||||
policy_obj = policy.QosPolicy(self.context,
|
policy_obj = policy.QosPolicy(self.context,
|
||||||
id=generated_qos_policy_id)
|
id=generated_qos_policy_id,
|
||||||
|
project_id=uuidutils.generate_uuid())
|
||||||
policy_obj.create()
|
policy_obj.create()
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import mock
|
||||||
|
|
||||||
from neutron.objects import base as obj_base
|
from neutron.objects import base as obj_base
|
||||||
from neutron.objects import network
|
from neutron.objects import network
|
||||||
from neutron.objects.qos import policy
|
from neutron.objects.qos import policy
|
||||||
@ -90,7 +92,8 @@ class NetworkDbObjectTestCase(obj_test_base.BaseDbObjectTestCase,
|
|||||||
testlib_api.SqlTestCase):
|
testlib_api.SqlTestCase):
|
||||||
_test_class = network.Network
|
_test_class = network.Network
|
||||||
|
|
||||||
def test_qos_policy_id(self):
|
@mock.patch.object(policy.QosPolicy, 'unset_default')
|
||||||
|
def test_qos_policy_id(self, *mocks):
|
||||||
policy_obj = policy.QosPolicy(self.context)
|
policy_obj = policy.QosPolicy(self.context)
|
||||||
policy_obj.create()
|
policy_obj.create()
|
||||||
|
|
||||||
@ -116,7 +119,8 @@ class NetworkDbObjectTestCase(obj_test_base.BaseDbObjectTestCase,
|
|||||||
obj = network.Network.get_object(self.context, id=obj.id)
|
obj = network.Network.get_object(self.context, id=obj.id)
|
||||||
self.assertIsNone(obj.qos_policy_id)
|
self.assertIsNone(obj.qos_policy_id)
|
||||||
|
|
||||||
def test__attach_qos_policy(self):
|
@mock.patch.object(policy.QosPolicy, 'unset_default')
|
||||||
|
def test__attach_qos_policy(self, *mocks):
|
||||||
obj = self._make_object(self.obj_fields[0])
|
obj = self._make_object(self.obj_fields[0])
|
||||||
obj.create()
|
obj.create()
|
||||||
|
|
||||||
|
@ -66,7 +66,8 @@ object_data = {
|
|||||||
'QosDscpMarkingRule': '1.3-0313c6554b34fd10c753cb63d638256c',
|
'QosDscpMarkingRule': '1.3-0313c6554b34fd10c753cb63d638256c',
|
||||||
'QosMinimumBandwidthRule': '1.3-314c3419f4799067cc31cc319080adff',
|
'QosMinimumBandwidthRule': '1.3-314c3419f4799067cc31cc319080adff',
|
||||||
'QosRuleType': '1.2-e6fd08fcca152c339cbd5e9b94b1b8e7',
|
'QosRuleType': '1.2-e6fd08fcca152c339cbd5e9b94b1b8e7',
|
||||||
'QosPolicy': '1.5-50460f619c34428ec5651916e938e5a0',
|
'QosPolicy': '1.6-4adb0cde3102c10d8970ec9487fd7fe7',
|
||||||
|
'QosPolicyDefault': '1.0-59e5060eedb1f06dd0935a244d27d11c',
|
||||||
'Quota': '1.0-6bb6a0f1bd5d66a2134ffa1a61873097',
|
'Quota': '1.0-6bb6a0f1bd5d66a2134ffa1a61873097',
|
||||||
'QuotaUsage': '1.0-6fbf820368681aac7c5d664662605cf9',
|
'QuotaUsage': '1.0-6fbf820368681aac7c5d664662605cf9',
|
||||||
'Reservation': '1.0-49929fef8e82051660342eed51b48f2a',
|
'Reservation': '1.0-49929fef8e82051660342eed51b48f2a',
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import mock
|
||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
import testscenarios
|
import testscenarios
|
||||||
|
|
||||||
@ -262,7 +263,8 @@ class PortDbObjectTestCase(obj_test_base.BaseDbObjectTestCase,
|
|||||||
obj = ports.Port.get_object(self.context, id=obj.id)
|
obj = ports.Port.get_object(self.context, id=obj.id)
|
||||||
self.assertIn(sg2_id, obj.security_group_ids)
|
self.assertIn(sg2_id, obj.security_group_ids)
|
||||||
|
|
||||||
def test_qos_policy_id(self):
|
@mock.patch.object(policy.QosPolicy, 'unset_default')
|
||||||
|
def test_qos_policy_id(self, *mocks):
|
||||||
policy_obj = policy.QosPolicy(self.context)
|
policy_obj = policy.QosPolicy(self.context)
|
||||||
policy_obj.create()
|
policy_obj.create()
|
||||||
|
|
||||||
@ -288,7 +290,8 @@ class PortDbObjectTestCase(obj_test_base.BaseDbObjectTestCase,
|
|||||||
obj = ports.Port.get_object(self.context, id=obj.id)
|
obj = ports.Port.get_object(self.context, id=obj.id)
|
||||||
self.assertIsNone(obj.qos_policy_id)
|
self.assertIsNone(obj.qos_policy_id)
|
||||||
|
|
||||||
def test__attach_qos_policy(self):
|
@mock.patch.object(policy.QosPolicy, 'unset_default')
|
||||||
|
def test__attach_qos_policy(self, *mocks):
|
||||||
obj = self._make_object(self.obj_fields[0])
|
obj = self._make_object(self.obj_fields[0])
|
||||||
obj.create()
|
obj.create()
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
from neutron_lib import context
|
from neutron_lib import context
|
||||||
from neutron_lib.plugins import directory
|
from neutron_lib.plugins import directory
|
||||||
@ -39,13 +40,16 @@ class TestQosPlugin(base.BaseQosTestCase):
|
|||||||
mock.patch('neutron.objects.db.api.update_object').start()
|
mock.patch('neutron.objects.db.api.update_object').start()
|
||||||
mock.patch('neutron.objects.db.api.delete_object').start()
|
mock.patch('neutron.objects.db.api.delete_object').start()
|
||||||
mock.patch('neutron.objects.db.api.get_object').start()
|
mock.patch('neutron.objects.db.api.get_object').start()
|
||||||
mock.patch(
|
_mock_qos_load_attr = mock.patch(
|
||||||
'neutron.objects.qos.policy.QosPolicy.obj_load_attr').start()
|
'neutron.objects.qos.policy.QosPolicy.obj_load_attr')
|
||||||
|
self.mock_qos_load_attr = _mock_qos_load_attr.start()
|
||||||
# We don't use real models as per mocks above. We also need to mock-out
|
# We don't use real models as per mocks above. We also need to mock-out
|
||||||
# methods that work with real data types
|
# methods that work with real data types
|
||||||
mock.patch(
|
mock.patch(
|
||||||
'neutron.objects.base.NeutronDbObject.modify_fields_from_db'
|
'neutron.objects.base.NeutronDbObject.modify_fields_from_db'
|
||||||
).start()
|
).start()
|
||||||
|
mock.patch.object(policy_object.QosPolicy, 'unset_default').start()
|
||||||
|
mock.patch.object(policy_object.QosPolicy, 'set_default').start()
|
||||||
|
|
||||||
cfg.CONF.set_override("core_plugin", DB_PLUGIN_KLASS)
|
cfg.CONF.set_override("core_plugin", DB_PLUGIN_KLASS)
|
||||||
cfg.CONF.set_override("service_plugins", ["qos"])
|
cfg.CONF.set_override("service_plugins", ["qos"])
|
||||||
@ -67,7 +71,8 @@ class TestQosPlugin(base.BaseQosTestCase):
|
|||||||
'project_id': uuidutils.generate_uuid(),
|
'project_id': uuidutils.generate_uuid(),
|
||||||
'name': 'test-policy',
|
'name': 'test-policy',
|
||||||
'description': 'Test policy description',
|
'description': 'Test policy description',
|
||||||
'shared': True}}
|
'shared': True,
|
||||||
|
'is_default': False}}
|
||||||
|
|
||||||
self.rule_data = {
|
self.rule_data = {
|
||||||
'bandwidth_limit_rule': {'id': uuidutils.generate_uuid(),
|
'bandwidth_limit_rule': {'id': uuidutils.generate_uuid(),
|
||||||
@ -339,13 +344,15 @@ class TestQosPlugin(base.BaseQosTestCase):
|
|||||||
'tenant_id': project_id,
|
'tenant_id': project_id,
|
||||||
'name': 'test-policy',
|
'name': 'test-policy',
|
||||||
'description': 'Test policy description',
|
'description': 'Test policy description',
|
||||||
'shared': True}}
|
'shared': True,
|
||||||
|
'is_default': False}}
|
||||||
|
|
||||||
policy_details = {'id': policy_id,
|
policy_details = {'id': policy_id,
|
||||||
'project_id': project_id,
|
'project_id': project_id,
|
||||||
'name': 'test-policy',
|
'name': 'test-policy',
|
||||||
'description': 'Test policy description',
|
'description': 'Test policy description',
|
||||||
'shared': True}
|
'shared': True,
|
||||||
|
'is_default': False}
|
||||||
|
|
||||||
with mock.patch('neutron.objects.qos.policy.QosPolicy') as QosMocked:
|
with mock.patch('neutron.objects.qos.policy.QosPolicy') as QosMocked:
|
||||||
self.qos_plugin.create_policy(self.ctxt, tenant_policy)
|
self.qos_plugin.create_policy(self.ctxt, tenant_policy)
|
||||||
@ -412,27 +419,23 @@ class TestQosPlugin(base.BaseQosTestCase):
|
|||||||
def test_create_policy_rule_check_rule_min_less_than_max(self):
|
def test_create_policy_rule_check_rule_min_less_than_max(self):
|
||||||
_policy = self._get_policy()
|
_policy = self._get_policy()
|
||||||
setattr(_policy, "rules", [self.rule])
|
setattr(_policy, "rules", [self.rule])
|
||||||
with mock.patch('neutron.objects.qos.rule.get_rules',
|
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
|
||||||
return_value=[self.rule]) as mock_get_rules, \
|
return_value=_policy) as mock_qos_get_obj:
|
||||||
mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
|
|
||||||
return_value=_policy) as mock_qos_get_obj:
|
|
||||||
self.qos_plugin.create_policy_minimum_bandwidth_rule(
|
self.qos_plugin.create_policy_minimum_bandwidth_rule(
|
||||||
self.ctxt, _policy.id, self.rule_data)
|
self.ctxt, _policy.id, self.rule_data)
|
||||||
self._validate_driver_params('update_policy')
|
self._validate_driver_params('update_policy')
|
||||||
mock_get_rules.assert_called_once_with(self.ctxt, _policy.id)
|
self.mock_qos_load_attr.assert_called_once_with('rules')
|
||||||
mock_qos_get_obj.assert_called_once_with(self.ctxt, id=_policy.id)
|
mock_qos_get_obj.assert_called_once_with(self.ctxt, id=_policy.id)
|
||||||
|
|
||||||
def test_create_policy_rule_check_rule_max_more_than_min(self):
|
def test_create_policy_rule_check_rule_max_more_than_min(self):
|
||||||
_policy = self._get_policy()
|
_policy = self._get_policy()
|
||||||
setattr(_policy, "rules", [self.min_rule])
|
setattr(_policy, "rules", [self.min_rule])
|
||||||
with mock.patch('neutron.objects.qos.rule.get_rules',
|
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
|
||||||
return_value=[self.rule]) as mock_get_rules, \
|
return_value=_policy) as mock_qos_get_obj:
|
||||||
mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
|
|
||||||
return_value=_policy) as mock_qos_get_obj:
|
|
||||||
self.qos_plugin.create_policy_bandwidth_limit_rule(
|
self.qos_plugin.create_policy_bandwidth_limit_rule(
|
||||||
self.ctxt, _policy.id, self.rule_data)
|
self.ctxt, _policy.id, self.rule_data)
|
||||||
self._validate_driver_params('update_policy')
|
self._validate_driver_params('update_policy')
|
||||||
mock_get_rules.assert_called_once_with(self.ctxt, _policy.id)
|
self.mock_qos_load_attr.assert_called_once_with('rules')
|
||||||
mock_qos_get_obj.assert_called_once_with(self.ctxt, id=_policy.id)
|
mock_qos_get_obj.assert_called_once_with(self.ctxt, id=_policy.id)
|
||||||
|
|
||||||
def test_create_policy_rule_check_rule_bwlimit_less_than_minbw(self):
|
def test_create_policy_rule_check_rule_bwlimit_less_than_minbw(self):
|
||||||
@ -486,39 +489,32 @@ class TestQosPlugin(base.BaseQosTestCase):
|
|||||||
def test_update_policy_rule_check_rule_min_less_than_max(self):
|
def test_update_policy_rule_check_rule_min_less_than_max(self):
|
||||||
_policy = self._get_policy()
|
_policy = self._get_policy()
|
||||||
setattr(_policy, "rules", [self.rule])
|
setattr(_policy, "rules", [self.rule])
|
||||||
with mock.patch('neutron.objects.qos.rule.get_rules',
|
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
|
||||||
return_value=[self.rule]) as mock_get_rules, \
|
return_value=_policy):
|
||||||
mock.patch(
|
|
||||||
'neutron.objects.qos.policy.QosPolicy.get_object',
|
|
||||||
return_value=_policy):
|
|
||||||
self.qos_plugin.update_policy_bandwidth_limit_rule(
|
self.qos_plugin.update_policy_bandwidth_limit_rule(
|
||||||
self.ctxt, self.rule.id, self.policy.id, self.rule_data)
|
self.ctxt, self.rule.id, self.policy.id, self.rule_data)
|
||||||
mock_get_rules.assert_called_once_with(self.ctxt, _policy.id)
|
self.mock_qos_load_attr.assert_called_once_with('rules')
|
||||||
self._validate_driver_params('update_policy')
|
self._validate_driver_params('update_policy')
|
||||||
|
|
||||||
rules = [self.rule, self.min_rule]
|
rules = [self.rule, self.min_rule]
|
||||||
setattr(_policy, "rules", rules)
|
setattr(_policy, "rules", rules)
|
||||||
with mock.patch('neutron.objects.qos.rule.get_rules',
|
self.mock_qos_load_attr.reset_mock()
|
||||||
return_value=rules) as mock_get_rules, \
|
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
|
||||||
mock.patch(
|
return_value=_policy):
|
||||||
'neutron.objects.qos.policy.QosPolicy.get_object',
|
|
||||||
return_value=_policy):
|
|
||||||
self.qos_plugin.update_policy_minimum_bandwidth_rule(
|
self.qos_plugin.update_policy_minimum_bandwidth_rule(
|
||||||
self.ctxt, self.min_rule.id,
|
self.ctxt, self.min_rule.id,
|
||||||
self.policy.id, self.rule_data)
|
self.policy.id, self.rule_data)
|
||||||
mock_get_rules.assert_called_once_with(self.ctxt, _policy.id)
|
self.mock_qos_load_attr.assert_called_once_with('rules')
|
||||||
self._validate_driver_params('update_policy')
|
self._validate_driver_params('update_policy')
|
||||||
|
|
||||||
def test_update_policy_rule_check_rule_bwlimit_less_than_minbw(self):
|
def test_update_policy_rule_check_rule_bwlimit_less_than_minbw(self):
|
||||||
_policy = self._get_policy()
|
_policy = self._get_policy()
|
||||||
setattr(_policy, "rules", [self.rule])
|
setattr(_policy, "rules", [self.rule])
|
||||||
with mock.patch('neutron.objects.qos.rule.get_rules',
|
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
|
||||||
return_value=[self.rule]), mock.patch(
|
return_value=_policy):
|
||||||
'neutron.objects.qos.policy.QosPolicy.get_object',
|
|
||||||
return_value=_policy):
|
|
||||||
self.qos_plugin.update_policy_bandwidth_limit_rule(
|
self.qos_plugin.update_policy_bandwidth_limit_rule(
|
||||||
self.ctxt, self.rule.id, self.policy.id, self.rule_data)
|
self.ctxt, self.rule.id, self.policy.id, self.rule_data)
|
||||||
self.assertTrue(getattr(rule_object, "get_rules").called)
|
self.mock_qos_load_attr.assert_called_once_with('rules')
|
||||||
self._validate_driver_params('update_policy')
|
self._validate_driver_params('update_policy')
|
||||||
self.rule_data['minimum_bandwidth_rule']['min_kbps'] = 1000
|
self.rule_data['minimum_bandwidth_rule']['min_kbps'] = 1000
|
||||||
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
|
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
|
||||||
@ -532,13 +528,11 @@ class TestQosPlugin(base.BaseQosTestCase):
|
|||||||
def test_update_policy_rule_check_rule_minbw_gr_than_bwlimit(self):
|
def test_update_policy_rule_check_rule_minbw_gr_than_bwlimit(self):
|
||||||
_policy = self._get_policy()
|
_policy = self._get_policy()
|
||||||
setattr(_policy, "rules", [self.min_rule])
|
setattr(_policy, "rules", [self.min_rule])
|
||||||
with mock.patch('neutron.objects.qos.rule.get_rules',
|
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
|
||||||
return_value=[self.min_rule]), mock.patch(
|
return_value=_policy):
|
||||||
'neutron.objects.qos.policy.QosPolicy.get_object',
|
|
||||||
return_value=_policy):
|
|
||||||
self.qos_plugin.update_policy_minimum_bandwidth_rule(
|
self.qos_plugin.update_policy_minimum_bandwidth_rule(
|
||||||
self.ctxt, self.min_rule.id, self.policy.id, self.rule_data)
|
self.ctxt, self.min_rule.id, self.policy.id, self.rule_data)
|
||||||
self.assertTrue(getattr(rule_object, "get_rules").called)
|
self.mock_qos_load_attr.assert_called_once_with('rules')
|
||||||
self._validate_driver_params('update_policy')
|
self._validate_driver_params('update_policy')
|
||||||
self.rule_data['bandwidth_limit_rule']['max_kbps'] = 1
|
self.rule_data['bandwidth_limit_rule']['max_kbps'] = 1
|
||||||
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
|
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
|
||||||
|
@ -170,7 +170,8 @@ class TestRevisionPlugin(test_plugin.Ml2PluginV2TestCase):
|
|||||||
with self.port() as port:
|
with self.port() as port:
|
||||||
rev = port['port']['revision_number']
|
rev = port['port']['revision_number']
|
||||||
qos_plugin = directory.get_plugin('QOS')
|
qos_plugin = directory.get_plugin('QOS')
|
||||||
qos_policy = {'policy': {'name': "policy1",
|
qos_policy = {'policy': {'id': uuidutils.generate_uuid(),
|
||||||
|
'name': "policy1",
|
||||||
'project_id': uuidutils.generate_uuid()}}
|
'project_id': uuidutils.generate_uuid()}}
|
||||||
qos_obj = qos_plugin.create_policy(self.ctx, qos_policy)
|
qos_obj = qos_plugin.create_policy(self.ctx, qos_policy)
|
||||||
data = {'port': {'qos_policy_id': qos_obj['id']}}
|
data = {'port': {'qos_policy_id': qos_obj['id']}}
|
||||||
@ -182,7 +183,8 @@ class TestRevisionPlugin(test_plugin.Ml2PluginV2TestCase):
|
|||||||
with self.network() as network:
|
with self.network() as network:
|
||||||
rev = network['network']['revision_number']
|
rev = network['network']['revision_number']
|
||||||
qos_plugin = directory.get_plugin('QOS')
|
qos_plugin = directory.get_plugin('QOS')
|
||||||
qos_policy = {'policy': {'name': "policy1",
|
qos_policy = {'policy': {'id': uuidutils.generate_uuid(),
|
||||||
|
'name': "policy1",
|
||||||
'project_id': uuidutils.generate_uuid()}}
|
'project_id': uuidutils.generate_uuid()}}
|
||||||
qos_obj = qos_plugin.create_policy(self.ctx, qos_policy)
|
qos_obj = qos_plugin.create_policy(self.ctx, qos_policy)
|
||||||
data = {'network': {'qos_policy_id': qos_obj['id']}}
|
data = {'network': {'qos_policy_id': qos_obj['id']}}
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
prelude: >
|
||||||
|
Add 'default' behaviour to QoS policies
|
||||||
|
features:
|
||||||
|
- Neutron now supports having a default QoS policy in a project, assigned
|
||||||
|
automatically to all new networks created.
|
Loading…
Reference in New Issue
Block a user