Add version columns to services table

The following patch is part of the cinder effort to
support rolling upgrade.  This patch adds columns
to the services table to track the RPC and
oslo_versionedobjects versions of each service.

Follow up patches will be made to have each service:
register its RPC and oslo_versionedobjects versions on
startup, make the RPC and oslo_versionedobjects versions
compatible with an older release, and update the versions
once all services are updated to the latest release.

Change-Id: Ifa6c6ac230988c75dcc4e5fe220bfc5ee70ac338
Partial-Implements: blueprint rpc-object-compatibility
This commit is contained in:
Thang Pham 2015-07-24 07:56:32 -07:00
parent 442aea54c9
commit 677ff1c699
8 changed files with 88 additions and 1 deletions

View File

@ -41,13 +41,15 @@ class BackupAPI(object):
"""
BASE_RPC_API_VERSION = '1.0'
RPC_API_VERSION = '1.1'
def __init__(self):
super(BackupAPI, self).__init__()
target = messaging.Target(topic=CONF.backup_topic,
version=self.BASE_RPC_API_VERSION)
serializer = objects_base.CinderObjectSerializer()
self.client = rpc.get_client(target, '1.1', serializer=serializer)
self.client = rpc.get_client(target, self.RPC_API_VERSION,
serializer=serializer)
def create_backup(self, ctxt, backup):
LOG.debug("create_backup in rpcapi backup_id %s", backup.id)

View File

@ -0,0 +1,51 @@
# Copyright (C) 2015 SimpliVity Corp.
# 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.
from sqlalchemy import Column
from sqlalchemy import MetaData, String, Table
def upgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
services = Table('services', meta, autoload=True)
rpc_current_version = Column('rpc_current_version', String(36))
rpc_available_version = Column('rpc_available_version', String(36))
object_current_version = Column('object_current_version', String(36))
object_available_version = Column('object_available_version', String(36))
services.create_column(rpc_current_version)
services.create_column(rpc_available_version)
services.create_column(object_current_version)
services.create_column(object_available_version)
services.update().values(rpc_current_version=None).execute()
services.update().values(rpc_available_version=None).execute()
services.update().values(object_current_version=None).execute()
services.update().values(object_available_version=None).execute()
def downgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
services = Table('services', meta, autoload=True)
rpc_current_version = services.columns.rpc_current_version
rpc_available_version = services.columns.rpc_available_version
object_current_version = services.columns.object_current_version
object_available_version = services.columns.object_available_version
services.drop_column(rpc_current_version)
services.drop_column(rpc_available_version)
services.drop_column(object_current_version)
services.drop_column(object_available_version)

View File

@ -69,6 +69,14 @@ class Service(BASE, CinderBase):
# periodic updates
modified_at = Column(DateTime)
# Version columns to support rolling upgrade.
# Current version is what the service is running now (i.e. minimum).
# Available version is what the service can support (i.e. max).
rpc_current_version = Column(String(36))
rpc_available_version = Column(String(36))
object_current_version = Column(String(36))
object_available_version = Column(String(36))
class ConsistencyGroup(BASE, CinderBase):
"""Represents a consistencygroup."""

View File

@ -69,6 +69,7 @@ class Backup(base.CinderPersistentObject, base.CinderObject,
def obj_make_compatible(self, primitive, target_version):
"""Make an object representation compatible with a target version."""
super(Backup, self).obj_make_compatible(primitive, target_version)
target_version = utils.convert_version_to_tuple(target_version)
@staticmethod

View File

@ -43,6 +43,11 @@ class CinderObject(base.VersionedObject):
# from one another.
OBJ_PROJECT_NAMESPACE = 'cinder'
# NOTE(thangp): As more objects are added to cinder, each object should
# have a custom map of version compatibility. This just anchors the base
# version compatibility.
VERSION_COMPATIBILITY = {'7.0.0': '1.0'}
def cinder_obj_get_changes(self):
"""Returns a dict of changed fields with tz unaware datetimes.

View File

@ -98,6 +98,7 @@ class Snapshot(base.CinderPersistentObject, base.CinderObject,
def obj_make_compatible(self, primitive, target_version):
"""Make an object representation compatible with a target version."""
super(Snapshot, self).obj_make_compatible(primitive, target_version)
target_version = utils.convert_version_to_tuple(target_version)
@staticmethod

View File

@ -96,6 +96,7 @@ class Volume(base.CinderPersistentObject, base.CinderObject,
def obj_make_compatible(self, primitive, target_version):
"""Make an object representation compatible with a target version."""
super(Volume, self).obj_make_compatible(primitive, target_version)
target_version = utils.convert_version_to_tuple(target_version)
@staticmethod

View File

@ -865,6 +865,24 @@ class MigrationsMixin(test_migrations.WalkVersionsMixin):
snapshots = db_utils.get_table(engine, 'snapshots')
self.assertNotIn('provider_auth', snapshots.c)
def _check_053(self, engine, data):
services = db_utils.get_table(engine, 'services')
self.assertIsInstance(services.c.rpc_current_version.type,
sqlalchemy.types.VARCHAR)
self.assertIsInstance(services.c.rpc_available_version.type,
sqlalchemy.types.VARCHAR)
self.assertIsInstance(services.c.object_current_version.type,
sqlalchemy.types.VARCHAR)
self.assertIsInstance(services.c.object_available_version.type,
sqlalchemy.types.VARCHAR)
def _post_downgrade_053(self, engine):
services = db_utils.get_table(engine, 'services')
self.assertNotIn('rpc_current_version', services.c)
self.assertNotIn('rpc_available_version', services.c)
self.assertNotIn('object_current_version', services.c)
self.assertNotIn('object_available_version', services.c)
def test_walk_versions(self):
self.walk_versions(True, False)