Merge "create a Quantum port to reserve VIP address"

This commit is contained in:
Jenkins 2013-02-27 23:49:44 +00:00 committed by Gerrit Code Review
commit ce7f38cd40
6 changed files with 299 additions and 217 deletions

View File

@ -29,6 +29,7 @@ from quantum.db import model_base
from quantum.db import models_v2
from quantum.extensions import loadbalancer
from quantum.extensions.loadbalancer import LoadBalancerPluginBase
from quantum import manager
from quantum.openstack.common import log as logging
from quantum.openstack.common import uuidutils
from quantum.plugins.common import constants
@ -64,9 +65,8 @@ class Vip(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
"""Represents a v2 quantum loadbalancer vip."""
name = sa.Column(sa.String(255))
description = sa.Column(sa.String(255))
subnet_id = sa.Column(sa.String(36), nullable=False)
address = sa.Column(sa.String(64))
port = sa.Column(sa.Integer, nullable=False)
port_id = sa.Column(sa.String(36), sa.ForeignKey('ports.id'))
protocol_port = sa.Column(sa.Integer, nullable=False)
protocol = sa.Column(sa.Enum("HTTP", "HTTPS", "TCP", name="lb_protocols"),
nullable=False)
pool_id = sa.Column(sa.String(36), nullable=False)
@ -77,6 +77,7 @@ class Vip(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
status = sa.Column(sa.String(16), nullable=False)
admin_state_up = sa.Column(sa.Boolean(), nullable=False)
connection_limit = sa.Column(sa.Integer)
port = orm.relationship(models_v2.Port)
class Member(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
@ -84,7 +85,7 @@ class Member(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
pool_id = sa.Column(sa.String(36), sa.ForeignKey("pools.id"),
nullable=False)
address = sa.Column(sa.String(64), nullable=False)
port = sa.Column(sa.Integer, nullable=False)
protocol_port = sa.Column(sa.Integer, nullable=False)
weight = sa.Column(sa.Integer, nullable=False)
status = sa.Column(sa.String(16), nullable=False)
admin_state_up = sa.Column(sa.Boolean(), nullable=False)
@ -151,6 +152,10 @@ class LoadBalancerPluginDb(LoadBalancerPluginBase):
loadbalancer plugin database access interface using SQLAlchemy models.
"""
@property
def _core_plugin(self):
return manager.QuantumManager.get_plugin()
# TODO(lcui):
# A set of internal facility methods are borrowed from QuantumDbPluginV2
# class and hence this is duplicate. We need to pull out those methods
@ -237,18 +242,22 @@ class LoadBalancerPluginDb(LoadBalancerPluginBase):
########################################################
# VIP DB access
def _make_vip_dict(self, vip, fields=None):
fixed_ip = (vip.port.fixed_ips or [{}])[0]
res = {'id': vip['id'],
'tenant_id': vip['tenant_id'],
'name': vip['name'],
'description': vip['description'],
'subnet_id': vip['subnet_id'],
'address': vip['address'],
'port': vip['port'],
'subnet_id': fixed_ip.get('subnet_id'),
'address': fixed_ip.get('ip_address'),
'port_id': vip['port_id'],
'protocol_port': vip['protocol_port'],
'protocol': vip['protocol'],
'pool_id': vip['pool_id'],
'connection_limit': vip['connection_limit'],
'admin_state_up': vip['admin_state_up'],
'status': vip['status']}
if vip['session_persistence']:
s_p = {
'type': vip['session_persistence']['type']
@ -320,22 +329,38 @@ class LoadBalancerPluginDb(LoadBalancerPluginBase):
sess_qry = context.session.query(SessionPersistence)
sess_qry.filter_by(vip_id=vip_id).delete()
def _create_port_for_vip(self, context, vip_db, subnet_id, ip_address):
# resolve subnet and create port
subnet = self._core_plugin.get_subnet(context, subnet_id)
fixed_ip = {'subnet_id': subnet['id']}
if ip_address and ip_address != attributes.ATTR_NOT_SPECIFIED:
fixed_ip['ip_address'] = ip_address
port_data = {
'tenant_id': vip_db.tenant_id,
'name': 'vip-' + vip_db.id,
'network_id': subnet['network_id'],
'mac_address': attributes.ATTR_NOT_SPECIFIED,
'admin_state_up': False,
'device_id': '',
'device_owner': '',
'fixed_ips': [fixed_ip]
}
port = self._core_plugin.create_port(context, {'port': port_data})
vip_db.port_id = port['id']
def create_vip(self, context, vip):
v = vip['vip']
tenant_id = self._get_tenant_id_for_create(context, v)
with context.session.begin(subtransactions=True):
if v['address'] is attributes.ATTR_NOT_SPECIFIED:
address = None
else:
address = v['address']
vip_db = Vip(id=uuidutils.generate_uuid(),
tenant_id=tenant_id,
name=v['name'],
description=v['description'],
subnet_id=v['subnet_id'],
address=address,
port=v['port'],
port_id=None,
protocol_port=v['protocol_port'],
protocol=v['protocol'],
pool_id=v['pool_id'],
connection_limit=v['connection_limit'],
@ -350,9 +375,16 @@ class LoadBalancerPluginDb(LoadBalancerPluginBase):
vip_db.session_persistence = s_p
context.session.add(vip_db)
self._update_pool_vip_info(context, v['pool_id'], vip_id)
context.session.flush()
vip_db = self._get_resource(context, Vip, vip_id)
self._create_port_for_vip(
context,
vip_db,
v['subnet_id'],
v.get('address')
)
self._update_pool_vip_info(context, v['pool_id'], vip_id)
return self._make_vip_dict(vip_db)
def update_vip(self, context, id, vip):
@ -383,7 +415,11 @@ class LoadBalancerPluginDb(LoadBalancerPluginBase):
qry = context.session.query(Pool)
for pool in qry.filter_by(vip_id=id).all():
pool.update({"vip_id": None})
context.session.delete(vip)
if vip.port: # this is a Quantum port
self._core_plugin.delete_port(context, vip.port.id)
context.session.flush()
def get_vip(self, context, id, fields=None):
vip = self._get_resource(context, Vip, id)
@ -574,7 +610,7 @@ class LoadBalancerPluginDb(LoadBalancerPluginBase):
'tenant_id': member['tenant_id'],
'pool_id': member['pool_id'],
'address': member['address'],
'port': member['port'],
'protocol_port': member['protocol_port'],
'weight': member['weight'],
'admin_state_up': member['admin_state_up'],
'status': member['status']}
@ -596,7 +632,7 @@ class LoadBalancerPluginDb(LoadBalancerPluginBase):
tenant_id=tenant_id,
pool_id=v['pool_id'],
address=v['address'],
port=v['port'],
protocol_port=v['protocol_port'],
weight=v['weight'],
admin_state_up=v['admin_state_up'],
status=constants.PENDING_CREATE)

View File

@ -48,9 +48,8 @@ def upgrade(active_plugin=None, options=None):
sa.Column(u'id', sa.String(36), nullable=False),
sa.Column(u'name', sa.String(255), nullable=True),
sa.Column(u'description', sa.String(255), nullable=True),
sa.Column(u'subnet_id', sa.String(36), nullable=False),
sa.Column(u'address', sa.String(64), nullable=True),
sa.Column(u'port', sa.Integer(), nullable=False),
sa.Column(u'port_id', sa.String(36), nullable=True),
sa.Column(u'protocol_port', sa.Integer(), nullable=False),
sa.Column(u'protocol',
sa.Enum("HTTP", "HTTPS", "TCP", name="lb_protocols"),
nullable=False),
@ -58,6 +57,7 @@ def upgrade(active_plugin=None, options=None):
sa.Column(u'status', sa.String(16), nullable=False),
sa.Column(u'admin_state_up', sa.Boolean(), nullable=False),
sa.Column(u'connection_limit', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['port_id'], ['ports.id'], ),
sa.PrimaryKeyConstraint(u'id')
)
op.create_table(
@ -130,7 +130,7 @@ def upgrade(active_plugin=None, options=None):
sa.Column(u'id', sa.String(36), nullable=False),
sa.Column(u'pool_id', sa.String(36), nullable=False),
sa.Column(u'address', sa.String(64), nullable=False),
sa.Column(u'port', sa.Integer(), nullable=False),
sa.Column(u'protocol_port', sa.Integer(), nullable=False),
sa.Column(u'weight', sa.Integer(), nullable=False),
sa.Column(u'status', sa.String(16), nullable=False),
sa.Column(u'admin_state_up', sa.Boolean(), nullable=False),

View File

@ -79,10 +79,13 @@ RESOURCE_ATTRIBUTE_MAP = {
'default': attr.ATTR_NOT_SPECIFIED,
'validate': {'type:ip_address_or_none': None},
'is_visible': True},
'port': {'allow_post': True, 'allow_put': False,
'validate': {'type:range': [0, 65535]},
'convert_to': attr.convert_to_int,
'is_visible': True},
'port_id': {'allow_post': False, 'allow_put': False,
'validate': {'type:uuid': None},
'is_visible': True},
'protocol_port': {'allow_post': True, 'allow_put': False,
'validate': {'type:range': [0, 65535]},
'convert_to': attr.convert_to_int,
'is_visible': True},
'protocol': {'allow_post': True, 'allow_put': False,
'validate': {'type:values': ['TCP', 'HTTP', 'HTTPS']},
'is_visible': True},
@ -167,10 +170,10 @@ RESOURCE_ATTRIBUTE_MAP = {
'address': {'allow_post': True, 'allow_put': False,
'validate': {'type:ip_address': None},
'is_visible': True},
'port': {'allow_post': True, 'allow_put': False,
'validate': {'type:range': [0, 65535]},
'convert_to': attr.convert_to_int,
'is_visible': True},
'protocol_port': {'allow_post': True, 'allow_put': False,
'validate': {'type:range': [0, 65535]},
'convert_to': attr.convert_to_int,
'is_visible': True},
'weight': {'allow_post': True, 'allow_put': True,
'default': 1,
'validate': {'type:range': [0, 256]},

View File

@ -15,7 +15,9 @@
import contextlib
import logging
import mock
import os
import testtools
from oslo.config import cfg
import webob.exc
@ -25,6 +27,7 @@ from quantum.api.extensions import PluginAwareExtensionManager
from quantum.api.v2 import attributes
from quantum.api.v2.router import APIRouter
from quantum.common import config
from quantum.common import exceptions as q_exc
from quantum.common.test_lib import test_config
from quantum.db import api as db
import quantum.extensions
@ -79,16 +82,15 @@ class LoadBalancerPluginDbTestCase(test_db_plugin.QuantumDbPluginV2TestCase):
app = config.load_paste_app('extensions_test_app')
self.ext_api = ExtensionMiddleware(app, ext_mgr=ext_mgr)
def _create_vip(self, fmt, name, pool_id, protocol, port, admin_state_up,
expected_res_status=None, **kwargs):
def _create_vip(self, fmt, name, pool_id, protocol, protocol_port,
admin_state_up, expected_res_status=None, **kwargs):
data = {'vip': {'name': name,
'subnet_id': self._subnet_id,
'pool_id': pool_id,
'protocol': protocol,
'port': port,
'protocol_port': protocol_port,
'admin_state_up': admin_state_up,
'tenant_id': self._tenant_id}}
for arg in ('description', 'address',
for arg in ('description', 'subnet_id', 'address',
'session_persistence', 'connection_limit'):
if arg in kwargs and kwargs[arg] is not None:
data['vip'][arg] = kwargs[arg]
@ -119,10 +121,10 @@ class LoadBalancerPluginDbTestCase(test_db_plugin.QuantumDbPluginV2TestCase):
return pool_res
def _create_member(self, fmt, address, port, admin_state_up,
def _create_member(self, fmt, address, protocol_port, admin_state_up,
expected_res_status=None, **kwargs):
data = {'member': {'address': address,
'port': port,
'protocol_port': protocol_port,
'admin_state_up': admin_state_up,
'tenant_id': self._tenant_id}}
for arg in ('weight', 'pool_id'):
@ -164,44 +166,31 @@ class LoadBalancerPluginDbTestCase(test_db_plugin.QuantumDbPluginV2TestCase):
return self.ext_api
@contextlib.contextmanager
def vip(self, fmt=None, name='vip1', pool=None,
protocol='HTTP', port=80, admin_state_up=True, no_delete=False,
address="172.16.1.123", **kwargs):
def vip(self, fmt=None, name='vip1', pool=None, subnet=None,
protocol='HTTP', protocol_port=80, admin_state_up=True,
no_delete=False, **kwargs):
if not fmt:
fmt = self.fmt
if not pool:
with self.pool() as pool:
pool_id = pool['pool']['id']
with test_db_plugin.optional_ctx(subnet, self.subnet) as tmp_subnet:
with test_db_plugin.optional_ctx(pool, self.pool) as tmp_pool:
pool_id = tmp_pool['pool']['id']
res = self._create_vip(fmt,
name,
pool_id,
protocol,
port,
protocol_port,
admin_state_up,
address=address,
subnet_id=tmp_subnet['subnet']['id'],
**kwargs)
vip = self.deserialize(fmt or self.fmt, res)
if res.status_int >= 400:
raise webob.exc.HTTPClientError(code=res.status_int)
yield vip
if not no_delete:
self._delete('vips', vip['vip']['id'])
else:
pool_id = pool['pool']['id']
res = self._create_vip(fmt,
name,
pool_id,
protocol,
port,
admin_state_up,
address=address,
**kwargs)
vip = self.deserialize(fmt or self.fmt, res)
if res.status_int >= 400:
raise webob.exc.HTTPClientError(code=res.status_int)
yield vip
if not no_delete:
self._delete('vips', vip['vip']['id'])
try:
yield vip
finally:
if not no_delete:
self._delete('vips', vip['vip']['id'])
@contextlib.contextmanager
def pool(self, fmt=None, name='pool1', lb_method='ROUND_ROBIN',
@ -218,27 +207,30 @@ class LoadBalancerPluginDbTestCase(test_db_plugin.QuantumDbPluginV2TestCase):
pool = self.deserialize(fmt or self.fmt, res)
if res.status_int >= 400:
raise webob.exc.HTTPClientError(code=res.status_int)
yield pool
if not no_delete:
self._delete('pools', pool['pool']['id'])
try:
yield pool
finally:
if not no_delete:
self._delete('pools', pool['pool']['id'])
@contextlib.contextmanager
def member(self, fmt=None, address='192.168.1.100',
port=80, admin_state_up=True, no_delete=False,
**kwargs):
def member(self, fmt=None, address='192.168.1.100', protocol_port=80,
admin_state_up=True, no_delete=False, **kwargs):
if not fmt:
fmt = self.fmt
res = self._create_member(fmt,
address,
port,
protocol_port,
admin_state_up,
**kwargs)
member = self.deserialize(fmt or self.fmt, res)
if res.status_int >= 400:
raise webob.exc.HTTPClientError(code=res.status_int)
yield member
if not no_delete:
self._delete('members', member['member']['id'])
try:
yield member
finally:
if not no_delete:
self._delete('members', member['member']['id'])
@contextlib.contextmanager
def health_monitor(self, fmt=None, type='TCP',
@ -270,99 +262,84 @@ class LoadBalancerPluginDbTestCase(test_db_plugin.QuantumDbPluginV2TestCase):
else:
for arg in http_related_attributes:
self.assertIsNone(the_health_monitor.get(arg))
yield health_monitor
if not no_delete:
self._delete('health_monitors', the_health_monitor['id'])
try:
yield health_monitor
finally:
if not no_delete:
self._delete('health_monitors', the_health_monitor['id'])
class TestLoadBalancer(LoadBalancerPluginDbTestCase):
def test_create_vip(self):
name = 'vip1'
keys = [('name', name),
('subnet_id', self._subnet_id),
('address', "172.16.1.123"),
('port', 80),
('protocol', 'HTTP'),
('connection_limit', -1),
('admin_state_up', True),
('status', 'PENDING_CREATE')]
def test_create_vip(self, **extras):
expected = {
'name': 'vip1',
'description': '',
'protocol_port': 80,
'protocol': 'HTTP',
'connection_limit': -1,
'admin_state_up': True,
'status': 'PENDING_CREATE',
'tenant_id': self._tenant_id,
}
with self.vip(name=name) as vip:
for k, v in keys:
self.assertEqual(vip['vip'][k], v)
expected.update(extras)
with self.subnet() as subnet:
expected['subnet_id'] = subnet['subnet']['id']
name = expected['name']
with self.vip(name=name, subnet=subnet, **extras) as vip:
for k in ('id', 'address', 'port_id', 'pool_id'):
self.assertTrue(vip['vip'].get(k, None))
self.assertEqual(
dict((k, v)
for k, v in vip['vip'].items() if k in expected),
expected
)
return vip
def test_create_vip_with_invalid_values(self):
name = 'vip3'
invalid = {
'protocol': 'UNSUPPORTED',
'protocol_port': 'NOT_AN_INT',
'protocol_port': 1000500,
'subnet': {'subnet': {'id': 'invalid-subnet'}}
}
vip = self.vip(name=name, protocol='UNSUPPORTED')
self.assertRaises(webob.exc.HTTPClientError, vip.__enter__)
for param, value in invalid.items():
kwargs = {'name': 'the-vip', param: value}
with testtools.ExpectedException(webob.exc.HTTPClientError):
with self.vip(**kwargs):
pass
vip = self.vip(name=name, port='NOT_AN_INT')
self.assertRaises(webob.exc.HTTPClientError, vip.__enter__)
def test_create_vip_with_address(self):
self.test_create_vip(address='10.0.0.7')
# 100500 is not a valid port number
vip = self.vip(name=name, port='100500')
self.assertRaises(webob.exc.HTTPClientError, vip.__enter__)
# 192.168.130.130.130 is not a valid IP address
vip = self.vip(name=name, address='192.168.130.130.130')
self.assertRaises(webob.exc.HTTPClientError, vip.__enter__)
def test_create_vip_with_address_outside_subnet(self):
with testtools.ExpectedException(webob.exc.HTTPClientError):
self.test_create_vip(address='9.9.9.9')
def test_create_vip_with_session_persistence(self):
name = 'vip2'
keys = [('name', name),
('subnet_id', self._subnet_id),
('address', "172.16.1.123"),
('port', 80),
('protocol', 'HTTP'),
('session_persistence', {'type': "HTTP_COOKIE"}),
('connection_limit', -1),
('admin_state_up', True),
('status', 'PENDING_CREATE')]
with self.vip(name=name,
session_persistence={'type': "HTTP_COOKIE"}) as vip:
for k, v in keys:
self.assertEqual(vip['vip'][k], v)
self.test_create_vip(session_persistence={'type': 'HTTP_COOKIE'})
def test_create_vip_with_session_persistence_with_app_cookie(self):
name = 'vip7'
keys = [('name', name),
('subnet_id', self._subnet_id),
('address', "172.16.1.123"),
('port', 80),
('protocol', 'HTTP'),
('session_persistence', {'type': "APP_COOKIE",
'cookie_name': 'sessionId'}),
('connection_limit', -1),
('admin_state_up', True),
('status', 'PENDING_CREATE')]
with self.vip(name=name,
session_persistence={'type': "APP_COOKIE",
'cookie_name': 'sessionId'}) as vip:
for k, v in keys:
self.assertEqual(vip['vip'][k], v)
sp = {'type': 'APP_COOKIE', 'cookie_name': 'sessionId'}
self.test_create_vip(session_persistence=sp)
def test_create_vip_with_session_persistence_unsupported_type(self):
name = 'vip5'
vip = self.vip(name=name, session_persistence={'type': "UNSUPPORTED"})
self.assertRaises(webob.exc.HTTPClientError, vip.__enter__)
with testtools.ExpectedException(webob.exc.HTTPClientError):
self.test_create_vip(session_persistence={'type': 'UNSUPPORTED'})
def test_create_vip_with_unnecessary_cookie_name(self):
name = 'vip8'
s_p = {'type': "SOURCE_IP", 'cookie_name': 'sessionId'}
vip = self.vip(name=name, session_persistence=s_p)
self.assertRaises(webob.exc.HTTPClientError, vip.__enter__)
sp = {'type': "SOURCE_IP", 'cookie_name': 'sessionId'}
with testtools.ExpectedException(webob.exc.HTTPClientError):
self.test_create_vip(session_persistence=sp)
def test_create_vip_with_session_persistence_without_cookie_name(self):
name = 'vip6'
vip = self.vip(name=name, session_persistence={'type': "APP_COOKIE"})
self.assertRaises(webob.exc.HTTPClientError, vip.__enter__)
sp = {'type': "APP_COOKIE"}
with testtools.ExpectedException(webob.exc.HTTPClientError):
self.test_create_vip(session_persistence=sp)
def test_reset_session_persistence(self):
name = 'vip4'
@ -386,14 +363,14 @@ class TestLoadBalancer(LoadBalancerPluginDbTestCase):
def test_update_vip(self):
name = 'new_vip'
keys = [('name', name),
('subnet_id', self._subnet_id),
('address', "172.16.1.123"),
('port', 80),
('address', "10.0.0.2"),
('protocol_port', 80),
('connection_limit', 100),
('admin_state_up', False),
('status', 'PENDING_UPDATE')]
with self.vip(name=name) as vip:
keys.append(('subnet_id', vip['vip']['subnet_id']))
data = {'vip': {'name': name,
'connection_limit': 100,
'session_persistence':
@ -416,14 +393,13 @@ class TestLoadBalancer(LoadBalancerPluginDbTestCase):
def test_show_vip(self):
name = "vip_show"
keys = [('name', name),
('subnet_id', self._subnet_id),
('address', "172.16.1.123"),
('port', 80),
('address', "10.0.0.10"),
('protocol_port', 80),
('protocol', 'HTTP'),
('connection_limit', -1),
('admin_state_up', True),
('status', 'PENDING_CREATE')]
with self.vip(name=name) as vip:
with self.vip(name=name, address='10.0.0.10') as vip:
req = self.new_show_request('vips',
vip['vip']['id'])
res = self.deserialize(self.fmt, req.get_response(self.ext_api))
@ -433,44 +409,52 @@ class TestLoadBalancer(LoadBalancerPluginDbTestCase):
def test_list_vips(self):
name = "vips_list"
keys = [('name', name),
('subnet_id', self._subnet_id),
('address', "172.16.1.123"),
('port', 80),
('address', "10.0.0.2"),
('protocol_port', 80),
('protocol', 'HTTP'),
('connection_limit', -1),
('admin_state_up', True),
('status', 'PENDING_CREATE')]
with self.vip(name=name):
with self.vip(name=name) as vip:
keys.append(('subnet_id', vip['vip']['subnet_id']))
req = self.new_list_request('vips')
res = self.deserialize(self.fmt, req.get_response(self.ext_api))
self.assertEqual(len(res), 1)
for k, v in keys:
self.assertEqual(res['vips'][0][k], v)
def test_list_vips_with_sort_emulated(self):
with contextlib.nested(self.vip(name='vip1', port=81),
self.vip(name='vip2', port=82),
self.vip(name='vip3', port=82)
) as (vip1, vip2, vip3):
self._test_list_with_sort('vip', (vip1, vip3, vip2),
[('port', 'asc'), ('name', 'desc')])
with self.subnet() as subnet:
with contextlib.nested(
self.vip(name='vip1', subnet=subnet, protocol_port=81),
self.vip(name='vip2', subnet=subnet, protocol_port=82),
self.vip(name='vip3', subnet=subnet, protocol_port=82)
) as (vip1, vip2, vip3):
self._test_list_with_sort(
'vip',
(vip1, vip3, vip2),
[('protocol_port', 'asc'), ('name', 'desc')]
)
def test_list_vips_with_pagination_emulated(self):
with contextlib.nested(self.vip(name='vip1'),
self.vip(name='vip2'),
self.vip(name='vip3')
) as (vip1, vip2, vip3):
self._test_list_with_pagination('vip',
(vip1, vip2, vip3),
('name', 'asc'), 2, 2)
with self.subnet() as subnet:
with contextlib.nested(self.vip(name='vip1', subnet=subnet),
self.vip(name='vip2', subnet=subnet),
self.vip(name='vip3', subnet=subnet)
) as (vip1, vip2, vip3):
self._test_list_with_pagination('vip',
(vip1, vip2, vip3),
('name', 'asc'), 2, 2)
def test_list_vips_with_pagination_reverse_emulated(self):
with contextlib.nested(self.vip(name='vip1'),
self.vip(name='vip2'),
self.vip(name='vip3')
) as (vip1, vip2, vip3):
self._test_list_with_pagination_reverse('vip',
(vip1, vip2, vip3),
('name', 'asc'), 2, 2)
with self.subnet() as subnet:
with contextlib.nested(self.vip(name='vip1', subnet=subnet),
self.vip(name='vip2', subnet=subnet),
self.vip(name='vip3', subnet=subnet)
) as (vip1, vip2, vip3):
self._test_list_with_pagination_reverse('vip',
(vip1, vip2, vip3),
('name', 'asc'), 2, 2)
def test_create_pool_with_invalid_values(self):
name = 'pool3'
@ -519,7 +503,7 @@ class TestLoadBalancer(LoadBalancerPluginDbTestCase):
self.assertEqual(len(pool_updated['pool']['members']), 1)
keys = [('address', '192.168.1.100'),
('port', 80),
('protocol_port', 80),
('weight', 1),
('pool_id', pool_id),
('admin_state_up', True),
@ -584,10 +568,10 @@ class TestLoadBalancer(LoadBalancerPluginDbTestCase):
with self.pool() as pool:
pool_id = pool['pool']['id']
with self.member(address='192.168.1.100',
port=80,
protocol_port=80,
pool_id=pool_id) as member1:
with self.member(address='192.168.1.101',
port=80,
protocol_port=80,
pool_id=pool_id) as member2:
req = self.new_show_request('pools',
pool_id,
@ -606,7 +590,7 @@ class TestLoadBalancer(LoadBalancerPluginDbTestCase):
with self.pool(name="pool2") as pool2:
keys = [('address', "192.168.1.100"),
('tenant_id', self._tenant_id),
('port', 80),
('protocol_port', 80),
('weight', 10),
('pool_id', pool2['pool']['id']),
('admin_state_up', False),
@ -686,7 +670,7 @@ class TestLoadBalancer(LoadBalancerPluginDbTestCase):
with self.pool() as pool:
keys = [('address', "192.168.1.100"),
('tenant_id', self._tenant_id),
('port', 80),
('protocol_port', 80),
('weight', 1),
('pool_id', pool['pool']['id']),
('admin_state_up', True),
@ -705,40 +689,40 @@ class TestLoadBalancer(LoadBalancerPluginDbTestCase):
def test_list_members_with_sort_emulated(self):
with self.pool() as pool:
with contextlib.nested(self.member(pool_id=pool['pool']['id'],
port=81),
protocol_port=81),
self.member(pool_id=pool['pool']['id'],
port=82),
protocol_port=82),
self.member(pool_id=pool['pool']['id'],
port=83)
protocol_port=83)
) as (m1, m2, m3):
self._test_list_with_sort('member', (m3, m2, m1),
[('port', 'desc')])
[('protocol_port', 'desc')])
def test_list_members_with_pagination_emulated(self):
with self.pool() as pool:
with contextlib.nested(self.member(pool_id=pool['pool']['id'],
port=81),
protocol_port=81),
self.member(pool_id=pool['pool']['id'],
port=82),
protocol_port=82),
self.member(pool_id=pool['pool']['id'],
port=83)
protocol_port=83)
) as (m1, m2, m3):
self._test_list_with_pagination('member',
(m1, m2, m3),
('port', 'asc'), 2, 2)
self._test_list_with_pagination(
'member', (m1, m2, m3), ('protocol_port', 'asc'), 2, 2
)
def test_list_members_with_pagination_reverse_emulated(self):
with self.pool() as pool:
with contextlib.nested(self.member(pool_id=pool['pool']['id'],
port=81),
protocol_port=81),
self.member(pool_id=pool['pool']['id'],
port=82),
protocol_port=82),
self.member(pool_id=pool['pool']['id'],
port=83)
protocol_port=83)
) as (m1, m2, m3):
self._test_list_with_pagination_reverse('member',
(m1, m2, m3),
('port', 'asc'), 2, 2)
self._test_list_with_pagination_reverse(
'member', (m1, m2, m3), ('protocol_port', 'asc'), 2, 2
)
def test_create_healthmonitor(self):
keys = [('type', "TCP"),

View File

@ -93,7 +93,7 @@ class LoadBalancerExtensionTestCase(testlib_api.WebTestCase):
'description': 'descr_vip1',
'subnet_id': _uuid(),
'address': '127.0.0.1',
'port': 80,
'protocol_port': 80,
'protocol': 'HTTP',
'pool_id': _uuid(),
'session_persistence': {'type': 'HTTP_COOKIE'},
@ -293,7 +293,7 @@ class LoadBalancerExtensionTestCase(testlib_api.WebTestCase):
member_id = _uuid()
data = {'member': {'pool_id': _uuid(),
'address': '127.0.0.1',
'port': 80,
'protocol_port': 80,
'weight': 1,
'admin_state_up': True,
'tenant_id': _uuid()}}

View File

@ -19,8 +19,11 @@ import webob.exc as webexc
import quantum
from quantum.api import extensions
from quantum.api.v2 import attributes
from quantum.api.v2 import router
from quantum.common import config
from quantum import context as q_context
from quantum.db import api as db
from quantum.db import db_base_plugin_v2
from quantum.db import l3_db
from quantum.db.loadbalancer import loadbalancer_db as lb_db
@ -171,6 +174,10 @@ class RouterServiceInsertionTestCase(testtools.TestCase):
# Ensure 'stale' patched copies of the plugin are never returned
quantum.manager.QuantumManager._instance = None
# Ensure the database is reset between tests
db._ENGINE = None
db._MAKER = None
# Ensure existing ExtensionManager is not used
ext_mgr = extensions.PluginAwareExtensionManager(
@ -188,6 +195,48 @@ class RouterServiceInsertionTestCase(testtools.TestCase):
res = self._do_request('GET', _get_path('service-types'))
self._service_type_id = res['service_types'][0]['id']
self._setup_core_resources()
# FIXME (markmcclain): The test setup makes it difficult to add core
# via the api. In the interim we'll create directly using the plugin with
# the side effect of polluting the fixture database until tearDown.
def _setup_core_resources(self):
core_plugin = quantum.manager.QuantumManager.get_plugin()
self._network = core_plugin.create_network(
q_context.get_admin_context(),
{
'network':
{
'tenant_id': self._tenant_id,
'name': 'test net',
'admin_state_up': True,
'shared': False,
}
}
)
self._subnet = core_plugin.create_subnet(
q_context.get_admin_context(),
{
'subnet':
{
'network_id': self._network['id'],
'name': 'test subnet',
'cidr': '192.168.1.0/24',
'ip_version': 4,
'gateway_ip': '192.168.1.1',
'allocation_pools': attributes.ATTR_NOT_SPECIFIED,
'dns_nameservers': attributes.ATTR_NOT_SPECIFIED,
'host_routes': attributes.ATTR_NOT_SPECIFIED,
'enable_dhcp': True,
}
}
)
self._subnet_id = self._subnet['id']
def _do_request(self, method, path, data=None, params=None, action=None):
content_type = 'application/json'
body = None
@ -267,7 +316,6 @@ class RouterServiceInsertionTestCase(testtools.TestCase):
'DELETE', _get_path('routers/{0}'.format(router['id'])))
def _test_lb_setup(self):
self._subnet_id = _uuid()
router = self._router_create(self._service_type_id)
self._router_id = router['id']
@ -337,10 +385,10 @@ class RouterServiceInsertionTestCase(testtools.TestCase):
"tenant_id": self._tenant_id,
"name": "test",
"protocol": "HTTP",
"port": 80,
"protocol_port": 80,
"subnet_id": self._subnet_id,
"pool_id": self._pool_id,
"address": "192.168.1.101",
"address": "192.168.1.102",
"connection_limit": 100,
"admin_state_up": True,
"router_id": router_id
@ -361,7 +409,6 @@ class RouterServiceInsertionTestCase(testtools.TestCase):
def _test_resource_create(self, res):
getattr(self, "_test_{0}_setup".format(res))()
obj = getattr(self, "_{0}_create".format(res))()
obj = getattr(self, "_{0}_create".format(res))(self._router_id)
self.assertEqual(obj['router_id'], self._router_id)
@ -389,12 +436,15 @@ class RouterServiceInsertionTestCase(testtools.TestCase):
_get_path('lb/{0}s/{1}'.format(res, obj['id'])))
self.assertEqual(updated[res][update_attr], update_value)
def _test_resource_delete(self, res):
def _test_resource_delete(self, res, with_router_id):
getattr(self, "_test_{0}_setup".format(res))()
obj = getattr(self, "_{0}_create".format(res))()
self._do_request(
'DELETE', _get_path('lb/{0}s/{1}'.format(res, obj['id'])))
obj = getattr(self, "_{0}_create".format(res))(self._router_id)
func = getattr(self, "_{0}_create".format(res))
if with_router_id:
obj = func(self._router_id)
else:
obj = func()
self._do_request(
'DELETE', _get_path('lb/{0}s/{1}'.format(res, obj['id'])))
@ -407,8 +457,11 @@ class RouterServiceInsertionTestCase(testtools.TestCase):
def test_pool_update_without_router_id(self):
self._test_resource_update('pool', False, 'name', _uuid())
def test_pool_delete(self):
self._test_resource_delete('pool')
def test_pool_delete_with_router_id(self):
self._test_resource_delete('pool', True)
def test_pool_delete_without_router_id(self):
self._test_resource_delete('pool', False)
def test_health_monitor_create(self):
self._test_resource_create('health_monitor')
@ -419,8 +472,11 @@ class RouterServiceInsertionTestCase(testtools.TestCase):
def test_health_monitor_update_without_router_id(self):
self._test_resource_update('health_monitor', False, 'timeout', 2)
def test_health_monitor_delete(self):
self._test_resource_delete('health_monitor')
def test_health_monitor_delete_with_router_id(self):
self._test_resource_delete('health_monitor', True)
def test_health_monitor_delete_without_router_id(self):
self._test_resource_delete('health_monitor', False)
def test_vip_create(self):
self._test_resource_create('vip')
@ -431,5 +487,8 @@ class RouterServiceInsertionTestCase(testtools.TestCase):
def test_vip_update_without_router_id(self):
self._test_resource_update('vip', False, 'name', _uuid())
def test_vip_delete(self):
self._test_resource_delete('vip')
def test_vip_delete_with_router_id(self):
self._test_resource_delete('vip', True)
def test_vip_delete_without_router_id(self):
self._test_resource_delete('vip', False)