Merge "L3 Metering label as shared"

This commit is contained in:
Jenkins 2014-09-13 15:44:12 +00:00 committed by Gerrit Code Review
commit bb536a3f4d
6 changed files with 132 additions and 10 deletions

View File

@ -54,6 +54,7 @@ class MeteringLabel(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
primaryjoin="MeteringLabel.tenant_id==Router.tenant_id",
foreign_keys='MeteringLabel.tenant_id',
uselist=True)
shared = sa.Column(sa.Boolean, default=False, server_default=sql.false())
class MeteringDbMixin(metering.MeteringPluginBase,
@ -66,6 +67,7 @@ class MeteringDbMixin(metering.MeteringPluginBase,
res = {'id': metering_label['id'],
'name': metering_label['name'],
'description': metering_label['description'],
'shared': metering_label['shared'],
'tenant_id': metering_label['tenant_id']}
return self._fields(res, fields)
@ -77,7 +79,8 @@ class MeteringDbMixin(metering.MeteringPluginBase,
metering_db = MeteringLabel(id=uuidutils.generate_uuid(),
description=m['description'],
tenant_id=tenant_id,
name=m['name'])
name=m['name'],
shared=m['shared'])
context.session.add(metering_db)
return self._make_metering_label_dict(metering_db)
@ -207,10 +210,19 @@ class MeteringDbMixin(metering.MeteringPluginBase,
return res
def _process_sync_metering_data(self, labels):
def _process_sync_metering_data(self, context, labels):
all_routers = None
routers_dict = {}
for label in labels:
routers = label.routers
if label.shared:
if not all_routers:
all_routers = self._get_collection_query(context,
l3_db.Router)
routers = all_routers
else:
routers = label.routers
for router in routers:
router_dict = routers_dict.get(
router['id'],
@ -234,4 +246,4 @@ class MeteringDbMixin(metering.MeteringPluginBase,
labels = (labels.join(MeteringLabel.routers).
filter(l3_db.Router.id.in_(router_ids)))
return self._process_sync_metering_data(labels)
return self._process_sync_metering_data(context, labels)

View File

@ -0,0 +1,39 @@
# Copyright 2014 OpenStack Foundation
#
# 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.
#
"""metering_label_shared
Revision ID: 3c346828361e
Revises: 16a27a58e093
Create Date: 2014-08-27 15:03:46.537290
"""
# revision identifiers, used by Alembic.
revision = '3c346828361e'
down_revision = '16a27a58e093'
from alembic import op
import sqlalchemy as sa
def upgrade(active_plugins=None, options=None):
op.add_column('meteringlabels', sa.Column('shared', sa.Boolean(),
server_default=sa.sql.false(),
nullable=True))
def downgrade(active_plugins=None, options=None):
op.drop_column('meteringlabels', 'shared')

View File

@ -1 +1 @@
16a27a58e093
3c346828361e

View File

@ -51,13 +51,16 @@ RESOURCE_ATTRIBUTE_MAP = {
'id': {'allow_post': False, 'allow_put': False,
'is_visible': True,
'primary_key': True},
'name': {'allow_post': True, 'allow_put': True,
'name': {'allow_post': True, 'allow_put': False,
'is_visible': True, 'default': ''},
'description': {'allow_post': True, 'allow_put': True,
'description': {'allow_post': True, 'allow_put': False,
'is_visible': True, 'default': ''},
'tenant_id': {'allow_post': True, 'allow_put': False,
'required_by_policy': True,
'is_visible': True}
'is_visible': True},
'shared': {'allow_post': True, 'allow_put': False,
'is_visible': True, 'default': False,
'convert_to': attr.convert_to_boolean}
},
'metering_label_rules': {
'id': {'allow_post': False, 'allow_put': False,
@ -66,10 +69,10 @@ RESOURCE_ATTRIBUTE_MAP = {
'metering_label_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:uuid': None},
'is_visible': True, 'required_by_policy': True},
'direction': {'allow_post': True, 'allow_put': True,
'direction': {'allow_post': True, 'allow_put': False,
'is_visible': True,
'validate': {'type:values': ['ingress', 'egress']}},
'excluded': {'allow_post': True, 'allow_put': True,
'excluded': {'allow_post': True, 'allow_put': False,
'is_visible': True, 'default': False,
'convert_to': attr.convert_to_boolean},
'remote_ip_prefix': {'allow_post': True, 'allow_put': False,

View File

@ -40,6 +40,7 @@ class MeteringPluginDbTestCaseMixin(object):
data = {'metering_label': {'name': name,
'tenant_id': kwargs.get('tenant_id',
'test-tenant'),
'shared': kwargs.get('shared', False),
'description': description}}
req = self.new_create_request('metering-labels', data,
fmt)
@ -149,6 +150,17 @@ class TestMetering(MeteringPluginDbTestCase):
for k, v, in keys:
self.assertEqual(metering_label['metering_label'][k], v)
def test_create_metering_label_shared(self):
name = 'my label'
description = 'my metering label'
shared = True
keys = [('name', name,), ('description', description),
('shared', shared)]
with self.metering_label(name, description,
shared=shared) as metering_label:
for k, v, in keys:
self.assertEqual(metering_label['metering_label'][k], v)
def test_delete_metering_label(self):
name = 'my label'
description = 'my metering label'

View File

@ -120,6 +120,32 @@ class TestMeteringPlugin(test_db_plugin.NeutronDbPluginV2TestCase,
set_context=True):
self.mock_fanout.assert_called_with(self.ctx, expected)
def test_add_metering_label_shared_rpc_call(self):
second_uuid = 'e27fe2df-376e-4ac7-ae13-92f050a21f84'
expected = {'args': {'routers': [{'status': 'ACTIVE',
'name': 'router1',
'gw_port_id': None,
'admin_state_up': True,
'tenant_id': self.tenant_id,
'_metering_labels': [
{'rules': [],
'id': self.uuid},
{'rules': [],
'id': second_uuid}],
'id': self.uuid}]},
'namespace': None,
'method': 'add_metering_label'}
tenant_id_2 = '8a268a58-1610-4890-87e0-07abb8231206'
with self.router(name='router1', tenant_id=self.tenant_id,
set_context=True):
with self.metering_label(tenant_id=self.tenant_id,
set_context=True):
self.mock_uuid.return_value = second_uuid
with self.metering_label(tenant_id=tenant_id_2, shared=True,
set_context=True):
self.mock_fanout.assert_called_with(self.ctx, expected)
def test_remove_metering_label_rpc_call(self):
expected = {'args':
{'routers': [{'status': 'ACTIVE',
@ -401,6 +427,10 @@ class TestMeteringPluginRpcFromL3Agent(
self.meter_plugin = manager.NeutronManager.get_service_plugins().get(
constants.METERING)
self.tenant_id = 'admin_tenant_id'
self.tenant_id_1 = 'tenant_id_1'
self.tenant_id_2 = 'tenant_id_2'
self.adminContext = context.get_admin_context()
self._register_l3_agent('agent1')
@ -439,3 +469,29 @@ class TestMeteringPluginRpcFromL3Agent(
self._remove_external_gateway_from_router(
r['id'], s['network_id'])
def test_get_sync_data_metering_shared(self):
with self.router(name='router1', tenant_id=self.tenant_id_1):
with self.router(name='router2', tenant_id=self.tenant_id_2):
with self.metering_label(tenant_id=self.tenant_id,
shared=True):
callbacks = metering_rpc.MeteringRpcCallbacks(
self.meter_plugin)
data = callbacks.get_sync_data_metering(self.adminContext)
routers = [router['name'] for router in data]
self.assertIn('router1', routers)
self.assertIn('router2', routers)
def test_get_sync_data_metering_not_shared(self):
with self.router(name='router1', tenant_id=self.tenant_id_1):
with self.router(name='router2', tenant_id=self.tenant_id_2):
with self.metering_label(tenant_id=self.tenant_id):
callbacks = metering_rpc.MeteringRpcCallbacks(
self.meter_plugin)
data = callbacks.get_sync_data_metering(self.adminContext)
routers = [router['name'] for router in data]
self.assertEqual([], routers)