Initial creation of db models, modules, and tests

Added sqlalchemy models mirroring initial migration
Added engine and session methods based off oslo.db
Added base db test based off of oslo.db
Added model tests
Added data models
Added data model tests
Added migration for one to many load balancer to amphora
Added migration for name and URL size changes
Added smarter comparison method for data models

Implements: blueprint initial-db-models

Change-Id: I8421093f0952d5e3ef287bfd4979cc5a83af6c09
This commit is contained in:
Brandon Logan 2014-08-22 11:38:43 -05:00 committed by Trevor Vardeman
parent 13b015daea
commit f482487c8c
11 changed files with 1633 additions and 19 deletions

View File

@ -1,28 +1,52 @@
# Copyright (c) 2012-2014 OpenStack Foundation.
# Copyright 2014 Rackspace
#
# 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
# 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
# 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.
# 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.
LB_METHOD_ROUND_ROBIN = 'ROUND_ROBIN'
LB_METHOD_LEAST_CONNECTIONS = 'LEAST_CONNECTIONS'
LB_METHOD_SOURCE_IP = 'SOURCE_IP'
LB_ALGORITHM_ROUND_ROBIN = 'ROUND_ROBIN'
LB_ALGORITHM_LEAST_CONNECTIONS = 'LEAST_CONNECTIONS'
LB_ALGORITHM_SOURCE_IP = 'SOURCE_IP'
SUPPORTED_LB_ALGORITHMS = (LB_ALGORITHM_LEAST_CONNECTIONS,
LB_ALGORITHM_ROUND_ROBIN,
LB_ALGORITHM_SOURCE_IP)
PROTOCOL_TCP = 'TCP'
PROTOCOL_HTTP = 'HTTP'
PROTOCOL_HTTPS = 'HTTPS'
PROTOCOL_UDP = 'UDP'
SESSION_PERSISTENCE_SOURCE_IP = 'SOURCE_IP'
SESSION_PERSISTENCE_HTTP_COOKIE = 'HTTP_COOKIE'
SUPPORTED_SP_TYPES = (SESSION_PERSISTENCE_SOURCE_IP,
SESSION_PERSISTENCE_HTTP_COOKIE)
HEALTH_MONITOR_PING = 'PING'
HEALTH_MONITOR_TCP = 'TCP'
HEALTH_MONITOR_HTTP = 'HTTP'
HEALTH_MONITOR_HTTPS = 'HTTPS'
SUPPORTED_HEALTH_MONITOR_TYPES = (HEALTH_MONITOR_HTTP, HEALTH_MONITOR_HTTPS,
HEALTH_MONITOR_PING, HEALTH_MONITOR_TCP)
PROTOCOL_TCP = 'TCP'
PROTOCOL_HTTP = 'HTTP'
PROTOCOL_HTTPS = 'HTTPS'
SUPPORTED_PROTOCOLS = (PROTOCOL_TCP, PROTOCOL_HTTPS, PROTOCOL_HTTP)
ACTIVE = 'ACTIVE'
PENDING_DELETE = 'PENDING_DELETE'
PENDING_UPDATE = 'PENDING_UPDATE'
PENDING_CREATE = 'PENDING_CREATE'
DELETED = 'DELETED'
ERROR = 'ERROR'
SUPPORTED_PROVISIONING_STATUSES = (ACTIVE, PENDING_DELETE, PENDING_CREATE,
PENDING_UPDATE, DELETED, ERROR)
ONLINE = 'ONLINE'
OFFLINE = 'OFFLINE'
DEGRADED = 'DEGRADED'
ERROR = 'ERROR'
SUPPORTED_OPERATING_STATUSES = (ONLINE, OFFLINE, DEGRADED, ERROR)

View File

@ -0,0 +1,193 @@
# Copyright (c) 2014 Rackspace
# 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.
class BaseDataModel(object):
# NOTE(brandon-logan) This does not discover dicts for relationship
# attributes.
def to_dict(self):
ret = {}
for attr in self.__dict__:
if (attr.startswith('_') or
isinstance(getattr(self, attr), BaseDataModel)):
continue
ret[attr] = self.__dict__[attr]
return ret
def __eq__(self, other):
if isinstance(other, self.__class__):
return self.to_dict() == other.to_dict()
return False
class SessionPersistence(BaseDataModel):
def __init__(self, pool_id=None, type=None, cookie_name=None,
pool=None):
self.pool_id = pool_id
self.type = type
self.cookie_name = cookie_name
self.pool = pool
class ListenerStatistics(BaseDataModel):
def __init__(self, listener_id=None, bytes_in=None, bytes_out=None,
active_connections=None, total_connections=None,
listener=None):
self.listener_id = listener_id
self.bytes_in = bytes_in
self.bytes_out = bytes_out
self.active_connections = active_connections
self.total_connections = total_connections
self.listener = listener
class HealthMonitor(BaseDataModel):
def __init__(self, id=None, tenant_id=None, pool_id=None, type=None,
delay=None, timeout=None, fall_threshold=None,
rise_threshold=None, http_method=None, url_path=None,
expected_codes=None, enabled=None, pool=None):
self.id = id
self.tenant_id = tenant_id
self.pool_id = pool_id
self.type = type
self.delay = delay
self.timeout = timeout
self.fall_threshold = fall_threshold
self.rise_threshold = rise_threshold
self.http_method = http_method
self.url_path = url_path
self.expected_codes = expected_codes
self.enabled = enabled
self.pool = pool
class Pool(BaseDataModel):
def __init__(self, id=None, tenant_id=None, name=None, description=None,
protocol=None, lb_algorithm=None, enabled=None,
operating_status=None, members=None, health_monitor=None,
session_persistence=None, listener=None):
self.id = id
self.tenant_id = tenant_id
self.name = name
self.description = description
self.protocol = protocol
self.lb_algorithm = lb_algorithm
self.enabled = enabled
self.operating_status = operating_status
self.members = members or []
self.health_monitor = health_monitor
self.session_persistence = session_persistence
self.listener = listener
class Member(BaseDataModel):
def __init__(self, id=None, tenant_id=None, pool_id=None, ip_address=None,
protocol_port=None, weight=None, enabled=None,
subnet_id=None, operating_status=None, pool=None):
self.id = id
self.tenant_id = tenant_id
self.pool_id = pool_id
self.ip_address = ip_address
self.protocol_port = protocol_port
self.weight = weight
self.enabled = enabled
self.subnet_id = subnet_id
self.operating_status = operating_status
self.pool = pool
class Listener(BaseDataModel):
def __init__(self, id=None, tenant_id=None, name=None, description=None,
default_pool_id=None, load_balancer_id=None, protocol=None,
protocol_port=None, connection_limit=None,
enabled=None, provisioning_status=None, operating_status=None,
default_tls_container_id=None, stats=None, default_pool=None,
load_balancer=None, sni_containers=None):
self.id = id
self.tenant_id = tenant_id
self.name = name
self.description = description
self.default_pool_id = default_pool_id
self.load_balancer_id = load_balancer_id
self.protocol = protocol
self.protocol_port = protocol_port
self.connection_limit = connection_limit
self.enabled = enabled
self.provisioning_status = provisioning_status
self.operating_status = operating_status
self.default_tls_container_id = default_tls_container_id
self.stats = stats
self.default_pool = default_pool
self.load_balancer = load_balancer
self.sni_containers = sni_containers
class LoadBalancer(BaseDataModel):
def __init__(self, id=None, tenant_id=None, name=None, description=None,
provisioning_status=None, operating_status=None, enabled=None,
vip=None, listeners=None, amphorae=None):
self.id = id
self.tenant_id = tenant_id
self.name = name
self.description = description
self.provisioning_status = provisioning_status
self.operating_status = operating_status
self.enabled = enabled
self.vip = vip
self.listeners = listeners or []
self.amphorae = amphorae or []
class Vip(BaseDataModel):
def __init__(self, load_balancer_id=None, ip_address=None,
net_port_id=None, subnet_id=None, floating_ip_id=None,
floating_ip_network_id=None, load_balancer=None):
self.load_balancer_id = load_balancer_id
self.ip_address = ip_address
self.net_port_id = net_port_id
self.subnet_id = subnet_id
self.floating_ip_id = floating_ip_id
self.floating_ip_network_id = floating_ip_network_id
self.load_balancer = load_balancer
class SNI(BaseDataModel):
def __init__(self, listener_id=None, position=None, listener=None,
tls_container_id=None):
self.listener_id = listener_id
self.position = position
self.listener = listener
self.tls_container_id = tls_container_id
class Amphora(BaseDataModel):
def __init__(self, id=None, load_balancer_id=None, host_id=None,
status=None, load_balancer=None):
self.id = id
self.load_balancer_id = load_balancer_id
self.host_id = host_id
self.status = status
self.load_balancer = load_balancer

