bc52ae4219
cinder does not provide an async error message when a new volume is created from an image if there is insufficient space to download the image. The changes are made such that if there is an IOError in fetch() or insufficient space error from check_available_space() cinder message API generates an async error message for the user. A new exception ImageTooBig() has been created to handle this error and whenever this exception is come across, cinder generates an error message. Changes are made in the create_volume flow to handle this exception and generate the message. Changes are made in image_utils.py so that whenever there is not enough space, the appropriate exception is raised. New action and detail are added to message_field.py for this type of error. Change-Id: I184acd9c26d2a2a140c8205e4c93164204e8674d
104 lines
3.7 KiB
Python
104 lines
3.7 KiB
Python
# 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.
|
|
|
|
"""Message Resource, Action, Detail and user visible message.
|
|
|
|
Use Resource, Action and Detail's combination to indicate the Event
|
|
in the format of:
|
|
EVENT: VOLUME_RESOURCE_ACTION_DETAIL
|
|
Also, use exception-to-detail mapping to decrease the workload of
|
|
classifying event in cinder's task code.
|
|
"""
|
|
|
|
from cinder.i18n import _
|
|
|
|
|
|
class Resource(object):
|
|
|
|
VOLUME = 'VOLUME'
|
|
|
|
|
|
class Action(object):
|
|
|
|
SCHEDULE_ALLOCATE_VOLUME = ('001', _('schedule allocate volume'))
|
|
ATTACH_VOLUME = ('002', _('attach volume'))
|
|
COPY_VOLUME_TO_IMAGE = ('003', _('copy volume to image'))
|
|
UPDATE_ATTACHMENT = ('004', _('update attachment'))
|
|
COPY_IMAGE_TO_VOLUME = ('005', _('copy image to volume'))
|
|
|
|
ALL = (SCHEDULE_ALLOCATE_VOLUME,
|
|
ATTACH_VOLUME,
|
|
COPY_VOLUME_TO_IMAGE,
|
|
UPDATE_ATTACHMENT,
|
|
COPY_IMAGE_TO_VOLUME)
|
|
|
|
|
|
class Detail(object):
|
|
|
|
UNKNOWN_ERROR = ('001', _('An unknown error occurred.'))
|
|
DRIVER_NOT_INITIALIZED = ('002',
|
|
_('Driver is not initialized at present.'))
|
|
NO_BACKEND_AVAILABLE = ('003',
|
|
_('Could not found any available '
|
|
'weighted backend.'))
|
|
FAILED_TO_UPLOAD_VOLUME = ('004',
|
|
_("Failed to upload volume to image "
|
|
"at backend."))
|
|
VOLUME_ATTACH_MODE_INVALID = ('005',
|
|
_("Volume's attach mode is invalid."))
|
|
QUOTA_EXCEED = ('006',
|
|
_("Not enough quota resource for operation."))
|
|
NOT_ENOUGH_SPACE_FOR_IMAGE = ('007',
|
|
_("Image used for creating volume exceeds "
|
|
"available space."))
|
|
|
|
ALL = (UNKNOWN_ERROR,
|
|
DRIVER_NOT_INITIALIZED,
|
|
NO_BACKEND_AVAILABLE,
|
|
FAILED_TO_UPLOAD_VOLUME,
|
|
VOLUME_ATTACH_MODE_INVALID,
|
|
QUOTA_EXCEED,
|
|
NOT_ENOUGH_SPACE_FOR_IMAGE)
|
|
|
|
# Exception and detail mappings
|
|
EXCEPTION_DETAIL_MAPPINGS = {
|
|
DRIVER_NOT_INITIALIZED: ['DriverNotInitialized'],
|
|
NO_BACKEND_AVAILABLE: ['NoValidBackend'],
|
|
VOLUME_ATTACH_MODE_INVALID: ['InvalidVolumeAttachMode'],
|
|
QUOTA_EXCEED: ['ImageLimitExceeded',
|
|
'BackupLimitExceeded',
|
|
'SnapshotLimitExceeded'],
|
|
NOT_ENOUGH_SPACE_FOR_IMAGE: ['ImageTooBig']
|
|
}
|
|
|
|
|
|
def translate_action(action_id):
|
|
action_message = next((action[1] for action in Action.ALL
|
|
if action[0] == action_id), None)
|
|
return action_message or 'unknown action'
|
|
|
|
|
|
def translate_detail(detail_id):
|
|
detail_message = next((action[1] for action in Detail.ALL
|
|
if action[0] == detail_id), None)
|
|
return detail_message or Detail.UNKNOWN_ERROR[1]
|
|
|
|
|
|
def translate_detail_id(exception, detail):
|
|
if exception is not None and isinstance(exception, Exception):
|
|
for key, value in Detail.EXCEPTION_DETAIL_MAPPINGS.items():
|
|
if exception.__class__.__name__ in value:
|
|
return key[0]
|
|
if detail in Detail.ALL:
|
|
return detail[0]
|
|
return Detail.UNKNOWN_ERROR[0]
|