2014-04-09 14:31:31 -07:00
|
|
|
# Copyright 2013 Rackspace, Inc.
|
|
|
|
#
|
|
|
|
# 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.
|
2013-12-21 17:22:09 -08:00
|
|
|
|
2014-03-19 16:19:52 -07:00
|
|
|
from ironic_python_agent import encoding
|
2013-12-21 17:22:09 -08:00
|
|
|
|
2014-03-17 10:58:39 -07:00
|
|
|
|
|
|
|
class RESTError(Exception, encoding.Serializable):
|
2014-03-19 16:19:52 -07:00
|
|
|
"""Base class for errors generated in ironic-python-client."""
|
2014-03-17 10:58:39 -07:00
|
|
|
message = 'An error occurred'
|
|
|
|
details = 'An unexpected error occurred. Please try back later.'
|
|
|
|
status_code = 500
|
2014-05-05 15:49:03 +04:00
|
|
|
serializable_fields = ('type', 'code', 'message', 'details')
|
2014-03-17 10:58:39 -07:00
|
|
|
|
2015-01-13 16:48:27 +00:00
|
|
|
def __init__(self, details=None, *args, **kwargs):
|
2014-05-05 15:49:03 +04:00
|
|
|
super(RESTError, self).__init__(*args, **kwargs)
|
|
|
|
self.type = self.__class__.__name__
|
|
|
|
self.code = self.status_code
|
2015-01-13 16:48:27 +00:00
|
|
|
if details:
|
|
|
|
self.details = details
|
2014-03-17 10:58:39 -07:00
|
|
|
|
|
|
|
|
|
|
|
class InvalidContentError(RESTError):
|
|
|
|
"""Error which occurs when a user supplies invalid content, either
|
|
|
|
because that content cannot be parsed according to the advertised
|
|
|
|
`Content-Type`, or due to a content validation error.
|
|
|
|
"""
|
|
|
|
message = 'Invalid request body'
|
|
|
|
status_code = 400
|
|
|
|
|
|
|
|
def __init__(self, details):
|
2015-01-13 16:48:27 +00:00
|
|
|
super(InvalidContentError, self).__init__(details)
|
2014-03-17 10:58:39 -07:00
|
|
|
|
2013-12-21 17:22:09 -08:00
|
|
|
|
2014-03-17 10:58:39 -07:00
|
|
|
class NotFound(RESTError):
|
|
|
|
"""Error which occurs when a user supplies invalid content, either
|
|
|
|
because that content cannot be parsed according to the advertised
|
|
|
|
`Content-Type`, or due to a content validation error.
|
|
|
|
"""
|
|
|
|
message = 'Not found'
|
|
|
|
status_code = 404
|
|
|
|
details = 'The requested URL was not found.'
|
2013-12-21 17:22:09 -08:00
|
|
|
|
|
|
|
|
2014-03-17 10:58:39 -07:00
|
|
|
class CommandExecutionError(RESTError):
|
2014-01-05 21:46:10 -08:00
|
|
|
"""Error raised when a command fails to execute."""
|
|
|
|
|
|
|
|
message = 'Command execution failed'
|
|
|
|
|
|
|
|
def __init__(self, details):
|
2015-01-13 16:48:27 +00:00
|
|
|
super(CommandExecutionError, self).__init__(details)
|
2014-01-05 21:46:10 -08:00
|
|
|
|
|
|
|
|
2014-03-17 10:58:39 -07:00
|
|
|
class InvalidCommandError(InvalidContentError):
|
2013-12-21 17:22:09 -08:00
|
|
|
"""Error which is raised when an unknown command is issued."""
|
|
|
|
|
2014-01-23 12:36:12 -08:00
|
|
|
messsage = 'Invalid command'
|
2013-12-21 17:22:09 -08:00
|
|
|
|
2014-01-23 12:36:12 -08:00
|
|
|
def __init__(self, details):
|
2013-12-21 17:22:09 -08:00
|
|
|
super(InvalidCommandError, self).__init__(details)
|
|
|
|
|
|
|
|
|
2014-03-17 10:58:39 -07:00
|
|
|
class InvalidCommandParamsError(InvalidContentError):
|
2013-12-21 17:22:09 -08:00
|
|
|
"""Error which is raised when command parameters are invalid."""
|
|
|
|
|
|
|
|
message = 'Invalid command parameters'
|
|
|
|
|
|
|
|
def __init__(self, details):
|
|
|
|
super(InvalidCommandParamsError, self).__init__(details)
|
2014-01-07 14:14:58 -08:00
|
|
|
|
|
|
|
|
2014-03-17 10:58:39 -07:00
|
|
|
class RequestedObjectNotFoundError(NotFound):
|
2014-01-09 13:43:04 -08:00
|
|
|
def __init__(self, type_descr, obj_id):
|
2014-03-11 13:31:19 -07:00
|
|
|
details = '{0} with id {1} not found.'.format(type_descr, obj_id)
|
2014-01-09 13:43:04 -08:00
|
|
|
super(RequestedObjectNotFoundError, self).__init__(details)
|
|
|
|
|
|
|
|
|
2014-03-19 16:19:52 -07:00
|
|
|
class IronicAPIError(RESTError):
|
2014-01-16 18:32:15 -08:00
|
|
|
"""Error raised when a call to the agent API fails."""
|
|
|
|
|
2014-03-19 16:19:52 -07:00
|
|
|
message = 'Error in call to ironic-api.'
|
2014-01-16 18:32:15 -08:00
|
|
|
|
|
|
|
def __init__(self, details):
|
2014-03-19 16:19:52 -07:00
|
|
|
super(IronicAPIError, self).__init__(details)
|
2014-01-16 18:32:15 -08:00
|
|
|
|
|
|
|
|
2014-03-19 16:19:52 -07:00
|
|
|
class HeartbeatError(IronicAPIError):
|
2014-01-07 14:14:58 -08:00
|
|
|
"""Error raised when a heartbeat to the agent API fails."""
|
|
|
|
|
|
|
|
message = 'Error heartbeating to agent API.'
|
|
|
|
|
|
|
|
def __init__(self, details):
|
2014-01-16 18:32:15 -08:00
|
|
|
super(HeartbeatError, self).__init__(details)
|
2014-01-14 12:39:08 -08:00
|
|
|
|
|
|
|
|
2014-03-19 16:19:52 -07:00
|
|
|
class LookupNodeError(IronicAPIError):
|
2014-03-18 10:39:47 -07:00
|
|
|
"""Error raised when the node configuration lookup to the Ironic API
|
|
|
|
fails.
|
|
|
|
"""
|
2014-03-17 16:43:23 -07:00
|
|
|
|
|
|
|
message = 'Error getting configuration from Ironic.'
|
|
|
|
|
|
|
|
def __init__(self, details):
|
2014-03-18 10:39:47 -07:00
|
|
|
super(LookupNodeError, self).__init__(details)
|
2014-03-17 16:43:23 -07:00
|
|
|
|
2014-03-13 16:52:45 -07:00
|
|
|
|
2014-05-30 23:55:34 +00:00
|
|
|
class LookupAgentIPError(IronicAPIError):
|
|
|
|
"""Error raised when automatic IP lookup fails."""
|
|
|
|
|
|
|
|
message = 'Error finding IP for Ironic Agent'
|
|
|
|
|
|
|
|
def __init__(self, details):
|
2015-01-12 21:12:37 +00:00
|
|
|
super(LookupAgentIPError, self).__init__(details)
|
2014-05-30 23:55:34 +00:00
|
|
|
|
|
|
|
|
|
|
|
class LookupAgentInterfaceError(IronicAPIError):
|
|
|
|
"""Error raised when agent interface lookup fails."""
|
|
|
|
|
|
|
|
message = 'Error finding network interface for Ironic Agent'
|
|
|
|
|
|
|
|
def __init__(self, details):
|
2015-01-12 21:12:37 +00:00
|
|
|
super(LookupAgentInterfaceError, self).__init__(details)
|
2014-05-30 23:55:34 +00:00
|
|
|
|
|
|
|
|
2014-03-17 16:43:23 -07:00
|
|
|
class ImageDownloadError(RESTError):
|
2014-01-14 12:39:08 -08:00
|
|
|
"""Error raised when an image cannot be downloaded."""
|
|
|
|
|
|
|
|
message = 'Error downloading image.'
|
|
|
|
|
2015-02-11 14:20:02 -08:00
|
|
|
def __init__(self, image_id, msg):
|
|
|
|
details = 'Download of image id {0} failed: {1}'.format(image_id, msg)
|
2015-01-13 16:48:27 +00:00
|
|
|
super(ImageDownloadError, self).__init__(details)
|
2014-01-14 13:05:22 -08:00
|
|
|
|
|
|
|
|
2014-03-17 10:58:39 -07:00
|
|
|
class ImageChecksumError(RESTError):
|
2014-01-14 13:05:22 -08:00
|
|
|
"""Error raised when an image fails to verify against its checksum."""
|
|
|
|
|
|
|
|
message = 'Error verifying image checksum.'
|
|
|
|
|
|
|
|
def __init__(self, image_id):
|
2015-01-13 16:48:27 +00:00
|
|
|
details = 'Image with id {0} failed to verify against checksum.'
|
|
|
|
details = details.format(image_id)
|
|
|
|
super(ImageChecksumError, self).__init__(details)
|
2014-01-15 11:20:05 -08:00
|
|
|
|
|
|
|
|
2014-03-17 10:58:39 -07:00
|
|
|
class ImageWriteError(RESTError):
|
2014-01-15 11:20:05 -08:00
|
|
|
"""Error raised when an image cannot be written to a device."""
|
|
|
|
|
|
|
|
message = 'Error writing image to device.'
|
|
|
|
|
2014-06-12 06:47:16 -07:00
|
|
|
def __init__(self, device, exit_code, stdout, stderr):
|
2015-01-13 16:48:27 +00:00
|
|
|
details = ('Writing image to device {0} failed with exit code '
|
|
|
|
'{1}. stdout: {2}. stderr: {3}')
|
|
|
|
details = details.format(device, exit_code, stdout, stderr)
|
|
|
|
super(ImageWriteError, self).__init__(details)
|
2014-01-17 15:59:56 -08:00
|
|
|
|
|
|
|
|
2014-04-21 10:44:49 -07:00
|
|
|
class ConfigDriveTooLargeError(RESTError):
|
|
|
|
"""Error raised when a configdrive is larger than the partition."""
|
|
|
|
message = 'Configdrive is too large for intended partition.'
|
|
|
|
|
|
|
|
def __init__(self, filename, filesize):
|
|
|
|
details = ('Configdrive at {0} has size {1}, which is larger than '
|
|
|
|
'the intended partition.').format(filename, filesize)
|
|
|
|
super(ConfigDriveTooLargeError, self).__init__(details)
|
|
|
|
|
|
|
|
|
2014-03-17 10:58:39 -07:00
|
|
|
class ConfigDriveWriteError(RESTError):
|
2014-01-28 15:54:24 -08:00
|
|
|
"""Error raised when a configdrive directory cannot be written to a
|
|
|
|
device.
|
|
|
|
"""
|
|
|
|
|
|
|
|
message = 'Error writing configdrive to device.'
|
|
|
|
|
2014-06-12 06:47:16 -07:00
|
|
|
def __init__(self, device, exit_code, stdout, stderr):
|
|
|
|
details = ('Writing configdrive to device {0} failed with exit code '
|
|
|
|
'{1}. stdout: {2}. stderr: {3}.')
|
|
|
|
details = details.format(device, exit_code, stdout, stderr)
|
2014-01-28 15:54:24 -08:00
|
|
|
super(ConfigDriveWriteError, self).__init__(details)
|
|
|
|
|
|
|
|
|
2014-03-17 10:58:39 -07:00
|
|
|
class SystemRebootError(RESTError):
|
2014-01-17 15:59:56 -08:00
|
|
|
"""Error raised when a system cannot reboot."""
|
|
|
|
|
|
|
|
message = 'Error rebooting system.'
|
|
|
|
|
2014-06-12 06:47:16 -07:00
|
|
|
def __init__(self, exit_code, stdout, stderr):
|
2015-01-13 16:48:27 +00:00
|
|
|
details = ('Reboot script failed with exit code {0}. stdout: '
|
|
|
|
'{1}. stderr: {2}.')
|
|
|
|
details = details.format(exit_code, stdout, stderr)
|
|
|
|
super(SystemRebootError, self).__init__(details)
|
2014-05-05 13:57:04 +04:00
|
|
|
|
|
|
|
|
2014-06-04 10:44:25 -07:00
|
|
|
class BlockDeviceEraseError(RESTError):
|
|
|
|
"""Error raised when an error occurs erasing a block device."""
|
|
|
|
|
|
|
|
message = 'Error erasing block device'
|
|
|
|
|
|
|
|
def __init__(self, details):
|
|
|
|
super(BlockDeviceEraseError, self).__init__(details)
|
|
|
|
|
|
|
|
|
2014-07-18 08:13:12 -07:00
|
|
|
class BlockDeviceError(RESTError):
|
|
|
|
"""Error raised when a block devices causes an unknown error"""
|
|
|
|
message = 'Block device caused unknown error'
|
|
|
|
|
|
|
|
def __init__(self, details):
|
|
|
|
super(BlockDeviceError, self).__init__(details)
|
|
|
|
|
|
|
|
|
2014-08-19 11:29:59 +05:30
|
|
|
class VirtualMediaBootError(RESTError):
|
|
|
|
"""Error raised when booting ironic-python-client from virtual media
|
|
|
|
fails.
|
|
|
|
"""
|
|
|
|
message = 'Booting ironic-python-client from virtual media failed.'
|
|
|
|
|
|
|
|
def __init__(self, details):
|
2015-01-12 21:12:37 +00:00
|
|
|
super(VirtualMediaBootError, self).__init__(details)
|
2014-08-19 11:29:59 +05:30
|
|
|
|
|
|
|
|
2015-01-16 21:56:03 +00:00
|
|
|
class ExtensionError(RESTError):
|
2014-05-05 13:57:04 +04:00
|
|
|
pass
|
2014-09-10 14:22:23 -07:00
|
|
|
|
|
|
|
|
2015-01-16 21:56:03 +00:00
|
|
|
class UnknownNodeError(RESTError):
|
2014-09-10 14:22:23 -07:00
|
|
|
"""Error raised when the agent is not associated with an Ironic node."""
|
|
|
|
|
|
|
|
message = 'Agent is not associated with an Ironic node.'
|
|
|
|
|
2015-01-16 21:56:03 +00:00
|
|
|
def __init__(self, details=None):
|
|
|
|
if details is not None:
|
|
|
|
details = details
|
|
|
|
else:
|
|
|
|
details = self.message
|
|
|
|
super(UnknownNodeError, self).__init__(details)
|
2014-12-19 13:24:21 -08:00
|
|
|
|
|
|
|
|
2015-01-16 21:56:03 +00:00
|
|
|
class HardwareManagerNotFound(RESTError):
|
2014-12-19 13:24:21 -08:00
|
|
|
"""Error raised when no valid HardwareManager can be found."""
|
|
|
|
|
|
|
|
message = 'No valid HardwareManager found.'
|
|
|
|
|
2015-01-16 21:56:03 +00:00
|
|
|
def __init__(self, details=None):
|
|
|
|
if details is not None:
|
|
|
|
details = details
|
|
|
|
else:
|
|
|
|
details = self.message
|
|
|
|
super(HardwareManagerNotFound, self).__init__(details)
|
2014-12-19 13:24:21 -08:00
|
|
|
|
|
|
|
|
|
|
|
class HardwareManagerMethodNotFound(RESTError):
|
|
|
|
"""Error raised when all HardwareManagers fail to handle a method."""
|
|
|
|
|
|
|
|
msg = 'No HardwareManager found to handle method'
|
|
|
|
message = msg + '.'
|
|
|
|
|
2015-01-09 08:50:36 -08:00
|
|
|
def __init__(self, method):
|
2015-01-13 16:48:27 +00:00
|
|
|
details = (self.msg + ': "{0}".').format(method)
|
|
|
|
super(HardwareManagerMethodNotFound, self).__init__(details)
|
2014-12-19 13:24:21 -08:00
|
|
|
|
|
|
|
|
|
|
|
class IncompatibleHardwareMethodError(RESTError):
|
|
|
|
"""Error raised when HardwareManager method is incompatible with node
|
|
|
|
hardware.
|
|
|
|
"""
|
|
|
|
|
|
|
|
message = 'HardwareManager method is not compatible with hardware.'
|
|
|
|
|
|
|
|
def __init__(self, details=None):
|
|
|
|
if details is not None:
|
2015-01-13 16:48:27 +00:00
|
|
|
details = details
|
2014-12-19 13:24:21 -08:00
|
|
|
else:
|
2015-01-13 16:48:27 +00:00
|
|
|
details = self.message
|
|
|
|
super(IncompatibleHardwareMethodError, self).__init__(details)
|