35
octavia/db/api.py Normal file
View File

@ -0,0 +1,35 @@
# Copyright 2014 Rackspace
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo.config import cfg
from oslo.db.sqlalchemy import session as db_session
_FACADE = None
def _create_facade_lazily():
global _FACADE
if _FACADE is None:
_FACADE = db_session.EngineFacade.from_config(cfg.CONF)
return _FACADE
def get_engine():
facade = _create_facade_lazily()
return facade.get_engine()
def get_session(**kwargs):
facade = _create_facade_lazily()
return facade.get_session(**kwargs)

70
octavia/db/base_models.py Normal file
View File

@ -0,0 +1,70 @@
# Copyright 2014 Rackspace
#
# 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 octavia.openstack.common import uuidutils
from oslo.db.sqlalchemy import models
import sqlalchemy as sa
from sqlalchemy.ext import declarative
from sqlalchemy.orm import collections
class OctaviaBase(models.ModelBase):
__data_model__ = None
def to_data_model(self, calling_cls=None):
if not self.__data_model__:
raise NotImplementedError
dm_kwargs = {}
for column in self.__table__.columns:
dm_kwargs[column.name] = getattr(self, column.name)
attr_names = [attr_name for attr_name in dir(self)
if not attr_name.startswith('_')]
for attr_name in attr_names:
attr = getattr(self, attr_name)
if isinstance(attr, OctaviaBase):
if attr.__class__ != calling_cls:
dm_kwargs[attr_name] = attr.to_data_model(
calling_cls=self.__class__)
elif isinstance(attr, collections.InstrumentedList):
dm_kwargs[attr_name] = []
for item in attr:
if isinstance(item, OctaviaBase):
if attr.__class__ != calling_cls:
dm_kwargs[attr_name].append(
item.to_data_model(calling_cls=self.__class__))
else:
dm_kwargs[attr_name].append(item)
return self.__data_model__(**dm_kwargs)
class LookupTableMixin(object):
"""Mixin to add to classes that are lookup tables."""
name = sa.Column(sa.String(255), primary_key=True, nullable=False)
description = sa.Column(sa.String(255), nullable=True)
class IdMixin(object):
"""Id mixin, add to subclasses that have a tenant."""
id = sa.Column(sa.String(36), primary_key=True,
default=uuidutils.generate_uuid)
class TenantMixin(object):
"""Tenant mixin, add to subclasses that have a tenant."""
tenant_id = sa.Column(sa.String(36))
BASE = declarative.declarative_base(cls=OctaviaBase)

View File

@ -0,0 +1,58 @@
# Copyright 2014 Rackspace
#
# 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.
'''update url and name size
Revision ID: 13500e2e978d
Revises: 4c094013699a
Create Date: 2014-09-18 16:07:04.859812
'''
# revision identifiers, used by Alembic.
revision = '13500e2e978d'
down_revision = '4c094013699a'
from alembic import op
import sqlalchemy as sa
def upgrade():
op.alter_column(u'provisioning_status', u'name',
existing_type=sa.String(255))
op.alter_column(u'operating_status', u'name',
existing_type=sa.String(255))
op.alter_column(u'health_monitor_type', u'name',
existing_type=sa.String(255))
op.alter_column(u'protocol', u'name',
existing_type=sa.String(255))
op.alter_column(u'algorithm', u'name',
existing_type=sa.String(255))
op.alter_column(u'session_persistence_type', u'name',
existing_type=sa.String(255))
def downgrade():
op.alter_column(u'provisioning_status', u'name',
existing_type=sa.String(30))
op.alter_column(u'operating_status', u'name',
existing_type=sa.String(30))
op.alter_column(u'health_monitor_type', u'name',
existing_type=sa.String(30))
op.alter_column(u'protocol', u'name',
existing_type=sa.String(30))
op.alter_column(u'algorithm', u'name',
existing_type=sa.String(30))
op.alter_column(u'session_persistence_type', u'name',
existing_type=sa.String(30))

View File

@ -0,0 +1,76 @@
# Copyright 2014 Rackspace
#
# 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.
'''update load balancer amphora relationship
Revision ID: 4c094013699a
Revises: 35dee79d5865
Create Date: 2014-09-15 14:42:44.875448
'''
# revision identifiers, used by Alembic.
revision = '4c094013699a'
down_revision = '35dee79d5865'
from alembic import op
import sqlalchemy as sa
def upgrade():
op.add_column(
u'amphora',
sa.Column(u'load_balancer_id', sa.String(36),
sa.ForeignKey(u'load_balancer.id',
name=u'fk_amphora_load_balancer_id'),
nullable=True)
)
op.drop_table(u'load_balancer_amphora')
op.drop_constraint(
u'fk_container_provisioning_status_name', u'amphora',
type_=u'foreignkey'
)
op.create_foreign_key(
u'fk_amphora_provisioning_status_name', u'amphora',
u'provisioning_status', [u'status'], [u'name']
)
def downgrade():
op.drop_constraint(
u'fk_amphora_load_balancer_id', u'amphora', type_=u'foreignkey'
)
op.drop_column(
u'amphora', u'load_balancer_id'
)
op.create_table(
u'load_balancer_amphora',
sa.Column(u'amphora_id', sa.String(36), nullable=False),
sa.Column(u'load_balancer_id', sa.String(36), nullable=False),
sa.ForeignKeyConstraint(
[u'load_balancer_id'], [u'load_balancer.id'],
name=u'fk_load_balancer_amphora_load_balancer_id'),
sa.ForeignKeyConstraint([u'amphora_id'],
[u'amphora.id'],
name=u'fk_load_balancer_amphora_id'),
sa.PrimaryKeyConstraint(u'amphora_id', u'load_balancer_id')
)
op.drop_constraint(
u'fk_amphora_provisioning_status_name', u'amphora',
type_=u'foreignkey'
)
op.create_foreign_key(
u'fk_container_provisioning_status_name', u'amphora',
u'provisioning_status', [u'status'], [u'name']
)

