fdc2c5d86a
I noticed in nova that we had a lot of unused conf variables. I wondered if this was a thing in other projects as well. Turns out it is. Change-Id: I2424e32dd4ad61881d9b6a0449e12937ea8151e0
113 lines
4.1 KiB
Python
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)
|