Remove dead code - replication RPC APIs
The REST APIs for promote_replica and reenable_replication were removed in If862bcd18515098639f94a8294a8e44e1358c52a with implementation of replication V2.1. Some code was left behind and now can be considered dead. This commit removes it. This should be safe from upgradeability point of view as we've deleted the APIs back in Mitaka and we're supporting backward compatibility with only one previous release. Changes in the drivers are left for the driver maintainers. Change-Id: Ia7dfcaa7601176ecb3a4b19bb59f6d9329e62635 Closes-Bug: 1620001
This commit is contained in:
parent
ecd2567374
commit
154404f5dd
|
@ -175,9 +175,6 @@ global_opts = [
|
|||
cfg.StrOpt('transfer_api_class',
|
||||
default='cinder.transfer.api.API',
|
||||
help='The full class name of the volume transfer API class'),
|
||||
cfg.StrOpt('replication_api_class',
|
||||
default='cinder.replication.api.API',
|
||||
help='The full class name of the volume replication API class'),
|
||||
cfg.StrOpt('consistencygroup_api_class',
|
||||
default='cinder.consistencygroup.api.API',
|
||||
help='The full class name of the consistencygroup API class'),
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
# Copyright 2014 IBM Corp.
|
||||
#
|
||||
# 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_utils import importutils
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
cls = CONF.replication_api_class
|
||||
API = importutils.import_class(cls)
|
|
@ -1,108 +0,0 @@
|
|||
# Copyright 2014 IBM Corp.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Handles all requests relating to volume replication.
|
||||
"""
|
||||
import functools
|
||||
|
||||
from cinder.db import base
|
||||
from cinder import exception
|
||||
from cinder.i18n import _
|
||||
from cinder import policy
|
||||
from cinder import volume as cinder_volume
|
||||
from cinder.volume import rpcapi as volume_rpcapi
|
||||
from cinder.volume import utils as volume_utils
|
||||
|
||||
|
||||
PROMOTE_PROCEED_STATUS = ('active', 'active-stopped')
|
||||
REENABLE_PROCEED_STATUS = ('inactive', 'active-stopped', 'error')
|
||||
|
||||
|
||||
def wrap_check_policy(func):
|
||||
"""Check policy corresponding to the wrapped methods prior to execution.
|
||||
|
||||
This decorator requires the first 3 args of the wrapped function
|
||||
to be (self, context, relationship_id)
|
||||
"""
|
||||
@functools.wraps(func)
|
||||
def wrapped(self, context, target_obj, *args, **kwargs):
|
||||
check_policy(context, func.__name__, target_obj)
|
||||
return func(self, context, target_obj, *args, **kwargs)
|
||||
return wrapped
|
||||
|
||||
|
||||
def check_policy(context, action, target_obj=None):
|
||||
target = {
|
||||
'project_id': context.project_id,
|
||||
'user_id': context.user_id,
|
||||
}
|
||||
target.update(target_obj or {})
|
||||
_action = 'volume_extension:replication:%s' % action
|
||||
policy.enforce(context, _action, target)
|
||||
|
||||
|
||||
class API(base.Base):
|
||||
"""API for interacting with volume replication relationships."""
|
||||
|
||||
def __init__(self, db_driver=None):
|
||||
super(API, self).__init__(db_driver)
|
||||
self.volume_rpcapi = volume_rpcapi.VolumeAPI()
|
||||
self.volume_api = cinder_volume.API()
|
||||
|
||||
@wrap_check_policy
|
||||
def promote(self, context, vol):
|
||||
if vol['replication_status'] == 'disabled':
|
||||
msg = _("Replication is not enabled for volume")
|
||||
raise exception.ReplicationError(
|
||||
reason=msg,
|
||||
volume_id=vol['id'])
|
||||
if vol['replication_status'] not in PROMOTE_PROCEED_STATUS:
|
||||
msg = _("Replication status for volume must be active or "
|
||||
"active-stopped, but current status "
|
||||
"is: %s") % vol['replication_status']
|
||||
raise exception.ReplicationError(
|
||||
reason=msg,
|
||||
volume_id=vol['id'])
|
||||
|
||||
if vol['status'] != 'available':
|
||||
msg = _("Volume status for volume must be available, but current "
|
||||
"status is: %s") % vol['status']
|
||||
raise exception.ReplicationError(
|
||||
reason=msg,
|
||||
volume_id=vol['id'])
|
||||
volume_utils.notify_about_replication_usage(context,
|
||||
vol,
|
||||
'promote')
|
||||
self.volume_rpcapi.promote_replica(context, vol)
|
||||
|
||||
@wrap_check_policy
|
||||
def reenable(self, context, vol):
|
||||
if vol['replication_status'] == 'disabled':
|
||||
msg = _("Replication is not enabled")
|
||||
raise exception.ReplicationError(
|
||||
reason=msg,
|
||||
volume_id=vol['id'])
|
||||
if vol['replication_status'] not in REENABLE_PROCEED_STATUS:
|
||||
msg = _("Replication status for volume must be inactive,"
|
||||
" active-stopped, or error, but current status "
|
||||
"is: %s") % vol['replication_status']
|
||||
raise exception.ReplicationError(
|
||||
reason=msg,
|
||||
volume_id=vol['id'])
|
||||
|
||||
volume_utils.notify_about_replication_usage(context,
|
||||
vol,
|
||||
'sync')
|
||||
self.volume_rpcapi.reenable_replication(context, vol)
|
|
@ -559,18 +559,6 @@ class VolumeRpcAPITestCase(test.TestCase):
|
|||
host='fake_host',
|
||||
version='3.0')
|
||||
|
||||
def test_promote_replica(self):
|
||||
self._test_volume_api('promote_replica',
|
||||
rpc_method='cast',
|
||||
volume=self.fake_volume,
|
||||
version='3.0')
|
||||
|
||||
def test_reenable_replica(self):
|
||||
self._test_volume_api('reenable_replication',
|
||||
rpc_method='cast',
|
||||
volume=self.fake_volume,
|
||||
version='3.0')
|
||||
|
||||
def test_freeze_host(self):
|
||||
self._test_volume_api('freeze_host', rpc_method='call',
|
||||
host='fake_host', version='3.0')
|
||||
|
|
|
@ -2187,103 +2187,9 @@ class ManageableSnapshotsVD(object):
|
|||
pass
|
||||
|
||||
|
||||
# TODO(jdg): Remove this after the V2.1 code merges
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class ReplicaVD(object):
|
||||
@abc.abstractmethod
|
||||
def reenable_replication(self, context, volume):
|
||||
"""Re-enable replication between the replica and primary volume.
|
||||
|
||||
This is used to re-enable/fix the replication between primary
|
||||
and secondary. One use is as part of the fail-back process, when
|
||||
you re-synchorize your old primary with the promoted volume
|
||||
(the old replica).
|
||||
Returns model_update for the volume to reflect the actions of the
|
||||
driver.
|
||||
|
||||
The driver is expected to update the following entries:
|
||||
- 'replication_status'
|
||||
- 'replication_extended_status'
|
||||
- 'replication_driver_data'
|
||||
|
||||
Possible 'replication_status' values (in model_update) are:
|
||||
- 'error' - replication in error state
|
||||
- 'copying' - replication copying data to secondary (inconsistent)
|
||||
- 'active' - replication copying data to secondary (consistent)
|
||||
- 'active-stopped' - replication data copy on hold (consistent)
|
||||
- 'inactive' - replication data copy on hold (inconsistent)
|
||||
|
||||
Values in 'replication_extended_status' and 'replication_driver_data'
|
||||
are managed by the driver.
|
||||
|
||||
:param context: Context
|
||||
:param volume: A dictionary describing the volume
|
||||
"""
|
||||
return
|
||||
|
||||
def get_replication_status(self, context, volume):
|
||||
"""Query the actual volume replication status from the driver.
|
||||
|
||||
Returns model_update for the volume.
|
||||
The driver is expected to update the following entries:
|
||||
- 'replication_status'
|
||||
- 'replication_extended_status'
|
||||
- 'replication_driver_data'
|
||||
|
||||
Possible 'replication_status' values (in model_update) are:
|
||||
- 'error' - replication in error state
|
||||
- 'copying' - replication copying data to secondary (inconsistent)
|
||||
- 'active' - replication copying data to secondary (consistent)
|
||||
- 'active-stopped' - replication data copy on hold (consistent)
|
||||
- 'inactive' - replication data copy on hold (inconsistent)
|
||||
|
||||
Values in 'replication_extended_status' and 'replication_driver_data'
|
||||
are managed by the driver.
|
||||
|
||||
:param context: Context
|
||||
:param volume: A dictionary describing the volume
|
||||
"""
|
||||
return None
|
||||
|
||||
@abc.abstractmethod
|
||||
def promote_replica(self, context, volume):
|
||||
"""Promote the replica to be the primary volume.
|
||||
|
||||
Following this command, replication between the volumes at
|
||||
the storage level should be stopped, the replica should be
|
||||
available to be attached, and the replication status should
|
||||
be in status 'inactive'.
|
||||
|
||||
Returns model_update for the volume.
|
||||
The driver is expected to update the following entries:
|
||||
- 'replication_status'
|
||||
- 'replication_extended_status'
|
||||
- 'replication_driver_data'
|
||||
|
||||
Possible 'replication_status' values (in model_update) are:
|
||||
- 'error' - replication in error state
|
||||
- 'inactive' - replication data copy on hold (inconsistent)
|
||||
|
||||
Values in 'replication_extended_status' and 'replication_driver_data'
|
||||
are managed by the driver.
|
||||
|
||||
:param context: Context
|
||||
:param volume: A dictionary describing the volume
|
||||
"""
|
||||
return
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_replica_test_volume(self, volume, src_vref):
|
||||
"""Creates a test replica clone of the specified replicated volume.
|
||||
|
||||
Create a clone of the replicated (secondary) volume.
|
||||
"""
|
||||
return
|
||||
|
||||
|
||||
class VolumeDriver(ConsistencyGroupVD, TransferVD, ManageableVD,
|
||||
ExtendVD, CloneableImageVD, ManageableSnapshotsVD,
|
||||
SnapshotVD, ReplicaVD, LocalVD, MigrateVD, BaseVD):
|
||||
SnapshotVD, LocalVD, MigrateVD, BaseVD):
|
||||
def check_for_setup_error(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
@ -2360,14 +2266,6 @@ class VolumeDriver(ConsistencyGroupVD, TransferVD, ManageableVD,
|
|||
def retype(self, context, volume, new_type, diff, host):
|
||||
return False, None
|
||||
|
||||
def reenable_replication(self, context, volume):
|
||||
msg = _("sync_replica not implemented.")
|
||||
raise NotImplementedError(msg)
|
||||
|
||||
def promote_replica(self, context, volume):
|
||||
msg = _("promote_replica not implemented.")
|
||||
raise NotImplementedError(msg)
|
||||
|
||||
# ####### Interface methods for DataPath (Connector) ########
|
||||
def ensure_export(self, context, volume):
|
||||
raise NotImplementedError()
|
||||
|
|
|
@ -1858,7 +1858,7 @@ class CLIResponse(object):
|
|||
class StorwizeSVCCommonDriver(san.SanDriver,
|
||||
driver.ManageableVD,
|
||||
driver.ExtendVD, driver.SnapshotVD,
|
||||
driver.MigrateVD, driver.ReplicaVD,
|
||||
driver.MigrateVD,
|
||||
driver.ConsistencyGroupVD,
|
||||
driver.CloneableImageVD,
|
||||
driver.TransferVD):
|
||||
|
|
|
@ -2446,87 +2446,6 @@ class VolumeManager(manager.SchedulerDependentManager):
|
|||
"to driver error."))
|
||||
return driver_entries
|
||||
|
||||
def promote_replica(self, ctxt, volume_id):
|
||||
"""Promote volume replica secondary to be the primary volume."""
|
||||
volume = self.db.volume_get(ctxt, volume_id)
|
||||
model_update = None
|
||||
|
||||
try:
|
||||
utils.require_driver_initialized(self.driver)
|
||||
except exception.DriverNotInitialized:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.exception(_LE("Promote volume replica failed."),
|
||||
resource=volume)
|
||||
|
||||
try:
|
||||
model_update = self.driver.promote_replica(ctxt, volume)
|
||||
except exception.CinderException:
|
||||
err_msg = (_('Error promoting secondary volume to primary'))
|
||||
raise exception.ReplicationError(reason=err_msg,
|
||||
volume_id=volume_id)
|
||||
|
||||
try:
|
||||
if model_update:
|
||||
volume = self.db.volume_update(ctxt,
|
||||
volume_id,
|
||||
model_update)
|
||||
except exception.CinderException:
|
||||
err_msg = (_("Failed updating model"
|
||||
" with driver provided model %(model)s") %
|
||||
{'model': model_update})
|
||||
raise exception.ReplicationError(reason=err_msg,
|
||||
volume_id=volume_id)
|
||||
LOG.info(_LI("Promote volume replica completed successfully."),
|
||||
resource=volume)
|
||||
|
||||
def reenable_replication(self, ctxt, volume_id):
|
||||
"""Re-enable replication of secondary volume with primary volumes."""
|
||||
volume = self.db.volume_get(ctxt, volume_id)
|
||||
model_update = None
|
||||
|
||||
try:
|
||||
utils.require_driver_initialized(self.driver)
|
||||
except exception.DriverNotInitialized:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.exception(_LE("Sync volume replica failed."),
|
||||
resource=volume)
|
||||
|
||||
try:
|
||||
model_update = self.driver.reenable_replication(ctxt, volume)
|
||||
except exception.CinderException:
|
||||
err_msg = (_("Synchronizing secondary volume to primary failed."))
|
||||
raise exception.ReplicationError(reason=err_msg,
|
||||
volume_id=volume_id)
|
||||
|
||||
try:
|
||||
if model_update:
|
||||
volume = self.db.volume_update(ctxt,
|
||||
volume_id,
|
||||
model_update)
|
||||
except exception.CinderException:
|
||||
err_msg = (_("Failed updating model"
|
||||
" with driver provided model %(model)s") %
|
||||
{'model': model_update})
|
||||
raise exception.ReplicationError(reason=err_msg,
|
||||
volume_id=volume_id)
|
||||
|
||||
def _update_replication_relationship_status(self, ctxt):
|
||||
# Only want volumes that do not have a 'disabled' replication status
|
||||
filters = {'replication_status': ['active', 'copying', 'error',
|
||||
'active-stopped', 'inactive']}
|
||||
volumes = self.db.volume_get_all_by_host(ctxt, self.host,
|
||||
filters=filters)
|
||||
for vol in volumes:
|
||||
model_update = None
|
||||
try:
|
||||
model_update = self.driver.get_replication_status(
|
||||
ctxt, vol)
|
||||
if model_update:
|
||||
self.db.volume_update(ctxt, vol['id'], model_update)
|
||||
except Exception:
|
||||
LOG.exception(_LE("Get replication status for volume failed."),
|
||||
resource=vol)
|
||||
|
||||
def create_consistencygroup(self, context, group):
|
||||
"""Creates the consistency group."""
|
||||
return self._create_group(context, group, False)
|
||||
|
@ -4352,7 +4271,7 @@ class VolumeManager(manager.SchedulerDependentManager):
|
|||
# TODO(dulek): This goes away immediately in Ocata and is just present in
|
||||
# Newton so that we can receive v2.x and v3.0 messages.
|
||||
class _VolumeV3Proxy(object):
|
||||
target = messaging.Target(version='3.0')
|
||||
target = messaging.Target(version='3.1')
|
||||
|
||||
def __init__(self, manager):
|
||||
self.manager = manager
|
||||
|
|
|
@ -110,9 +110,12 @@ class VolumeAPI(rpc.RPCAPI):
|
|||
the version_cap being set to 2.6.
|
||||
|
||||
3.0 - Drop 2.x compatibility
|
||||
3.1 - Remove promote_replica and reenable_replication. This is
|
||||
non-backward compatible, but the user-facing API was removed
|
||||
back in Mitaka when introducing cheesecake replication.
|
||||
"""
|
||||
|
||||
RPC_API_VERSION = '3.0'
|
||||
RPC_API_VERSION = '3.1'
|
||||
TOPIC = constants.VOLUME_TOPIC
|
||||
BINARY = 'cinder-volume'
|
||||
|
||||
|
@ -339,16 +342,6 @@ class VolumeAPI(rpc.RPCAPI):
|
|||
cctxt = self._get_cctxt(volume.host, version)
|
||||
cctxt.cast(ctxt, 'manage_existing', **msg_args)
|
||||
|
||||
def promote_replica(self, ctxt, volume):
|
||||
version = self._compat_ver('3.0', '2.0')
|
||||
cctxt = self._get_cctxt(volume['host'], version)
|
||||
cctxt.cast(ctxt, 'promote_replica', volume_id=volume['id'])
|
||||
|
||||
def reenable_replication(self, ctxt, volume):
|
||||
version = self._compat_ver('3.0', '2.0')
|
||||
cctxt = self._get_cctxt(volume['host'], version)
|
||||
cctxt.cast(ctxt, 'reenable_replication', volume_id=volume['id'])
|
||||
|
||||
def update_migrated_volume(self, ctxt, volume, new_volume,
|
||||
original_volume_status):
|
||||
version = self._compat_ver('3.0', '2.0')
|
||||
|
|
Loading…
Reference in New Issue