From 32e5b054d20083edc5e6bd255505757d5793d376 Mon Sep 17 00:00:00 2001 From: Oleg Bondarev Date: Mon, 24 Jun 2013 16:50:19 +0400 Subject: [PATCH] Add status description field for lbaas objects Fixes bug 1166925 Change-Id: I44d936afd8cd531a786c09c38bbc4702737ce99c --- neutron/db/loadbalancer/loadbalancer_db.py | 39 ++++++++----- .../2032abe8edac_lbaas_add_status_des.py | 55 +++++++++++++++++++ neutron/db/models_v2.py | 7 +++ neutron/extensions/loadbalancer.py | 16 ++++-- .../db/loadbalancer/test_db_loadbalancer.py | 20 +++++++ 5 files changed, 119 insertions(+), 18 deletions(-) create mode 100644 neutron/db/migration/alembic_migrations/versions/2032abe8edac_lbaas_add_status_des.py diff --git a/neutron/db/loadbalancer/loadbalancer_db.py b/neutron/db/loadbalancer/loadbalancer_db.py index b207e3f8a..12dee74d4 100644 --- a/neutron/db/loadbalancer/loadbalancer_db.py +++ b/neutron/db/loadbalancer/loadbalancer_db.py @@ -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']: diff --git a/neutron/db/migration/alembic_migrations/versions/2032abe8edac_lbaas_add_status_des.py b/neutron/db/migration/alembic_migrations/versions/2032abe8edac_lbaas_add_status_des.py new file mode 100644 index 000000000..05b30e3e9 --- /dev/null +++ b/neutron/db/migration/alembic_migrations/versions/2032abe8edac_lbaas_add_status_des.py @@ -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') diff --git a/neutron/db/models_v2.py b/neutron/db/models_v2.py index 2db0e6398..8c00ffce5 100644 --- a/neutron/db/models_v2.py +++ b/neutron/db/models_v2.py @@ -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. diff --git a/neutron/extensions/loadbalancer.py b/neutron/extensions/loadbalancer.py index 7a6da2619..d93360f03 100644 --- a/neutron/extensions/loadbalancer.py +++ b/neutron/extensions/loadbalancer.py @@ -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} } } diff --git a/neutron/tests/unit/db/loadbalancer/test_db_loadbalancer.py b/neutron/tests/unit/db/loadbalancer/test_db_loadbalancer.py index 750441f2c..e28d22726 100644 --- a/neutron/tests/unit/db/loadbalancer/test_db_loadbalancer.py +++ b/neutron/tests/unit/db/loadbalancer/test_db_loadbalancer.py @@ -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'