Add status description field for lbaas objects

Fixes bug 1166925

Change-Id: I44d936afd8cd531a786c09c38bbc4702737ce99c
This commit is contained in:
Oleg Bondarev 2013-06-24 16:50:19 +04:00
parent 0795d308b4
commit 32e5b054d2
5 changed files with 119 additions and 18 deletions

View File

@ -71,7 +71,8 @@ class PoolStatistics(model_base.BASEV2):
return value
class Vip(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
class Vip(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant,
models_v2.HasStatusDescription):
"""Represents a v2 neutron loadbalancer vip."""
name = sa.Column(sa.String(255))
@ -85,13 +86,13 @@ class Vip(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
uselist=False,
backref="vips",
cascade="all, delete-orphan")
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):
class Member(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant,
models_v2.HasStatusDescription):
"""Represents a v2 neutron loadbalancer member."""
pool_id = sa.Column(sa.String(36), sa.ForeignKey("pools.id"),
@ -99,11 +100,11 @@ class Member(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
address = sa.Column(sa.String(64), 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)
class Pool(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
class Pool(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant,
models_v2.HasStatusDescription):
"""Represents a v2 neutron loadbalancer pool."""
vip_id = sa.Column(sa.String(36), sa.ForeignKey("vips.id"))
@ -117,7 +118,6 @@ class Pool(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
"SOURCE_IP",
name="pools_lb_method"),
nullable=False)
status = sa.Column(sa.String(16), nullable=False)
admin_state_up = sa.Column(sa.Boolean(), nullable=False)
stats = orm.relationship(PoolStatistics,
uselist=False,
@ -130,7 +130,8 @@ class Pool(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
vip = orm.relationship(Vip, backref='pool')
class HealthMonitor(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
class HealthMonitor(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant,
models_v2.HasStatusDescription):
"""Represents a v2 neutron loadbalancer healthmonitor."""
type = sa.Column(sa.Enum("PING", "TCP", "HTTP", "HTTPS",
@ -142,7 +143,6 @@ class HealthMonitor(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
http_method = sa.Column(sa.String(16))
url_path = sa.Column(sa.String(255))
expected_codes = sa.Column(sa.String(64))
status = sa.Column(sa.String(16), nullable=False)
admin_state_up = sa.Column(sa.Boolean(), nullable=False)
pools = orm.relationship(
@ -175,10 +175,16 @@ class LoadBalancerPluginDb(LoadBalancerPluginBase,
def _core_plugin(self):
return manager.NeutronManager.get_plugin()
def update_status(self, context, model, id, status):
def update_status(self, context, model, id, status,
status_description=None):
with context.session.begin(subtransactions=True):
v_db = self._get_resource(context, model, id)
v_db.update({'status': status})
v_db.status = status
# update status_description in two cases:
# - new value is passed
# - old value is not None (needs to be updated anyway)
if status_description or v_db['status_description']:
v_db.status_description = status_description
def _get_resource(self, context, model, id):
try:
@ -219,7 +225,8 @@ class LoadBalancerPluginDb(LoadBalancerPluginBase,
'pool_id': vip['pool_id'],
'connection_limit': vip['connection_limit'],
'admin_state_up': vip['admin_state_up'],
'status': vip['status']}
'status': vip['status'],
'status_description': vip['status_description']}
if vip['session_persistence']:
s_p = {
@ -448,7 +455,8 @@ class LoadBalancerPluginDb(LoadBalancerPluginBase,
'vip_id': pool['vip_id'],
'lb_method': pool['lb_method'],
'admin_state_up': pool['admin_state_up'],
'status': pool['status']}
'status': pool['status'],
'status_description': pool['status_description']}
# Get the associated members
res['members'] = [member['id'] for member in pool['members']]
@ -593,7 +601,9 @@ class LoadBalancerPluginDb(LoadBalancerPluginBase,
'protocol_port': member['protocol_port'],
'weight': member['weight'],
'admin_state_up': member['admin_state_up'],
'status': member['status']}
'status': member['status'],
'status_description': member['status_description']}
return self._fields(res, fields)
def create_member(self, context, member):
@ -650,7 +660,8 @@ class LoadBalancerPluginDb(LoadBalancerPluginBase,
'timeout': health_monitor['timeout'],
'max_retries': health_monitor['max_retries'],
'admin_state_up': health_monitor['admin_state_up'],
'status': health_monitor['status']}
'status': health_monitor['status'],
'status_description': health_monitor['status_description']}
# no point to add the values below to
# the result if the 'type' is not HTTP/S
if res['type'] in ['HTTP', 'HTTPS']:

View File

@ -0,0 +1,55 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright 2013 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.
#
"""LBaaS add status description
Revision ID: 2032abe8edac
Revises: b7a8863760e
Create Date: 2013-06-24 06:51:47.308545
"""
# revision identifiers, used by Alembic.
revision = '2032abe8edac'
down_revision = 'b7a8863760e'
# Change to ['*'] if this migration applies to all plugins
migration_for_plugins = ['*']
from alembic import op
import sqlalchemy as sa
from neutron.db import migration
ENTITIES = ['vips', 'pools', 'members', 'healthmonitors']
def upgrade(active_plugin=None, options=None):
if not migration.should_run(active_plugin, migration_for_plugins):
return
for entity in ENTITIES:
op.add_column(entity, sa.Column('status_description', sa.String(255)))
def downgrade(active_plugin=None, options=None):
if not migration.should_run(active_plugin, migration_for_plugins):
return
for entity in ENTITIES:
op.drop_column(entity, 'status_description')

View File

@ -37,6 +37,13 @@ class HasId(object):
default=uuidutils.generate_uuid)
class HasStatusDescription(object):
"""Status with description mixin."""
status = sa.Column(sa.String(16), nullable=False)
status_description = sa.Column(sa.String(255))
class IPAvailabilityRange(model_base.BASEV2):
"""Internal representation of available IPs for Neutron subnets.

View File

@ -124,7 +124,9 @@ RESOURCE_ATTRIBUTE_MAP = {
'convert_to': attr.convert_to_boolean,
'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True}
'is_visible': True},
'status_description': {'allow_post': False, 'allow_put': False,
'is_visible': True}
},
'pools': {
'id': {'allow_post': False, 'allow_put': False,
@ -165,7 +167,9 @@ RESOURCE_ATTRIBUTE_MAP = {
'convert_to': attr.convert_to_boolean,
'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True}
'is_visible': True},
'status_description': {'allow_post': False, 'allow_put': False,
'is_visible': True}
},
'members': {
'id': {'allow_post': False, 'allow_put': False,
@ -196,7 +200,9 @@ RESOURCE_ATTRIBUTE_MAP = {
'convert_to': attr.convert_to_boolean,
'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True}
'is_visible': True},
'status_description': {'allow_post': False, 'allow_put': False,
'is_visible': True}
},
'health_monitors': {
'id': {'allow_post': False, 'allow_put': False,
@ -240,7 +246,9 @@ RESOURCE_ATTRIBUTE_MAP = {
'convert_to': attr.convert_to_boolean,
'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True}
'is_visible': True},
'status_description': {'allow_post': False, 'allow_put': False,
'is_visible': True}
}
}

View File

@ -1179,6 +1179,26 @@ class TestLoadBalancer(LoadBalancerPluginDbTestCase):
"123-456-789"
)
def test_update_status(self):
with self.pool() as pool:
self.assertEqual(pool['pool']['status'], 'PENDING_CREATE')
self.assertFalse(pool['pool']['status_description'])
self.plugin.update_status(context.get_admin_context(), ldb.Pool,
pool['pool']['id'], 'ERROR', 'unknown')
updated_pool = self.plugin.get_pool(context.get_admin_context(),
pool['pool']['id'])
self.assertEqual(updated_pool['status'], 'ERROR')
self.assertEqual(updated_pool['status_description'], 'unknown')
# update status to ACTIVE, status_description should be cleared
self.plugin.update_status(context.get_admin_context(), ldb.Pool,
pool['pool']['id'], 'ACTIVE')
updated_pool = self.plugin.get_pool(context.get_admin_context(),
pool['pool']['id'])
self.assertEqual(updated_pool['status'], 'ACTIVE')
self.assertFalse(pool['pool']['status_description'])
class TestLoadBalancerXML(TestLoadBalancer):
fmt = 'xml'