327
octavia/db/models.py Normal file
View File

@ -0,0 +1,327 @@
# Copyright 2014 Rackspace
#
# 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 sqlalchemy as sa
from sqlalchemy import orm
from sqlalchemy.orm import validates
from octavia.common import data_models
from octavia.db import base_models
class ProvisioningStatus(base_models.BASE, base_models.LookupTableMixin):
__tablename__ = "provisioning_status"
class OperatingStatus(base_models.BASE, base_models.LookupTableMixin):
__tablename__ = "operating_status"
class Protocol(base_models.BASE, base_models.LookupTableMixin):
__tablename__ = "protocol"
class Algorithm(base_models.BASE, base_models.LookupTableMixin):
__tablename__ = "algorithm"
class SessionPersistenceType(base_models.BASE, base_models.LookupTableMixin):
__tablename__ = "session_persistence_type"
class HealthMonitorType(base_models.BASE, base_models.LookupTableMixin):
__tablename__ = "health_monitor_type"
class SessionPersistence(base_models.BASE):
__data_model__ = data_models.SessionPersistence
__tablename__ = "session_persistence"
pool_id = sa.Column(
sa.String(36),
sa.ForeignKey("pool.id", name="fk_session_persistence_pool_id"),
nullable=False,
primary_key=True)
type = sa.Column(
sa.String(36),
sa.ForeignKey(
"session_persistence_type.name",
name="fk_session_persistence_session_persistence_type_name"),
nullable=False)
cookie_name = sa.Column(sa.String(255), nullable=True)
pool = orm.relationship("Pool", uselist=False,
backref=orm.backref("session_persistence",
uselist=False,
cascade="delete"))
class ListenerStatistics(base_models.BASE):
__data_model__ = data_models.ListenerStatistics
__tablename__ = "listener_statistics"
listener_id = sa.Column(
sa.String(36),
sa.ForeignKey("listener.id",
name="fk_listener_statistics_listener_id"),
primary_key=True,
nullable=False)
bytes_in = sa.Column(sa.BigInteger, nullable=False)
bytes_out = sa.Column(sa.BigInteger, nullable=False)
active_connections = sa.Column(sa.Integer, nullable=False)
total_connections = sa.Column(sa.BigInteger, nullable=False)
listener = orm.relationship("Listener", uselist=False,
backref=orm.backref("stats", uselist=False,
cascade="delete"))
@validates('bytes_in', 'bytes_out',
'active_connections', 'total_connections')
def validate_non_negative_int(self, key, value):
if value < 0:
data = {'key': key, 'value': value}
raise ValueError(data)
# TODO(trevor-vardeman): Repair this functionality after Openstack
# Common is in
# raise ValueError(_('The %(key)s field can not have '
# 'negative value. '
# 'Current value is %(value)d.') % data)
return value
class Member(base_models.BASE, base_models.IdMixin, base_models.TenantMixin):
__data_model__ = data_models.Member
__tablename__ = "member"
__table_args__ = (
sa.UniqueConstraint('pool_id', 'ip_address', 'protocol_port',
name='uq_member_pool_id_ip_address_protocol_port'),
)
pool_id = sa.Column(
sa.String(36),
sa.ForeignKey("pool.id", name="fk_member_pool_id"),
nullable=False)
subnet_id = sa.Column(sa.String(36), nullable=True)
ip_address = sa.Column(sa.String(64), nullable=False)
protocol_port = sa.Column(sa.Integer, nullable=False)
weight = sa.Column(sa.Integer, nullable=True)
operating_status = sa.Column(
sa.String(16),
sa.ForeignKey("operating_status.name",
name="fk_member_operating_status_name"),
nullable=False)
enabled = sa.Column(sa.Boolean(), nullable=False)
pool = orm.relationship("Pool", backref=orm.backref("members",
uselist=True,
cascade="delete"))
class HealthMonitor(base_models.BASE, base_models.IdMixin,
base_models.TenantMixin):
__data_model__ = data_models.HealthMonitor
__tablename__ = "health_monitor"
type = sa.Column(
sa.String(36),
sa.ForeignKey("health_monitor_type.name",
name="fk_health_monitor_health_monitor_type_name"),
nullable=False)
pool_id = sa.Column(
sa.String(36),
sa.ForeignKey("pool.id", name="fk_health_monitor_pool_id"),
nullable=False, primary_key=True)
delay = sa.Column(sa.Integer, nullable=False)
timeout = sa.Column(sa.Integer, nullable=False)
fall_threshold = sa.Column(sa.Integer, nullable=False)
rise_threshold = sa.Column(sa.Integer, nullable=False)
http_method = sa.Column(sa.String(16), nullable=True)
url_path = sa.Column(sa.String(2048), nullable=True)
expected_codes = sa.Column(sa.String(64), nullable=True)
enabled = sa.Column(sa.Boolean, nullable=False)
pool = orm.relationship("Pool", uselist=False,
backref=orm.backref("health_monitor",
uselist=False,
cascade="delete"))
class Pool(base_models.BASE, base_models.IdMixin, base_models.TenantMixin):
__data_model__ = data_models.Pool
__tablename__ = "pool"
name = sa.Column(sa.String(255), nullable=True)
description = sa.Column(sa.String(255), nullable=True)
protocol = sa.Column(
sa.String(16),
sa.ForeignKey("protocol.name", name="fk_pool_protocol_name"),
nullable=False)
lb_algorithm = sa.Column(
sa.String(16),
sa.ForeignKey("algorithm.name", name="fk_pool_algorithm_name"),
nullable=False)
operating_status = sa.Column(
sa.String(16),
sa.ForeignKey("operating_status.name",
name="fk_pool_operating_status_name"),
nullable=False)
enabled = sa.Column(sa.Boolean, nullable=False)
class LoadBalancer(base_models.BASE, base_models.IdMixin,
base_models.TenantMixin):
__data_model__ = data_models.LoadBalancer
__tablename__ = "load_balancer"
name = sa.Column(sa.String(255), nullable=True)
description = sa.Column(sa.String(255), nullable=True)
provisioning_status = sa.Column(
sa.String(16),
sa.ForeignKey("provisioning_status.name",
name="fk_load_balancer_provisioning_status_name"),
nullable=False)
operating_status = sa.Column(
sa.String(16),
sa.ForeignKey("operating_status.name",
name="fk_load_balancer_operating_status_name"),
nullable=False)
enabled = sa.Column(sa.Boolean, nullable=False)
amphorae = orm.relationship("Amphora", uselist=True,
backref=orm.backref("load_balancer",
uselist=False))
class Vip(base_models.BASE):
__data_model__ = data_models.Vip
__tablename__ = "vip"
load_balancer_id = sa.Column(
sa.String(36),
sa.ForeignKey("load_balancer.id",
name="fk_vip_load_balancer_id"),
nullable=False, primary_key=True)
ip_address = sa.Column(sa.String(36), nullable=True)
net_port_id = sa.Column(sa.String(36), nullable=True)
subnet_id = sa.Column(sa.String(36), nullable=True)
floating_ip_id = sa.Column(sa.String(36), nullable=True)
floating_ip_network_id = sa.Column(sa.String(36), nullable=True)
load_balancer = orm.relationship("LoadBalancer", uselist=False,
backref=orm.backref("vip", uselist=False,
cascade="delete"))
class Listener(base_models.BASE, base_models.IdMixin, base_models.TenantMixin):
__data_model__ = data_models.Listener
__tablename__ = "listener"
__table_args__ = (
sa.UniqueConstraint('load_balancer_id', 'protocol_port',
name='uq_listener_load_balancer_id_protocol_port'),
sa.UniqueConstraint('default_pool_id',
name='uq_listener_default_pool_id')
)
name = sa.Column(sa.String(255), nullable=True)
description = sa.Column(sa.String(255), nullable=True)
protocol = sa.Column(
sa.String(16),
sa.ForeignKey("protocol.name", name="fk_listener_protocol_name"),
nullable=False)
protocol_port = sa.Column(sa.Integer(), nullable=False)
connection_limit = sa.Column(sa.Integer, nullable=True)
load_balancer_id = sa.Column(
sa.String(36),
sa.ForeignKey("load_balancer.id", name="fk_listener_load_balancer_id"),
nullable=True)
default_tls_container_id = sa.Column(sa.String(36), nullable=True)
default_pool_id = sa.Column(
sa.String(36),
sa.ForeignKey("pool.id", name="fk_listener_pool_id"),
unique=True, nullable=True)
provisioning_status = sa.Column(
sa.String(16),
sa.ForeignKey("provisioning_status.name",
name="fk_listener_provisioning_status_name"),
nullable=False)
operating_status = sa.Column(
sa.String(16),
sa.ForeignKey("operating_status.name",
name="fk_listener_operating_status_name"),
nullable=False)
enabled = sa.Column(sa.Boolean(), nullable=False)
load_balancer = orm.relationship("LoadBalancer", uselist=False,
backref=orm.backref("listeners",
uselist=True,
cascade="delete"))
default_pool = orm.relationship("Pool", uselist=False,
backref=orm.backref("listener",
uselist=False),
cascade="delete")
class SNI(base_models.BASE):
__data_model__ = data_models.SNI
__tablename__ = "sni"
__table_args__ = (
sa.PrimaryKeyConstraint('listener_id', 'tls_container_id'),
)
listener_id = sa.Column(
sa.String(36),
sa.ForeignKey("listener.id", name="fk_sni_listener_id"),
nullable=False)
tls_container_id = sa.Column(sa.String(36), nullable=False)
position = sa.Column(sa.Integer(), nullable=True)
listener = orm.relationship("Listener", uselist=False,
backref=orm.backref("sni_containers",
uselist=True,
cascade="delete"))
class Amphora(base_models.BASE):
__data_model__ = data_models.Amphora
__tablename__ = "amphora"
id = sa.Column(sa.String(36), nullable=False, primary_key=True,
autoincrement=False)
load_balancer_id = sa.Column(
sa.String(36), sa.ForeignKey("load_balancer.id",
name="fk_amphora_load_balancer_id"),
nullable=True)
host_id = sa.Column(sa.String(36), nullable=False)
status = sa.Column(
sa.String(36),
sa.ForeignKey("provisioning_status.name",
name="fk_container_provisioning_status_name"))

