Merge "Add QoS North Bound Functionality"
This commit is contained in:
commit
f3e56f2132
@ -17,7 +17,7 @@
|
||||
# http://git.openstack.org/cgit/openstack-infra/project-config/tree/jenkins/jobs/dragonflow.yaml
|
||||
#
|
||||
|
||||
export OVERRIDE_ENABLED_SERVICES=key,n-api,n-cpu,n-cond,n-sch,n-crt,n-cauth,n-obj,g-api,g-reg,c-sch,c-api,c-vol,horizon,rabbit,mysql,dstat,df-controller,df-redis,df-redis-server,q-svc,df-l3-agent,df-metadata
|
||||
export OVERRIDE_ENABLED_SERVICES=key,n-api,n-cpu,n-cond,n-sch,n-crt,n-cauth,n-obj,g-api,g-reg,c-sch,c-api,c-vol,horizon,rabbit,mysql,dstat,df-controller,df-redis,df-redis-server,q-svc,df-l3-agent,df-metadata,q-qos
|
||||
export DEVSTACK_LOCAL_CONFIG+=$'\n'"DF_REDIS_PUBSUB=True"
|
||||
export DEVSTACK_LOCAL_CONFIG+=$'\n'"DF_RUNNING_IN_GATE=True"
|
||||
export DEVSTACK_LOCAL_CONFIG+=$'\n'"NEUTRON_CREATE_INITIAL_NETWORKS=False"
|
||||
|
@ -145,6 +145,32 @@ function configure_df_metadata_service {
|
||||
fi
|
||||
}
|
||||
|
||||
function configure_qos {
|
||||
Q_SERVICE_PLUGIN_CLASSES+=",qos"
|
||||
Q_ML2_PLUGIN_EXT_DRIVERS+=",qos"
|
||||
iniset /$Q_PLUGIN_CONF_FILE ml2 extension_drivers "$Q_ML2_PLUGIN_EXT_DRIVERS"
|
||||
|
||||
# NOTE: QoS plugin use "message_queue" as default driver if no
|
||||
# notification driver in neutron.conf, or it will use driver
|
||||
# assigned in neutron.conf.
|
||||
# If "df" is the only mech driver for ml2, we use
|
||||
# "df_notification_driver" as notification driver.
|
||||
# If ml2 has other mech driver except "df", we should add
|
||||
# "message_queue,df_notification_driver" to existing
|
||||
# notification driver
|
||||
if [[ "$Q_ML2_PLUGIN_MECHANISM_DRIVERS" == "df" ]]; then
|
||||
NOTIFICATION_DRIVER="df_notification_driver"
|
||||
else
|
||||
NOTIFICATION_DRIVER=$(iniget ${NEUTRON_CONF} qos notification_drivers)
|
||||
if [[ "$NOTIFICATION_DRIVER" == "" ]]; then
|
||||
NOTIFICATION_DRIVER="message_queue,df_notification_driver"
|
||||
else
|
||||
NOTIFICATION_DRIVER+=",df_notification_driver"
|
||||
fi
|
||||
fi
|
||||
iniset $NEUTRON_CONF qos notification_drivers "$NOTIFICATION_DRIVER"
|
||||
}
|
||||
|
||||
function configure_df_plugin {
|
||||
echo "Configuring Neutron for Dragonflow"
|
||||
|
||||
@ -160,6 +186,9 @@ function configure_df_plugin {
|
||||
Q_SERVICE_PLUGIN_CLASSES=""
|
||||
else
|
||||
DF_APPS_LIST=$ML2_APPS_LIST
|
||||
if is_service_enabled q-qos ; then
|
||||
configure_qos
|
||||
fi
|
||||
fi
|
||||
|
||||
# Generate configuration file
|
||||
|
@ -24,7 +24,7 @@ from dragonflow.common import utils as df_utils
|
||||
cfg.CONF.register_opts(common_params.DF_OPTS, 'df')
|
||||
|
||||
db_tables = ['lport', 'lswitch', 'lrouter', 'chassis', 'secgroup',
|
||||
'tunnel_key', 'floatingip', 'publisher']
|
||||
'tunnel_key', 'floatingip', 'publisher', 'qospolicy']
|
||||
|
||||
usage_str = "The following commands are supported:\n" \
|
||||
"1) df-db ls - print all the db tables \n" \
|
||||
|
@ -743,6 +743,40 @@ class NbApi(object):
|
||||
topic,
|
||||
)
|
||||
|
||||
def create_qos_policy(self, policy_id, topic, **columns):
|
||||
policy = {'id': policy_id,
|
||||
'topic': topic}
|
||||
policy.update(columns)
|
||||
policy_json = jsonutils.dumps(policy)
|
||||
|
||||
self.driver.create_key('qospolicy', policy_id, policy_json, topic)
|
||||
self._send_db_change_event('qospolicy', policy_id, 'create',
|
||||
policy_json, topic)
|
||||
|
||||
def update_qos_policy(self, policy_id, topic, **columns):
|
||||
qospolicy_json = self.driver.get_key('qospolicy', policy_id, topic)
|
||||
policy = jsonutils.loads(qospolicy_json)
|
||||
policy.update(columns)
|
||||
policy_json = jsonutils.dumps(policy)
|
||||
|
||||
self.driver.set_key('qospolicy', policy_id, policy_json, topic)
|
||||
self._send_db_change_event('qospolicy', policy_id, 'set',
|
||||
policy_json, topic)
|
||||
|
||||
def delete_qos_policy(self, policy_id, topic):
|
||||
self.driver.delete_key('qospolicy', policy_id, topic)
|
||||
self._send_db_change_event('qospolicy', policy_id, 'delete', policy_id,
|
||||
topic)
|
||||
|
||||
def get_qos_policy(self, policy_id, topic=None):
|
||||
try:
|
||||
qospolicy_value = self.driver.get_key('qospolicy',
|
||||
policy_id, topic)
|
||||
return QosPolicy(qospolicy_value)
|
||||
except Exception:
|
||||
LOG.exception(_LE('Could not get qos policy %s'), policy_id)
|
||||
return None
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class DbStoreObject(object):
|
||||
@ -927,6 +961,9 @@ class LogicalPort(DbStoreObject):
|
||||
def get_binding_vnic_type(self):
|
||||
return self.lport.get('binding_vnic_type')
|
||||
|
||||
def get_qos_policy_id(self):
|
||||
return self.lport.get('qos_policy_id')
|
||||
|
||||
def get_version(self):
|
||||
return self.lport['version']
|
||||
|
||||
@ -1212,3 +1249,57 @@ class Publisher(DbStoreObject):
|
||||
|
||||
def __str__(self):
|
||||
return str(self.publisher)
|
||||
|
||||
|
||||
class QosPolicy(DbStoreObject):
|
||||
|
||||
def __init__(self, value):
|
||||
self.qospolicy = jsonutils.loads(value)
|
||||
|
||||
def get_id(self):
|
||||
return self.qospolicy.get('id')
|
||||
|
||||
def get_name(self):
|
||||
return self.qospolicy.get('name')
|
||||
|
||||
def get_topic(self):
|
||||
return self.qospolicy.get('topic')
|
||||
|
||||
def get_type(self):
|
||||
return self.qospolicy.get('type')
|
||||
|
||||
def get_version(self):
|
||||
return self.qospolicy.get('version')
|
||||
|
||||
def get_max_burst_kbps(self):
|
||||
rules = self.qospolicy.get('rules')
|
||||
max_burst_kbps = None
|
||||
for rule in rules:
|
||||
if rule['type'] == 'bandwidth_limit':
|
||||
max_burst_kbps = rule.get('max_burst_kbps')
|
||||
break
|
||||
|
||||
return max_burst_kbps
|
||||
|
||||
def get_max_kbps(self):
|
||||
rules = self.qospolicy.get('rules')
|
||||
max_kbps = None
|
||||
for rule in rules:
|
||||
if rule['type'] == 'bandwidth_limit':
|
||||
max_kbps = rule.get('max_kbps')
|
||||
break
|
||||
|
||||
return max_kbps
|
||||
|
||||
def get_dscp_marking(self):
|
||||
rules = self.qospolicy.get('rules')
|
||||
dscp_marking = None
|
||||
for rule in rules:
|
||||
if rule['type'] == 'dscp_marking':
|
||||
dscp_marking = rule.get('dscp_mark')
|
||||
break
|
||||
|
||||
return dscp_marking
|
||||
|
||||
def __str__(self):
|
||||
return str(self.qospolicy)
|
||||
|
@ -47,6 +47,8 @@ RESOURCE_ML2_CORE = 2 # network, subnet, port
|
||||
RESOURCE_ML2_SECURITY_GROUP = 3
|
||||
RESOURCE_ML2_SECURITY_GROUP_RULE_CREATE = 4
|
||||
RESOURCE_ML2_SECURITY_GROUP_RULE_DELETE = 5
|
||||
RESOURCE_QOS_POLICY_CREATE_OR_UPDATE = 6
|
||||
RESOURCE_QOS_POLICY_DELETE = 7
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
@ -107,6 +109,11 @@ def _get_lock_id_by_resource_type(type, *args, **kwargs):
|
||||
lock_id = args[1]['security_group_rule']['tenant_id']
|
||||
elif RESOURCE_ML2_SECURITY_GROUP_RULE_DELETE == type:
|
||||
lock_id = args[1]['context'].tenant_id
|
||||
elif RESOURCE_QOS_POLICY_CREATE_OR_UPDATE == type:
|
||||
lock_id = args[0][2]['tenant_id']
|
||||
elif RESOURCE_QOS_POLICY_DELETE == type:
|
||||
# when delete qos policy, there's no tenant_id in args.
|
||||
lock_id = GLOBAL_LOCK_ID
|
||||
|
||||
if not lock_id:
|
||||
lock_id = GLOBAL_LOCK_ID
|
||||
|
@ -246,7 +246,8 @@ class DFMechDriver(driver_api.MechanismDriver):
|
||||
router_external=network['router:external'],
|
||||
mtu=network.get('mtu'),
|
||||
version=network['revision_number'],
|
||||
subnets=[])
|
||||
subnets=[],
|
||||
qos_policy_id=network.get('qos_policy_id'))
|
||||
|
||||
LOG.info(_LI("DFMechDriver: create network %s"), network['id'])
|
||||
return network
|
||||
@ -263,9 +264,28 @@ class DFMechDriver(driver_api.MechanismDriver):
|
||||
except df_exceptions.DBKeyNotFound:
|
||||
LOG.debug("lswitch %s is not found in DF DB, might have "
|
||||
"been deleted concurrently" % network_id)
|
||||
return
|
||||
|
||||
LOG.info(_LI("DFMechDriver: delete network %s"), network_id)
|
||||
|
||||
@lock_db.wrap_db_lock(lock_db.RESOURCE_ML2_CORE)
|
||||
def update_network_postcommit(self, context):
|
||||
network = context.current
|
||||
|
||||
self.nb_api.update_lswitch(
|
||||
id=network['id'],
|
||||
topic=network['tenant_id'],
|
||||
name=network.get('name', df_const.DF_NETWORK_DEFAULT_NAME),
|
||||
network_type=network.get('provider:network_type'),
|
||||
segmentation_id=network.get('provider:segmentation_id'),
|
||||
router_external=network.get('router:external'),
|
||||
mtu=network.get('mtu'),
|
||||
version=network['revision_number'],
|
||||
qos_policy_id=network.get('qos_policy_id'))
|
||||
|
||||
LOG.info(_LI("DFMechDriver: update network %s"), network['id'])
|
||||
return network
|
||||
|
||||
def _get_dhcp_port_for_subnet(self, context, subnet_id):
|
||||
filters = {'fixed_ips': {'subnet_id': [subnet_id]},
|
||||
'device_owner': [n_const.DEVICE_OWNER_DHCP]}
|
||||
@ -370,8 +390,9 @@ class DFMechDriver(driver_api.MechanismDriver):
|
||||
dhcp_ip, dhcp_port = self._handle_create_subnet_dhcp(
|
||||
plugin_context,
|
||||
subnet)
|
||||
except Exception as e:
|
||||
LOG.exception(e)
|
||||
except Exception:
|
||||
LOG.exception(
|
||||
_LE("Failed to create dhcp port for subnet %s"), subnet['id'])
|
||||
return None
|
||||
|
||||
self.nb_api.add_subnet(
|
||||
@ -447,8 +468,10 @@ class DFMechDriver(driver_api.MechanismDriver):
|
||||
plugin_context,
|
||||
old_subnet,
|
||||
new_subnet)
|
||||
except Exception as e:
|
||||
LOG.exception(e)
|
||||
except Exception:
|
||||
LOG.exception(
|
||||
_LE("Failed to create dhcp port for subnet %s"),
|
||||
new_subnet['id'])
|
||||
return None
|
||||
|
||||
self.nb_api.update_subnet(
|
||||
@ -489,6 +512,7 @@ class DFMechDriver(driver_api.MechanismDriver):
|
||||
except df_exceptions.DBKeyNotFound:
|
||||
LOG.debug("network %s is not found in DB, might have "
|
||||
"been deleted concurrently" % net_id)
|
||||
return
|
||||
|
||||
LOG.info(_LI("DFMechDriver: delete subnet %s"), subnet_id)
|
||||
|
||||
@ -532,7 +556,8 @@ class DFMechDriver(driver_api.MechanismDriver):
|
||||
remote_vtep=remote_vtep,
|
||||
allowed_address_pairs=port.get(addr_pair.ADDRESS_PAIRS, []),
|
||||
binding_profile=port.get(portbindings.PROFILE, None),
|
||||
binding_vnic_type=port.get(portbindings.VNIC_TYPE, None))
|
||||
binding_vnic_type=port.get(portbindings.VNIC_TYPE, None),
|
||||
qos_policy_id=port.get('qos_policy_id', None))
|
||||
|
||||
LOG.info(_LI("DFMechDriver: create port %s"), port['id'])
|
||||
return port
|
||||
@ -629,8 +654,8 @@ class DFMechDriver(driver_api.MechanismDriver):
|
||||
[]),
|
||||
binding_profile=updated_port.get(portbindings.PROFILE, None),
|
||||
binding_vnic_type=updated_port.get(portbindings.VNIC_TYPE, None),
|
||||
version=updated_port['revision_number'],
|
||||
remote_vtep=remote_vtep)
|
||||
version=updated_port['revision_number'], remote_vtep=remote_vtep,
|
||||
qos_policy_id=updated_port.get('qos_policy_id'))
|
||||
|
||||
LOG.info(_LI("DFMechDriver: update port %s"), updated_port['id'])
|
||||
return updated_port
|
||||
@ -646,6 +671,7 @@ class DFMechDriver(driver_api.MechanismDriver):
|
||||
except df_exceptions.DBKeyNotFound:
|
||||
LOG.debug("port %s is not found in DF DB, might have "
|
||||
"been deleted concurrently" % port_id)
|
||||
return
|
||||
|
||||
LOG.info(_LI("DFMechDriver: delete port %s"), port_id)
|
||||
|
||||
|
0
dragonflow/neutron/services/qos/__init__.py
Normal file
0
dragonflow/neutron/services/qos/__init__.py
Normal file
@ -0,0 +1,75 @@
|
||||
# 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 import manager
|
||||
from neutron.plugins.common import constants as service_constants
|
||||
from neutron.plugins.ml2 import plugin as ml2_plugin
|
||||
from neutron.services.qos.notification_drivers import qos_base
|
||||
|
||||
from dragonflow.db.neutron import lockedobjects_db as lock_db
|
||||
|
||||
|
||||
class DFQosServiceNotificationDriver(
|
||||
qos_base.QosServiceNotificationDriverBase):
|
||||
"""Dragonflow notification driver for QoS."""
|
||||
|
||||
def __init__(self):
|
||||
self._nb_api = None
|
||||
|
||||
def get_description(self):
|
||||
return "Notification driver for Dragonflow"
|
||||
|
||||
@property
|
||||
def _plugin(self):
|
||||
return manager.NeutronManager.get_service_plugins().get(
|
||||
service_constants.QOS)
|
||||
|
||||
@property
|
||||
def nb_api(self):
|
||||
if self._nb_api is None:
|
||||
plugin = manager.NeutronManager.get_plugin()
|
||||
if isinstance(plugin, ml2_plugin.Ml2Plugin):
|
||||
mech_driver = plugin.mechanism_manager.mech_drivers['df'].obj
|
||||
self._nb_api = mech_driver.nb_api
|
||||
else:
|
||||
# DF neutron plugin
|
||||
self._nb_api = plugin.nb_api
|
||||
return self._nb_api
|
||||
|
||||
@lock_db.wrap_db_lock(lock_db.RESOURCE_QOS_POLICY_CREATE_OR_UPDATE)
|
||||
def create_policy(self, context, policy):
|
||||
self.nb_api.create_qos_policy(policy['id'],
|
||||
policy['tenant_id'],
|
||||
name=policy['name'],
|
||||
rules=policy.get('rules', []),
|
||||
version=policy['revision_number'])
|
||||
|
||||
@lock_db.wrap_db_lock(lock_db.RESOURCE_QOS_POLICY_CREATE_OR_UPDATE)
|
||||
def update_policy(self, context, policy):
|
||||
policy_id = policy['id']
|
||||
# NOTE: Neutron will not pass policy with latest revision_number
|
||||
# in argument. Get the latest policy from neutron.
|
||||
policy_neutron = self._plugin.get_policy(context, policy_id)
|
||||
|
||||
self.nb_api.update_qos_policy(
|
||||
policy_id, policy_neutron['tenant_id'],
|
||||
name=policy['name'], rules=policy_neutron['rules'],
|
||||
version=policy_neutron['revision_number'])
|
||||
|
||||
@lock_db.wrap_db_lock(lock_db.RESOURCE_QOS_POLICY_DELETE)
|
||||
def delete_policy(self, context, policy):
|
||||
policy_id = policy['id']
|
||||
# Only id will be in policy in the argument. Get full policy from
|
||||
# neutron.
|
||||
policy_neutron = self._plugin.get_policy(context, policy_id)
|
||||
|
||||
self.nb_api.delete_qos_policy(policy_id, policy_neutron['tenant_id'])
|
@ -14,11 +14,15 @@ import contextlib
|
||||
|
||||
from neutronclient.common import exceptions as n_exc
|
||||
from oslo_concurrency import lockutils
|
||||
from oslo_config import cfg
|
||||
|
||||
from dragonflow.tests.common import utils
|
||||
from dragonflow.tests.fullstack import test_base
|
||||
from dragonflow.tests.fullstack import test_objects as objects
|
||||
|
||||
# TODO(xiaohhui): This should be removed, once the DFPlugin has been removed.
|
||||
DF_PLUGIN = 'dragonflow.neutron.plugin.DFPlugin'
|
||||
|
||||
|
||||
class TestNeutronAPIandDB(test_base.DFTestBase):
|
||||
|
||||
@ -174,6 +178,75 @@ class TestNeutronAPIandDB(test_base.DFTestBase):
|
||||
network.close()
|
||||
self.assertFalse(network.exists())
|
||||
|
||||
def test_create_port_with_qospolicy(self):
|
||||
if cfg.CONF.core_plugin == DF_PLUGIN:
|
||||
return
|
||||
|
||||
network = self.store(objects.NetworkTestObj(self.neutron, self.nb_api))
|
||||
network_id = network.create()
|
||||
self.assertTrue(network.exists())
|
||||
|
||||
qospolicy = self.store(objects.QosPolicyTestObj(self.neutron,
|
||||
self.nb_api))
|
||||
qos_policy_id = qospolicy.create()
|
||||
self.assertTrue(qospolicy.exists())
|
||||
|
||||
port = self.store(objects.PortTestObj(self.neutron,
|
||||
self.nb_api,
|
||||
network_id))
|
||||
port_param = {
|
||||
'admin_state_up': True,
|
||||
'name': 'port1',
|
||||
'network_id': network_id,
|
||||
'qos_policy_id': qos_policy_id
|
||||
}
|
||||
port.create(port_param)
|
||||
self.assertTrue(port.exists())
|
||||
self.assertEqual(qos_policy_id,
|
||||
port.get_logical_port().get_qos_policy_id())
|
||||
|
||||
port.close()
|
||||
self.assertFalse(port.exists())
|
||||
network.close()
|
||||
self.assertFalse(network.exists())
|
||||
qospolicy.close()
|
||||
self.assertFalse(qospolicy.exists())
|
||||
|
||||
def test_update_port_with_qospolicy(self):
|
||||
if cfg.CONF.core_plugin == DF_PLUGIN:
|
||||
return
|
||||
|
||||
network = self.store(objects.NetworkTestObj(self.neutron, self.nb_api))
|
||||
network_id = network.create()
|
||||
self.assertTrue(network.exists())
|
||||
|
||||
qospolicy = self.store(objects.QosPolicyTestObj(self.neutron,
|
||||
self.nb_api))
|
||||
qos_policy_id = qospolicy.create()
|
||||
self.assertTrue(qospolicy.exists())
|
||||
|
||||
port = self.store(objects.PortTestObj(self.neutron,
|
||||
self.nb_api,
|
||||
network_id))
|
||||
port.create()
|
||||
self.assertTrue(port.exists())
|
||||
|
||||
port_param = {
|
||||
'admin_state_up': True,
|
||||
'name': 'port1',
|
||||
'qos_policy_id': qos_policy_id
|
||||
}
|
||||
port.update(port_param)
|
||||
self.assertEqual(qos_policy_id,
|
||||
port.get_logical_port().get_qos_policy_id())
|
||||
|
||||
port.close()
|
||||
self.assertFalse(port.exists())
|
||||
network.close()
|
||||
self.assertFalse(network.exists())
|
||||
qospolicy.close()
|
||||
self.assertFalse(qospolicy.exists())
|
||||
|
||||
def test_delete_router_interface_port(self):
|
||||
router = self.store(objects.RouterTestObj(self.neutron, self.nb_api))
|
||||
network = self.store(objects.NetworkTestObj(self.neutron, self.nb_api))
|
||||
@ -241,6 +314,20 @@ class TestNeutronAPIandDB(test_base.DFTestBase):
|
||||
secgroup.close()
|
||||
self.assertFalse(secgroup.exists())
|
||||
|
||||
def test_create_delete_qos_policy(self):
|
||||
if cfg.CONF.core_plugin == DF_PLUGIN:
|
||||
return
|
||||
|
||||
qospolicy = self.store(
|
||||
objects.QosPolicyTestObj(self.neutron, self.nb_api))
|
||||
policy_id = qospolicy.create()
|
||||
self.assertTrue(qospolicy.exists())
|
||||
rule = {'max_kbps': '1000', 'max_burst_kbps': '100'}
|
||||
qospolicy.create_rule(policy_id, rule)
|
||||
self.assertTrue(qospolicy.exists())
|
||||
qospolicy.close()
|
||||
self.assertFalse(qospolicy.exists())
|
||||
|
||||
@contextlib.contextmanager
|
||||
def _prepare_ext_net(self):
|
||||
external_net = objects.find_first_network(self.neutron,
|
||||
|
@ -13,10 +13,13 @@
|
||||
import contextlib
|
||||
|
||||
from oslo_concurrency import lockutils
|
||||
from oslo_config import cfg
|
||||
|
||||
from dragonflow.tests.fullstack import test_base
|
||||
from dragonflow.tests.fullstack import test_objects as objects
|
||||
|
||||
DF_PLUGIN = 'dragonflow.neutron.plugin.DFPlugin'
|
||||
|
||||
|
||||
class TestObjectVersion(test_base.DFTestBase):
|
||||
|
||||
@ -127,6 +130,25 @@ class TestObjectVersion(test_base.DFTestBase):
|
||||
secgroup.close()
|
||||
self.assertFalse(secgroup.exists())
|
||||
|
||||
def test_qospolicy_version(self):
|
||||
if cfg.CONF.core_plugin == DF_PLUGIN:
|
||||
return
|
||||
|
||||
qospolicy = self.store(objects.QosPolicyTestObj(self.neutron,
|
||||
self.nb_api))
|
||||
policy_id = qospolicy.create()
|
||||
self.assertTrue(qospolicy.exists())
|
||||
version = self.nb_api.get_qos_policy(policy_id).get_version()
|
||||
|
||||
rule = {'max_kbps': '1000', 'max_burst_kbps': '100'}
|
||||
qospolicy.create_rule(policy_id, rule)
|
||||
self.assertTrue(qospolicy.exists())
|
||||
new_version = self.nb_api.get_qos_policy(policy_id).get_version()
|
||||
self.assertGreater(new_version, version)
|
||||
|
||||
qospolicy.close()
|
||||
self.assertFalse(qospolicy.exists())
|
||||
|
||||
@contextlib.contextmanager
|
||||
def _prepare_ext_net(self):
|
||||
external_net = objects.find_first_network(self.neutron,
|
||||
|
@ -444,3 +444,34 @@ class FloatingipTestObj(object):
|
||||
return True
|
||||
return False
|
||||
utils.wait_until_true(internal_predicate, timeout, sleep, exception)
|
||||
|
||||
|
||||
class QosPolicyTestObj(object):
|
||||
def __init__(self, neutron, nb_api):
|
||||
self.policy_id = None
|
||||
self.neutron = neutron
|
||||
self.nb_api = nb_api
|
||||
self.closed = False
|
||||
|
||||
def create(self, qospolicy={'name': 'myqospolicy1'}):
|
||||
new_qospolicy = self.neutron.create_qos_policy({'policy':
|
||||
qospolicy})
|
||||
self.policy_id = new_qospolicy['policy']['id']
|
||||
return self.policy_id
|
||||
|
||||
def create_rule(self, policy_id, rule):
|
||||
self.neutron.create_bandwidth_limit_rule(
|
||||
policy_id, {'bandwidth_limit_rule': rule})
|
||||
return
|
||||
|
||||
def close(self):
|
||||
if self.closed or self.policy_id is None:
|
||||
return
|
||||
self.neutron.delete_qos_policy(self.policy_id)
|
||||
self.closed = True
|
||||
|
||||
def exists(self):
|
||||
qospolicy = self.nb_api.get_qos_policy(self.policy_id)
|
||||
if qospolicy:
|
||||
return True
|
||||
return False
|
||||
|
98
dragonflow/tests/unit/test_df_qos_notification_driver.py
Normal file
98
dragonflow/tests/unit/test_df_qos_notification_driver.py
Normal file
@ -0,0 +1,98 @@
|
||||
# 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 mock
|
||||
from neutron.conf.services import qos_driver_manager as driver_mgr_config
|
||||
from neutron import manager
|
||||
from neutron.objects.qos import rule
|
||||
from neutron.plugins.ml2 import config as ml2_config
|
||||
|
||||
from dragonflow.tests.unit import test_mech_driver
|
||||
|
||||
|
||||
class TestDFQosNotificationDriver(test_mech_driver.DFMechanismDriverTestCase):
|
||||
|
||||
"""Test case of df qos notification drvier"""
|
||||
|
||||
_extension_drivers = ['qos']
|
||||
|
||||
def get_additional_service_plugins(self):
|
||||
p = super(TestDFQosNotificationDriver,
|
||||
self).get_additional_service_plugins()
|
||||
p.update({'qos_plugin_name': 'qos'})
|
||||
return p
|
||||
|
||||
def setUp(self):
|
||||
ml2_config.cfg.CONF.set_override('extension_drivers',
|
||||
self._extension_drivers,
|
||||
group='ml2')
|
||||
driver_mgr_config.register_qos_plugin_opts(ml2_config.cfg.CONF)
|
||||
ml2_config.cfg.CONF.set_override('notification_drivers',
|
||||
['df_notification_driver'], 'qos')
|
||||
super(TestDFQosNotificationDriver, self).setUp()
|
||||
self.plugin = (manager.NeutronManager.
|
||||
get_service_plugins()['QOS'])
|
||||
self.driver = (
|
||||
self.plugin.notification_driver_manager.notification_drivers[0])
|
||||
|
||||
def _test_create_policy(self):
|
||||
qos_policy = {'policy': {'name': "policy1", 'tenant_id': "tenant1"}}
|
||||
qos_obj = self.plugin.create_policy(self.context, qos_policy)
|
||||
self.assertGreater(qos_obj['revision_number'], 0)
|
||||
self.driver.nb_api.create_qos_policy.assert_called_with(
|
||||
mock.ANY, 'tenant1', name='policy1',
|
||||
rules=[], version=qos_obj['revision_number'])
|
||||
return qos_obj
|
||||
|
||||
def test_create_policy(self):
|
||||
self._test_create_policy()
|
||||
|
||||
def test_update_policy(self):
|
||||
qos_obj = self._test_create_policy()
|
||||
new_qos_obj = self.plugin.update_policy(
|
||||
self.context, qos_obj['id'], {'policy': {'name': 'policy2'}})
|
||||
self.assertGreater(new_qos_obj['revision_number'],
|
||||
qos_obj['revision_number'])
|
||||
self.driver.nb_api.update_qos_policy.assert_called_with(
|
||||
qos_obj['id'], 'tenant1', name='policy2',
|
||||
rules=[], version=new_qos_obj['revision_number'])
|
||||
|
||||
def test_create_delete_policy_rule(self):
|
||||
qos_obj = self._test_create_policy()
|
||||
qos_rule = {'max_burst_kbps': 1000,
|
||||
'max_kbps': 100}
|
||||
qos_rule_obj = self.plugin.create_policy_rule(
|
||||
self.context, rule.QosBandwidthLimitRule,
|
||||
qos_obj['id'], {'bandwidth_limit_rule': qos_rule})
|
||||
new_qos_obj = self.plugin.get_policy(self.context, qos_obj['id'])
|
||||
self.assertGreater(new_qos_obj['revision_number'],
|
||||
qos_obj['revision_number'])
|
||||
self.driver.nb_api.update_qos_policy.assert_called_with(
|
||||
qos_obj['id'], 'tenant1', name='policy1',
|
||||
rules=[qos_rule_obj], version=new_qos_obj['revision_number'])
|
||||
|
||||
self.plugin.delete_policy_rule(self.context,
|
||||
rule.QosBandwidthLimitRule,
|
||||
qos_rule_obj['id'],
|
||||
qos_obj['id'])
|
||||
newer_qos_obj = self.plugin.get_policy(self.context, qos_obj['id'])
|
||||
self.assertGreater(newer_qos_obj['revision_number'],
|
||||
new_qos_obj['revision_number'])
|
||||
self.driver.nb_api.update_qos_policy.assert_called_with(
|
||||
qos_obj['id'], 'tenant1', name='policy1',
|
||||
rules=[], version=newer_qos_obj['revision_number'])
|
||||
|
||||
def test_delete_policy(self):
|
||||
qos_obj = self._test_create_policy()
|
||||
self.plugin.delete_policy(self.context, qos_obj['id'])
|
||||
self.driver.nb_api.delete_qos_policy.assert_called_with(
|
||||
qos_obj['id'], 'tenant1')
|
@ -123,7 +123,8 @@ class TestDFMechDriver(DFMechanismDriverTestCase):
|
||||
physical_network=network['provider:physical_network'],
|
||||
router_external=network['router:external'],
|
||||
mtu=network['mtu'], version=network['revision_number'],
|
||||
subnets=[])
|
||||
subnets=[],
|
||||
qos_policy_id=None)
|
||||
return network
|
||||
|
||||
def test_create_network_revision(self):
|
||||
@ -221,7 +222,8 @@ class TestDFMechDriver(DFMechanismDriverTestCase):
|
||||
remote_vtep=False,
|
||||
allowed_address_pairs=mock.ANY,
|
||||
binding_profile=mock.ANY,
|
||||
binding_vnic_type=mock.ANY)
|
||||
binding_vnic_type=mock.ANY,
|
||||
qos_policy_id=None)
|
||||
|
||||
data = {'port': {'name': 'updated'}}
|
||||
req = self.new_update_request('ports', data, port['id'])
|
||||
@ -244,7 +246,8 @@ class TestDFMechDriver(DFMechanismDriverTestCase):
|
||||
port_security_enabled=mock.ANY,
|
||||
allowed_address_pairs=mock.ANY,
|
||||
binding_profile=mock.ANY,
|
||||
binding_vnic_type=mock.ANY)
|
||||
binding_vnic_type=mock.ANY,
|
||||
qos_policy_id=None)
|
||||
|
||||
def test_delete_network(self):
|
||||
network = self._test_create_network_revision()
|
||||
@ -272,6 +275,7 @@ class TestDFMechDriver(DFMechanismDriverTestCase):
|
||||
device_id=port['device_id'],
|
||||
security_groups=mock.ANY,
|
||||
port_security_enabled=mock.ANY,
|
||||
qos_policy_id=mock.ANY,
|
||||
remote_vtep=True,
|
||||
allowed_address_pairs=mock.ANY,
|
||||
binding_profile=profile,
|
||||
@ -291,6 +295,7 @@ class TestDFMechDriver(DFMechanismDriverTestCase):
|
||||
version=mock.ANY,
|
||||
device_owner=port['device_owner'],
|
||||
device_id=port['device_id'],
|
||||
qos_policy_id=mock.ANY,
|
||||
remote_vtep=True,
|
||||
security_groups=mock.ANY,
|
||||
port_security_enabled=mock.ANY,
|
||||
|
@ -48,6 +48,8 @@ output_file = dragonflow/locale/dragonflow.pot
|
||||
|
||||
|
||||
[entry_points]
|
||||
neutron.qos.notification_drivers =
|
||||
df_notification_driver = dragonflow.neutron.services.qos.notification_drivers.df_qos_notification_driver:DFQosServiceNotificationDriver
|
||||
neutron.ml2.mechanism_drivers =
|
||||
df = dragonflow.neutron.ml2.mech_driver:DFMechDriver
|
||||
neutron.db.alembic_migrations =
|
||||
|
Loading…
Reference in New Issue
Block a user