deb-cinder/cinder/volume/qos_specs.py
Danny Al-Gaaf 1323339d33 Fix doc and source documentation errors and warning
Solve warnings and errors from build_sphinx. Fix rst doc files
and source code docstring issues.

Closes-Bug: #1557047

Change-Id: Ib59df2681c98716c786ff0edf6d7cfcc3e8fe5ec
Signed-off-by: Danny Al-Gaaf <danny.al-gaaf@bisect.de>
2016-04-14 12:30:08 +02:00

262 lines
9.2 KiB
Python

# Copyright (c) 2013 eBay Inc.
# Copyright (c) 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.
"""The QoS Specs Implementation"""
from oslo_db import exception as db_exc
from oslo_log import log as logging
from cinder import context
from cinder import db
from cinder import exception
from cinder.i18n import _, _LE, _LW
from cinder.volume import volume_types
LOG = logging.getLogger(__name__)
CONTROL_LOCATION = ['front-end', 'back-end', 'both']
def _verify_prepare_qos_specs(specs, create=True):
"""Check if 'consumer' value in qos specs is valid.
Verify 'consumer' value in qos_specs is valid, raise
exception if not. Assign default value to 'consumer', which
is 'back-end' if input is empty.
:params create a flag indicate if specs being verified is
for create. If it's false, that means specs is for update,
so that there's no need to add 'consumer' if that wasn't in
specs.
"""
# Check control location, if it's missing in input, assign default
# control location: 'front-end'
if not specs:
specs = {}
# remove 'name' since we will handle that elsewhere.
if specs.get('name', None):
del specs['name']
try:
if specs['consumer'] not in CONTROL_LOCATION:
msg = _("Valid consumer of QoS specs are: %s") % CONTROL_LOCATION
raise exception.InvalidQoSSpecs(reason=msg)
except KeyError:
# Default consumer is back-end, i.e Cinder volume service
if create:
specs['consumer'] = 'back-end'
return specs
def create(context, name, specs=None):
"""Creates qos_specs.
:param specs dictionary that contains specifications for QoS
e.g. {'consumer': 'front-end',
'total_iops_sec': 1000,
'total_bytes_sec': 1024000}
"""
_verify_prepare_qos_specs(specs)
values = dict(name=name, qos_specs=specs)
LOG.debug("Dict for qos_specs: %s", values)
try:
qos_specs_ref = db.qos_specs_create(context, values)
except db_exc.DBDataError:
msg = _('Error writing field to database')
LOG.exception(msg)
raise exception.Invalid(msg)
except db_exc.DBError:
LOG.exception(_LE('DB error:'))
raise exception.QoSSpecsCreateFailed(name=name,
qos_specs=specs)
return qos_specs_ref
def update(context, qos_specs_id, specs):
"""Update qos specs.
:param specs: dictionary that contains key/value pairs for updating
existing specs.
e.g. {'consumer': 'front-end',
'total_iops_sec': 500,
'total_bytes_sec': 512000,}
"""
# need to verify specs in case 'consumer' is passed
_verify_prepare_qos_specs(specs, create=False)
LOG.debug('qos_specs.update(): specs %s' % specs)
try:
res = db.qos_specs_update(context, qos_specs_id, specs)
except db_exc.DBError:
LOG.exception(_LE('DB error:'))
raise exception.QoSSpecsUpdateFailed(specs_id=qos_specs_id,
qos_specs=specs)
return res
def delete(context, qos_specs_id, force=False):
"""Marks qos specs as deleted.
'force' parameter is a flag to determine whether should destroy
should continue when there were entities associated with the qos specs.
force=True indicates caller would like to mark qos specs as deleted
even if there was entities associate with target qos specs.
Trying to delete a qos specs still associated with entities will
cause QoSSpecsInUse exception if force=False (default).
"""
if qos_specs_id is None:
msg = _("id cannot be None")
raise exception.InvalidQoSSpecs(reason=msg)
# check if there is any entity associated with this qos specs
res = db.qos_specs_associations_get(context, qos_specs_id)
if res and not force:
raise exception.QoSSpecsInUse(specs_id=qos_specs_id)
elif res and force:
# remove all association
db.qos_specs_disassociate_all(context, qos_specs_id)
db.qos_specs_delete(context, qos_specs_id)
def delete_keys(context, qos_specs_id, keys):
"""Marks specified key of target qos specs as deleted."""
if qos_specs_id is None:
msg = _("id cannot be None")
raise exception.InvalidQoSSpecs(reason=msg)
# make sure qos_specs_id is valid
get_qos_specs(context, qos_specs_id)
for key in keys:
db.qos_specs_item_delete(context, qos_specs_id, key)
def get_associations(context, specs_id):
"""Get all associations of given qos specs."""
try:
# query returns a list of volume types associated with qos specs
associates = db.qos_specs_associations_get(context, specs_id)
except db_exc.DBError:
LOG.exception(_LE('DB error:'))
msg = _('Failed to get all associations of '
'qos specs %s') % specs_id
LOG.warning(msg)
raise exception.CinderException(message=msg)
result = []
for vol_type in associates:
member = dict(association_type='volume_type')
member.update(dict(name=vol_type['name']))
member.update(dict(id=vol_type['id']))
result.append(member)
return result
def associate_qos_with_type(context, specs_id, type_id):
"""Associate qos_specs with volume type.
Associate target qos specs with specific volume type.
:param specs_id: qos specs ID to associate with
:param type_id: volume type ID to associate with
:raises VolumeTypeNotFound: if volume type doesn't exist
:raises QoSSpecsNotFound: if qos specs doesn't exist
:raises InvalidVolumeType: if volume type is already associated
with qos specs other than given one.
:raises QoSSpecsAssociateFailed: if there was general DB error
"""
try:
get_qos_specs(context, specs_id)
res = volume_types.get_volume_type_qos_specs(type_id)
if res.get('qos_specs', None):
if res['qos_specs'].get('id') != specs_id:
msg = (_("Type %(type_id)s is already associated with another "
"qos specs: %(qos_specs_id)s") %
{'type_id': type_id,
'qos_specs_id': res['qos_specs']['id']})
raise exception.InvalidVolumeType(reason=msg)
else:
db.qos_specs_associate(context, specs_id, type_id)
except db_exc.DBError:
LOG.exception(_LE('DB error:'))
LOG.warning(_LW('Failed to associate qos specs '
'%(id)s with type: %(vol_type_id)s'),
dict(id=specs_id, vol_type_id=type_id))
raise exception.QoSSpecsAssociateFailed(specs_id=specs_id,
type_id=type_id)
def disassociate_qos_specs(context, specs_id, type_id):
"""Disassociate qos_specs from volume type."""
try:
get_qos_specs(context, specs_id)
db.qos_specs_disassociate(context, specs_id, type_id)
except db_exc.DBError:
LOG.exception(_LE('DB error:'))
LOG.warning(_LW('Failed to disassociate qos specs '
'%(id)s with type: %(vol_type_id)s'),
dict(id=specs_id, vol_type_id=type_id))
raise exception.QoSSpecsDisassociateFailed(specs_id=specs_id,
type_id=type_id)
def disassociate_all(context, specs_id):
"""Disassociate qos_specs from all entities."""
try:
get_qos_specs(context, specs_id)
db.qos_specs_disassociate_all(context, specs_id)
except db_exc.DBError:
LOG.exception(_LE('DB error:'))
LOG.warning(_LW('Failed to disassociate qos specs %s.'), specs_id)
raise exception.QoSSpecsDisassociateFailed(specs_id=specs_id,
type_id=None)
def get_all_specs(context, filters=None, marker=None, limit=None, offset=None,
sort_keys=None, sort_dirs=None):
"""Get all non-deleted qos specs."""
qos_specs = db.qos_specs_get_all(context, filters=filters, marker=marker,
limit=limit, offset=offset,
sort_keys=sort_keys, sort_dirs=sort_dirs)
return qos_specs
def get_qos_specs(ctxt, id):
"""Retrieves single qos specs by id."""
if id is None:
msg = _("id cannot be None")
raise exception.InvalidQoSSpecs(reason=msg)
if ctxt is None:
ctxt = context.get_admin_context()
return db.qos_specs_get(ctxt, id)
def get_qos_specs_by_name(context, name):
"""Retrieves single qos specs by name."""
if name is None:
msg = _("name cannot be None")
raise exception.InvalidQoSSpecs(reason=msg)
return db.qos_specs_get_by_name(context, name)