View File

@ -20,4 +20,4 @@ class TestConstants(base.TestCase):
# Rough sanity test of module import; not meant to be exhaustive
def test_import(self):
self.assertEqual(constants.PROTOCOL_UDP, 'UDP')
self.assertEqual(constants.PROTOCOL_TCP, 'TCP')

View File

@ -0,0 +1,67 @@
# Copyright 2014 Rackspace
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo.db.sqlalchemy import test_base
from octavia.common import constants
from octavia.db import base_models
from octavia.db import models
class OctaviaDBTestBase(test_base.DbTestCase):
def setUp(self):
super(OctaviaDBTestBase, self).setUp()
# needed for closure
engine = self.engine
base_models.BASE.metadata.create_all(bind=engine)
self._seed_lookup_tables()
def unregister_models():
"""Unregister all data models."""
base_models.BASE.metadata.drop_all(bind=engine)
self.addCleanup(unregister_models)
self.session = self._get_session()
def _get_session(self):
return self.sessionmaker(bind=self.engine, expire_on_commit=True)
def _seed_lookup_tables(self):
session = self._get_session()
self._seed_lookup_table(
session, constants.SUPPORTED_PROVISIONING_STATUSES,
models.ProvisioningStatus)
self._seed_lookup_table(
session, constants.SUPPORTED_HEALTH_MONITOR_TYPES,
models.HealthMonitorType)
self._seed_lookup_table(
session, constants.SUPPORTED_LB_ALGORITHMS,
models.Algorithm)
self._seed_lookup_table(
session, constants.SUPPORTED_PROTOCOLS,
models.Protocol)
self._seed_lookup_table(
session, constants.SUPPORTED_OPERATING_STATUSES,
models.OperatingStatus)
self._seed_lookup_table(
session, constants.SUPPORTED_SP_TYPES,
models.SessionPersistenceType)
def _seed_lookup_table(self, session, name_list, model_cls):
for name in name_list:
with session.begin():
model = model_cls(name=name)
session.add(model)

View File

