cinder/cinder/replication/api.py

113 lines
4.1 KiB
Python

# 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 oslo_log import log as logging
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
LOG = logging.getLogger(__name__)
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)