@ -0,0 +1,763 @@
# Copyright 2014 Rackspace
#
# 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 octavia.common import constants
from octavia.common import data_models
from octavia.db import models
from octavia.tests.unit.db import base
class ModelTestMixin(object):
FAKE_UUID_1 = '0123456789012345678901234567890123456'
FAKE_UUID_2 = '1234567890123456789012345678901234567'
def _insert(self, session, model_cls, model_kwargs):
with session.begin():
model = model_cls(**model_kwargs)
session.add(model)
return model
def associate_amphora(self, load_balancer, amphora):
load_balancer.amphorae.append(amphora)
def create_listener(self, session, **overrides):
kwargs = {'tenant_id': self.FAKE_UUID_1,
'id': self.FAKE_UUID_1,
'protocol': constants.PROTOCOL_HTTP,
'protocol_port': 80,
'provisioning_status': constants.ACTIVE,
'operating_status': constants.ONLINE,
'enabled': True}
kwargs.update(overrides)
return self._insert(session, models.Listener, kwargs)
def create_listener_statistics(self, session, listener_id, **overrides):
kwargs = {'listener_id': listener_id,
'bytes_in': 0,
'bytes_out': 0,
'active_connections': 0,
'total_connections': 0}
kwargs.update(overrides)
return self._insert(session, models.ListenerStatistics, kwargs)
def create_pool(self, session, **overrides):
kwargs = {'tenant_id': self.FAKE_UUID_1,
'id': self.FAKE_UUID_1,
'protocol': constants.PROTOCOL_HTTP,
'lb_algorithm': constants.LB_ALGORITHM_ROUND_ROBIN,
'operating_status': constants.ONLINE,
'enabled': True}
kwargs.update(overrides)
return self._insert(session, models.Pool, kwargs)
def create_session_persistence(self, session, pool_id, **overrides):
kwargs = {'pool_id': pool_id,
'type': constants.SESSION_PERSISTENCE_HTTP_COOKIE}
kwargs.update(overrides)
return self._insert(session, models.SessionPersistence, kwargs)
def create_health_monitor(self, session, pool_id, **overrides):
kwargs = {'tenant_id': self.FAKE_UUID_1,
'id': self.FAKE_UUID_1,
'pool_id': pool_id,
'type': constants.HEALTH_MONITOR_HTTP,
'delay': 1,
'timeout': 1,
'fall_threshold': 1,
'rise_threshold': 1,
'enabled': True}
kwargs.update(overrides)
return self._insert(session, models.HealthMonitor, kwargs)
def create_member(self, session, pool_id, **overrides):
kwargs = {'tenant_id': self.FAKE_UUID_1,
'id': self.FAKE_UUID_1,
'pool_id': pool_id,
'ip_address': '10.0.0.1',
'protocol_port': 80,
'operating_status': constants.ONLINE,
'enabled': True}
kwargs.update(overrides)
return self._insert(session, models.Member, kwargs)
def create_load_balancer(self, session, **overrides):
kwargs = {'tenant_id': self.FAKE_UUID_1,
'id': self.FAKE_UUID_1,
'provisioning_status': constants.ACTIVE,
'operating_status': constants.ONLINE,
'enabled': True}
kwargs.update(overrides)
return self._insert(session, models.LoadBalancer, kwargs)
def create_vip(self, session, load_balancer_id, **overrides):
kwargs = {'load_balancer_id': load_balancer_id}
kwargs.update(overrides)
return self._insert(session, models.Vip, kwargs)
def create_sni(self, session, **overrides):
kwargs = {'listener_id': self.FAKE_UUID_1,
'tls_container_id': self.FAKE_UUID_1}
kwargs.update(overrides)
return self._insert(session, models.SNI, kwargs)
def create_amphora(self, session, **overrides):
kwargs = {'id': self.FAKE_UUID_1,
'host_id': self.FAKE_UUID_1,
'status': constants.ONLINE}
kwargs.update(overrides)
return self._insert(session, models.Amphora, kwargs)
class PoolModelTest(base.OctaviaDBTestBase, ModelTestMixin):
def test_create(self):
self.create_pool(self.session)
def test_update(self):
pool = self.create_pool(self.session)
id = pool.id
pool.name = 'test1'
new_pool = self.session.query(
models.Pool).filter_by(id=id).first()
self.assertEqual('test1', new_pool.name)
def test_delete(self):
pool = self.create_pool(self.session)
id = pool.id
with self.session.begin():
self.session.delete(pool)
self.session.flush()
new_pool = self.session.query(
models.Pool).filter_by(id=id).first()
self.assertIsNone(new_pool)
def test_member_relationship(self):
pool = self.create_pool(self.session)
self.create_member(self.session, pool.id, id=self.FAKE_UUID_1,
ip_address="10.0.0.1")
self.create_member(self.session, pool.id, id=self.FAKE_UUID_2,
ip_address="10.0.0.2")
new_pool = self.session.query(
models.Pool).filter_by(id=pool.id).first()
self.assertIsNotNone(new_pool.members)
self.assertEqual(2, len(new_pool.members))
self.assertTrue(isinstance(new_pool.members[0], models.Member))
def test_health_monitor_relationship(self):
pool = self.create_pool(self.session)
self.create_health_monitor(self.session, pool.id)
new_pool = self.session.query(models.Pool).filter_by(
id=pool.id).first()
self.assertIsNotNone(new_pool.health_monitor)
self.assertTrue(isinstance(new_pool.health_monitor,
models.HealthMonitor))
def test_session_persistence_relationship(self):
pool = self.create_pool(self.session)
self.create_session_persistence(self.session, pool_id=pool.id)
new_pool = self.session.query(models.Pool).filter_by(
id=pool.id).first()
self.assertIsNotNone(new_pool.session_persistence)
self.assertTrue(isinstance(new_pool.session_persistence,
models.SessionPersistence))
def test_listener_relationship(self):
pool = self.create_pool(self.session)
self.create_listener(self.session, default_pool_id=pool.id)
new_pool = self.session.query(models.Pool).filter_by(
id=pool.id).first()
self.assertIsNotNone(new_pool.listener)
self.assertTrue(isinstance(new_pool.listener, models.Listener))
class MemberModelTest(base.OctaviaDBTestBase, ModelTestMixin):
def setUp(self):
super(MemberModelTest, self).setUp()
self.pool = self.create_pool(self.session)
def test_create(self):
self.create_member(self.session, self.pool.id)
def test_update(self):
member = self.create_member(self.session, self.pool.id)
member_id = member.id
member.name = 'test1'
new_member = self.session.query(
models.Member).filter_by(id=member_id).first()
self.assertEqual('test1', new_member.name)
def test_delete(self):
member = self.create_member(self.session, self.pool.id)
member_id = member.id
with self.session.begin():
self.session.delete(member)
self.session.flush()
new_member = self.session.query(
models.Member).filter_by(id=member_id).first()
self.assertIsNone(new_member)
def test_pool_relationship(self):
member = self.create_member(self.session, self.pool.id,
id=self.FAKE_UUID_1,
ip_address="10.0.0.1")
self.create_member(self.session, self.pool.id, id=self.FAKE_UUID_2,
ip_address="10.0.0.2")
new_member = self.session.query(models.Member).filter_by(
id=member.id).first()
self.assertIsNotNone(new_member.pool)
self.assertTrue(isinstance(new_member.pool, models.Pool))
class SessionPersistenceModelTest(base.OctaviaDBTestBase, ModelTestMixin):
def setUp(self):
super(SessionPersistenceModelTest, self).setUp()
self.pool = self.create_pool(self.session)
def test_create(self):
self.create_session_persistence(self.session, self.pool.id)
def test_update(self):
session_persistence = self.create_session_persistence(self.session,
self.pool.id)
session_persistence.name = 'test1'
new_session_persistence = self.session.query(
models.SessionPersistence).filter_by(pool_id=self.pool.id).first()
self.assertEqual('test1', new_session_persistence.name)
def test_delete(self):
session_persistence = self.create_session_persistence(self.session,
self.pool.id)
with self.session.begin():
self.session.delete(session_persistence)
self.session.flush()
new_session_persistence = self.session.query(
models.SessionPersistence).filter_by(pool_id=self.pool.id).first()
self.assertIsNone(new_session_persistence)
def test_pool_relationship(self):
self.create_session_persistence(self.session, self.pool.id)
new_persistence = self.session.query(
models.SessionPersistence).filter_by(pool_id=self.pool.id).first()
self.assertIsNotNone(new_persistence.pool)
self.assertTrue(isinstance(new_persistence.pool, models.Pool))
class ListenerModelTest(base.OctaviaDBTestBase, ModelTestMixin):
def test_create(self):
self.create_listener(self.session)
def test_update(self):
listener = self.create_listener(self.session)
listener_id = listener.id
listener.name = 'test1'
new_listener = self.session.query(
models.Listener).filter_by(id=listener_id).first()
self.assertEqual('test1', new_listener.name)
def test_delete(self):
listener = self.create_listener(self.session)
listener_id = listener.id
with self.session.begin():
self.session.delete(listener)
self.session.flush()
new_listener = self.session.query(
models.Listener).filter_by(id=listener_id).first()
self.assertIsNone(new_listener)
def test_load_balancer_relationship(self):
lb = self.create_load_balancer(self.session)
listener = self.create_listener(self.session, load_balancer_id=lb.id)
new_listener = self.session.query(
models.Listener).filter_by(id=listener.id).first()
self.assertIsNotNone(new_listener.load_balancer)
self.assertTrue(isinstance(new_listener.load_balancer,
models.LoadBalancer))
def test_listener_statistics_relationship(self):
listener = self.create_listener(self.session)
self.create_listener_statistics(self.session, listener_id=listener.id)
new_listener = self.session.query(models.Listener).filter_by(
id=listener.id).first()
self.assertIsNotNone(new_listener.stats)
self.assertTrue(isinstance(new_listener.stats,
models.ListenerStatistics))
def test_pool_relationship(self):
pool = self.create_pool(self.session)
listener = self.create_listener(self.session, default_pool_id=pool.id)
new_listener = self.session.query(models.Listener).filter_by(
id=listener.id).first()
self.assertIsNotNone(new_listener.default_pool)
self.assertTrue(isinstance(new_listener.default_pool, models.Pool))
def test_sni_relationship(self):
listener = self.create_listener(self.session)
self.create_sni(self.session, listener_id=listener.id,
tls_container_id=self.FAKE_UUID_1)
self.create_sni(self.session, listener_id=listener.id,
tls_container_id=self.FAKE_UUID_2)
new_listener = self.session.query(models.Listener).filter_by(
id=listener.id).first()
self.assertIsNotNone(new_listener.sni_containers)
self.assertEqual(2, len(new_listener.sni_containers))
class ListenerStatisticsModelTest(base.OctaviaDBTestBase, ModelTestMixin):
def setUp(self):
super(ListenerStatisticsModelTest, self).setUp()
self.listener = self.create_listener(self.session)
def test_create(self):
self.create_listener_statistics(self.session, self.listener.id)
def test_update(self):
stats = self.create_listener_statistics(self.session, self.listener.id)
stats.name = 'test1'
new_stats = self.session.query(models.ListenerStatistics).filter_by(
listener_id=self.listener.id).first()
self.assertEqual('test1', new_stats.name)
def test_delete(self):
stats = self.create_listener_statistics(self.session, self.listener.id)
with self.session.begin():
self.session.delete(stats)
self.session.flush()
new_stats = self.session.query(models.ListenerStatistics).filter_by(
listener_id=self.listener.id).first()
self.assertIsNone(new_stats)
def test_listener_relationship(self):
self.create_listener_statistics(self.session, self.listener.id)
new_stats = self.session.query(models.ListenerStatistics).filter_by(
listener_id=self.listener.id).first()
self.assertIsNotNone(new_stats.listener)
self.assertTrue(isinstance(new_stats.listener, models.Listener))
class HealthMonitorModelTest(base.OctaviaDBTestBase, ModelTestMixin):
def setUp(self):
super(HealthMonitorModelTest, self).setUp()
self.pool = self.create_pool(self.session)
def test_create(self):
self.create_health_monitor(self.session, self.pool.id)
def test_update(self):
health_monitor = self.create_health_monitor(self.session, self.pool.id)
health_monitor_id = health_monitor.id
health_monitor.name = 'test1'
new_health_monitor = self.session.query(
models.HealthMonitor).filter_by(id=health_monitor_id).first()
self.assertEqual('test1', new_health_monitor.name)
def test_delete(self):
health_monitor = self.create_health_monitor(self.session, self.pool.id)
health_monitor_id = health_monitor.id
with self.session.begin():
self.session.delete(health_monitor)
self.session.flush()
new_health_monitor = self.session.query(
models.HealthMonitor).filter_by(id=health_monitor_id).first()
self.assertIsNone(new_health_monitor)
def test_pool_relationship(self):
health_monitor = self.create_health_monitor(self.session, self.pool.id)
new_health_monitor = self.session.query(
models.HealthMonitor).filter_by(id=health_monitor.id).first()
self.assertIsNotNone(new_health_monitor.pool)
self.assertTrue(isinstance(new_health_monitor.pool, models.Pool))
class LoadBalancerModelTest(base.OctaviaDBTestBase, ModelTestMixin):
def test_create(self):
self.create_load_balancer(self.session)
def test_update(self):
load_balancer = self.create_load_balancer(self.session)
lb_id = load_balancer.id
load_balancer.name = 'test1'
new_load_balancer = self.session.query(
models.LoadBalancer).filter_by(id=lb_id).first()
self.assertEqual('test1', new_load_balancer.name)
def test_delete(self):
load_balancer = self.create_load_balancer(self.session)
lb_id = load_balancer.id
with self.session.begin():
self.session.delete(load_balancer)
self.session.flush()
new_load_balancer = self.session.query(
models.LoadBalancer).filter_by(id=lb_id).first()
self.assertIsNone(new_load_balancer)
def test_listener_relationship(self):
load_balancer = self.create_load_balancer(self.session)
self.create_listener(self.session, load_balancer_id=load_balancer.id)
new_load_balancer = self.session.query(
models.LoadBalancer).filter_by(id=load_balancer.id).first()
self.assertIsNotNone(new_load_balancer.listeners)
self.assertEqual(1, len(new_load_balancer.listeners))
def test_load_balancer_amphora_relationship(self):
load_balancer = self.create_load_balancer(self.session)
amphora = self.create_amphora(self.session)
self.associate_amphora(load_balancer, amphora)
new_load_balancer = self.session.query(
models.LoadBalancer).filter_by(id=load_balancer.id).first()
self.assertIsNotNone(new_load_balancer.amphorae)
self.assertEqual(1, len(new_load_balancer.amphorae))
def test_load_balancer_vip_relationship(self):
load_balancer = self.create_load_balancer(self.session)
self.create_vip(self.session, load_balancer.id)
new_load_balancer = self.session.query(
models.LoadBalancer).filter_by(id=load_balancer.id).first()
self.assertIsNotNone(new_load_balancer.vip)
self.assertIsInstance(new_load_balancer.vip, models.Vip)
class VipModelTest(base.OctaviaDBTestBase, ModelTestMixin):
def setUp(self):
super(VipModelTest, self).setUp()
self.load_balancer = self.create_load_balancer(self.session)
def test_create(self):
self.create_vip(self.session, self.load_balancer.id)
def test_update(self):
vip = self.create_vip(self.session, self.load_balancer.id)
vip.ip_address = "10.0.0.1"
new_vip = self.session.query(models.Vip).filter_by(
load_balancer_id=self.load_balancer.id).first()
self.assertEqual("10.0.0.1", new_vip.ip_address)
def test_delete(self):
vip = self.create_vip(self.session, self.load_balancer.id)
with self.session.begin():
self.session.delete(vip)
self.session.flush()
new_vip = self.session.query(models.Vip).filter_by(
load_balancer_id=vip.load_balancer_id).first()
self.assertIsNone(new_vip)
def test_vip_load_balancer_relationship(self):
self.create_vip(self.session, self.load_balancer.id)
new_vip = self.session.query(models.Vip).filter_by(
load_balancer_id=self.load_balancer.id).first()
self.assertIsNotNone(new_vip.load_balancer)
self.assertTrue(isinstance(new_vip.load_balancer, models.LoadBalancer))
class SNIModelTest(base.OctaviaDBTestBase, ModelTestMixin):
def setUp(self):
super(SNIModelTest, self).setUp()
self.listener = self.create_listener(self.session)
def test_create(self):
self.create_sni(self.session, listener_id=self.listener.id)
def test_update(self):
sni = self.create_sni(self.session, listener_id=self.listener.id)
sni.listener_id = self.FAKE_UUID_2
new_sni = self.session.query(
models.SNI).filter_by(listener_id=self.FAKE_UUID_2).first()
self.assertEqual(self.FAKE_UUID_2, new_sni.listener_id)
def test_delete(self):
sni = self.create_sni(self.session, listener_id=self.listener.id)
with self.session.begin():
self.session.delete(sni)
self.session.flush()
new_sni = self.session.query(
models.SNI).filter_by(listener_id=self.listener.id).first()
self.assertIsNone(new_sni)
def test_sni_relationship(self):
self.create_sni(self.session, listener_id=self.listener.id)
new_sni = self.session.query(models.SNI).filter_by(
listener_id=self.listener.id).first()
self.assertIsNotNone(new_sni.listener)
self.assertTrue(isinstance(new_sni.listener, models.Listener))
class AmphoraModelTest(base.OctaviaDBTestBase, ModelTestMixin):
def setUp(self):
super(AmphoraModelTest, self).setUp()
self.load_balancer = self.create_load_balancer(self.session)
def test_create(self):
self.create_amphora(self.session)
def test_update(self):
amphora = self.create_amphora(
self.session)
amphora.amphora_id = self.FAKE_UUID_2
new_amphora = self.session.query(models.Amphora).filter_by(
id=amphora.id).first()
self.assertEqual(self.FAKE_UUID_2, new_amphora.amphora_id)
def test_delete(self):
amphora = self.create_amphora(
self.session)
with self.session.begin():
self.session.delete(amphora)
self.session.flush()
new_amphora = self.session.query(
models.Amphora).filter_by(id=amphora.id).first()
self.assertIsNone(new_amphora)
def test_load_balancer_relationship(self):
amphora = self.create_amphora(self.session)
self.associate_amphora(self.load_balancer, amphora)
new_amphora = self.session.query(models.Amphora).filter_by(
id=amphora.id).first()
self.assertIsNotNone(new_amphora.load_balancer)
self.assertIsInstance(new_amphora.load_balancer, models.LoadBalancer)
class DataModelConversionTest(base.OctaviaDBTestBase, ModelTestMixin):
def setUp(self):
super(DataModelConversionTest, self).setUp()
self.pool = self.create_pool(self.session)
self.hm = self.create_health_monitor(self.session, self.pool.id)
self.member = self.create_member(self.session, self.pool.id,
id=self.FAKE_UUID_1,
ip_address='10.0.0.1')
self.sp = self.create_session_persistence(self.session, self.pool.id)
self.lb = self.create_load_balancer(self.session)
self.vip = self.create_vip(self.session, self.lb.id)
self.listener = self.create_listener(self.session,
default_pool_id=self.pool.id,
load_balancer_id=self.lb.id)
self.stats = self.create_listener_statistics(self.session,
self.listener.id)
self.sni = self.create_sni(self.session, listener_id=self.listener.id)
def test_load_balancer_tree(self):
lb_db = self.session.query(models.LoadBalancer).filter_by(
id=self.lb.id).first()
self.check_load_balancer(lb_db.to_data_model())
def test_vip_tree(self):
vip_db = self.session.query(models.Vip).filter_by(
load_balancer_id=self.lb.id).first()
self.check_vip(vip_db.to_data_model())
def test_listener_tree(self):
listener_db = self.session.query(models.Listener).filter_by(
id=self.listener.id).first()
self.check_listener(listener_db.to_data_model())
def test_sni_tree(self):
sni_db = self.session.query(models.SNI).filter_by(
listener_id=self.listener.id).first()
self.check_sni(sni_db.to_data_model())
def test_listener_statistics_tree(self):
stats_db = self.session.query(models.ListenerStatistics).filter_by(
listener_id=self.listener.id).first()
self.check_listener_statistics(stats_db.to_data_model())
def test_pool_tree(self):
pool_db = self.session.query(models.Pool).filter_by(
id=self.pool.id).first()
self.check_pool(pool_db.to_data_model())
def test_session_persistence_tree(self):
sp_db = self.session.query(models.SessionPersistence).filter_by(
pool_id=self.pool.id).first()
self.check_session_persistence(sp_db.to_data_model())
def test_health_monitor_tree(self):
hm_db = self.session.query(models.HealthMonitor).filter_by(
id=self.hm.id).first()
self.check_health_monitor(hm_db.to_data_model())
def test_member_tree(self):
member_db = self.session.query(models.Member).filter_by(
id=self.member.id).first()
self.check_member(member_db.to_data_model())
def check_load_balancer(self, lb, check_listeners=True,
check_amphorae=True, check_vip=True):
self.assertIsInstance(lb, data_models.LoadBalancer)
self.check_load_balancer_data_model(lb)
self.assertIsInstance(lb.listeners, list)
self.assertIsInstance(lb.amphorae, list)
if check_listeners:
for listener in lb.listeners:
self.check_listener(listener, check_lb=False)
if check_amphorae:
for amphora in lb.amphorae:
self.check_amphora(amphora, check_load_balancer=False)
if check_vip:
self.check_vip(lb.vip, check_lb=False)
def check_vip(self, vip, check_lb=True):
self.assertIsInstance(vip, data_models.Vip)
self.check_vip_data_model(vip)
if check_lb:
self.check_load_balancer(vip.load_balancer, check_vip=False)
def check_sni(self, sni, check_listener=True):
self.assertIsInstance(sni, data_models.SNI)
self.check_sni_data_model(sni)
if check_listener:
self.check_listener(sni.listener, check_sni=False)
def check_listener_statistics(self, stats, check_listener=True):
self.assertIsInstance(stats, data_models.ListenerStatistics)
self.check_listener_statistics_data_model(stats)
if check_listener:
self.check_listener(stats.listener, check_statistics=False)
def check_amphora(self, amphora, check_load_balancer=True):
self.assertIsInstance(amphora, data_models.Amphora)
self.check_amphora_data_model(amphora)
if check_load_balancer:
self.check_load_balancer(amphora.load_balancer)
def check_listener(self, listener, check_sni=True, check_pool=True,
check_lb=True, check_statistics=True):
self.assertIsInstance(listener, data_models.Listener)
self.check_listener_data_model(listener)
if check_lb:
self.check_load_balancer(listener.load_balancer)
if check_sni:
c_containers = listener.sni_containers
self.assertIsInstance(c_containers, list)
for sni in c_containers:
self.check_sni(sni, check_listener=False)
if check_pool:
self.check_pool(listener.default_pool, check_listener=False)
if check_statistics:
self.check_listener_statistics(listener.stats,
check_listener=False)
def check_session_persistence(self, session_persistence, check_pool=True):
self.assertIsInstance(session_persistence,
data_models.SessionPersistence)
self.check_session_persistence_data_model(session_persistence)
if check_pool:
self.check_pool(session_persistence.pool, check_sp=False)
def check_member(self, member, check_pool=True):
self.assertIsInstance(member, data_models.Member)
self.check_member_data_model(member)
if check_pool:
self.check_pool(member.pool)
def check_health_monitor(self, health_monitor, check_pool=True):
self.assertIsInstance(health_monitor, data_models.HealthMonitor)
self.check_health_monitor_data_model(health_monitor)
if check_pool:
self.check_pool(health_monitor.pool, check_hm=False)
def check_pool(self, pool, check_listener=True, check_sp=True,
check_hm=True, check_members=True):
self.assertIsInstance(pool, data_models.Pool)
self.check_pool_data_model(pool)
if check_listener:
self.check_listener(pool.listener, check_pool=False)
if check_sp:
self.check_session_persistence(pool.session_persistence,
check_pool=False)
if check_members:
c_members = pool.members
self.assertIsNotNone(c_members)
self.assertEqual(1, len(c_members))
for c_member in c_members:
self.check_member(c_member, check_pool=False)
if check_hm:
self.check_health_monitor(pool.health_monitor, check_pool=False)
def check_load_balancer_data_model(self, lb):
self.assertEqual(self.FAKE_UUID_1, lb.tenant_id)
self.assertEqual(self.FAKE_UUID_1, lb.id)
self.assertEqual(constants.ACTIVE, lb.provisioning_status)
self.assertEqual(True, lb.enabled)
def check_vip_data_model(self, vip):
self.assertEqual(self.FAKE_UUID_1, vip.load_balancer_id)
def check_listener_data_model(self, listener):
self.assertEqual(self.FAKE_UUID_1, listener.tenant_id)
self.assertEqual(self.FAKE_UUID_1, listener.id)
self.assertEqual(constants.PROTOCOL_HTTP, listener.protocol)
self.assertEqual(80, listener.protocol_port)
self.assertEqual(constants.ACTIVE, listener.provisioning_status)
self.assertEqual(constants.ONLINE, listener.operating_status)
self.assertEqual(True, listener.enabled)
def check_sni_data_model(self, sni):
self.assertEqual(self.FAKE_UUID_1, sni.listener_id)
self.assertEqual(self.FAKE_UUID_1, sni.tls_container_id)
def check_listener_statistics_data_model(self, stats):
self.assertEqual(self.listener.id, stats.listener_id)
self.assertEqual(0, stats.bytes_in)
self.assertEqual(0, stats.bytes_out)
self.assertEqual(0, stats.active_connections)
self.assertEqual(0, stats.total_connections)
def check_pool_data_model(self, pool):
self.assertEqual(self.FAKE_UUID_1, pool.tenant_id)
self.assertEqual(self.FAKE_UUID_1, pool.id)
self.assertEqual(constants.PROTOCOL_HTTP, pool.protocol)
self.assertEqual(constants.LB_ALGORITHM_ROUND_ROBIN, pool.lb_algorithm)
self.assertEqual(constants.ONLINE, pool.operating_status)
self.assertEqual(True, pool.enabled)
def check_session_persistence_data_model(self, sp):
self.assertEqual(self.pool.id, sp.pool_id)
self.assertEqual(constants.SESSION_PERSISTENCE_HTTP_COOKIE, sp.type)
def check_health_monitor_data_model(self, hm):
self.assertEqual(self.FAKE_UUID_1, hm.tenant_id)
self.assertEqual(self.FAKE_UUID_1, hm.id)
self.assertEqual(constants.HEALTH_MONITOR_HTTP, hm.type)
self.assertEqual(1, hm.delay)
self.assertEqual(1, hm.timeout)
self.assertEqual(1, hm.fall_threshold)
self.assertEqual(1, hm.rise_threshold)
self.assertEqual(True, hm.enabled)
def check_member_data_model(self, member):
self.assertEqual(self.FAKE_UUID_1, member.tenant_id)
self.assertEqual(self.FAKE_UUID_1, member.id)
self.assertEqual(self.pool.id, member.pool_id)
self.assertEqual('10.0.0.1', member.ip_address)
self.assertEqual(80, member.protocol_port)
self.assertEqual(constants.ONLINE, member.operating_status)
self.assertEqual(True, member.enabled)
def check_amphora_data_model(self, amphora):
self.assertEqual(self.FAKE_UUID_1, amphora.id)
self.assertEqual(self.FAKE_UUID_1, amphora.host_id)
self.assertEqual(constants.ONLINE, amphora.status)
def check_load_balancer_amphora_data_model(self, amphora):
self.assertEqual(self.FAKE_UUID_1, amphora.amphora_id)
self.assertEqual(self.FAKE_UUID_1, amphora.load_balancer_id)

View File

@ -7,6 +7,7 @@ fixtures>=0.3.14
mock>=1.0
python-subunit>=0.0.18
ordereddict
oslotest==1.0.0
testrepository>=0.0.18
testtools>=0.9.34
WebTest>=2.0