ec2-api/ec2api/exception.py
Andrey Pavlov 2cc7ec92dc fix races
1) fix bug with filtering
filters were applied before unpaired items is added to result

2) fix races in default security group creation

3) add waiter for associate/disassociate address

4) fix security group classic test
it should choose default group group only from classic groups

5) fix describe_vpc_with_filters test
it can run in parallel with other test with same CIDR

6) fix networks list for instance run at subnet creation/deletion

7) fix selective decsribe by names
it should not delete valid items from db

Change-Id: Iadadefb8b4abebbb3b8efc0e536e5de30ed23dab
2015-12-15 09:22:50 +03:00

495 lines
15 KiB
Python

# Copyright 2014
# The Cloudscaling Group, 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.
"""ec2api base exception handling.
Includes decorator for re-raising ec2api-type exceptions.
SHOULD include dedicated exception logging.
"""
import sys
from oslo_config import cfg
from oslo_log import log as logging
import six
from ec2api.i18n import _
LOG = logging.getLogger(__name__)
exc_log_opts = [
cfg.BoolOpt('fatal_exception_format_errors',
default=False,
help='Make exception message format errors fatal'),
]
CONF = cfg.CONF
CONF.register_opts(exc_log_opts)
class EC2APIException(Exception):
"""Base EC2 API Exception
To correctly use this class, inherit from it and define
a 'msg_fmt' property. That msg_fmt will get printf'd
with the keyword arguments provided to the constructor.
"""
msg_fmt = _('An unknown exception occurred.')
def __init__(self, message=None, **kwargs):
self.kwargs = kwargs
if not message:
try:
message = self.msg_fmt % kwargs
except Exception:
exc_info = sys.exc_info()
# kwargs doesn't match a variable in the message
# log the issue and the kwargs
LOG.exception(_('Exception in string format operation for '
'%s exception'), self.__class__.__name__)
for name, value in six.iteritems(kwargs):
LOG.error('%s: %s' % (name, value))
if CONF.fatal_exception_format_errors:
six.reraise(*exc_info)
else:
# at least get the core message out if something happened
message = self.msg_fmt
elif not isinstance(message, six.string_types):
LOG.error(_("Message '%(msg)s' for %(ex)s exception is not "
"a string"),
{'msg': message, 'ex': self.__class__.__name__})
if CONF.fatal_exception_format_errors:
raise TypeError(_('Invalid exception message format'))
else:
message = self.msg_fmt
super(EC2APIException, self).__init__(message)
def format_message(self):
# NOTE(mrodden): use the first argument to the python Exception object
# which should be our full EC2APIException message, (see __init__)
return self.args[0]
# Internal ec2api exceptions
class EC2APIConfigNotFound(EC2APIException):
msg_fmt = _("Could not find config at %(path)s")
class EC2APIPasteAppNotFound(EC2APIException):
msg_fmt = _("Could not load paste app '%(name)s' from %(path)s")
class EC2KeystoneDiscoverFailure(EC2APIException):
msg_fmt = _("Could not discover keystone versions.")
class EC2DBInvalidOsIdUpdate(EC2APIException):
msg_fmt = _('Invalid update of os_id of %(item_id)s item '
'from %(old_os_id)s to %(new_os_id)s')
class EC2DBDuplicateEntry(EC2APIException):
msg_fmt = _('Entry %(id)s already exists in DB.')
# Internal ec2api metadata exceptions
class EC2MetadataException(EC2APIException):
pass
class EC2MetadataNotFound(EC2MetadataException):
pass
class EC2MetadataInvalidAddress(EC2MetadataException):
pass
# Intermediate exception classes to organize AWS exception hierarchy
class EC2Exception(EC2APIException):
"""Base EC2 compliant exception
To correctly use this class, inherit from it and define
a 'ec2_code' property if a new class name doesn't coincide with
AWS Error Code.
"""
code = 400
class EC2InvalidException(EC2Exception):
pass
class EC2IncorrectStateException(EC2Exception):
pass
class EC2DuplicateException(EC2InvalidException):
pass
class EC2InUseException(EC2InvalidException):
pass
class EC2NotFoundException(EC2InvalidException):
pass
class EC2OverlimitException(EC2Exception):
pass
# AWS compliant exceptions
class Unsupported(EC2Exception):
msg_fmt = _("The specified request is unsupported. %(reason)s")
class UnsupportedOperation(EC2Exception):
msg_fmt = _('The specified request includes an unsupported operation.')
class OperationNotPermitted(EC2Exception):
msg_fmt = _('The specified operation is not allowed.')
class InvalidRequest(EC2InvalidException):
msg_fmt = _('The request received was invalid.')
class InvalidAttribute(EC2InvalidException):
msg_fmt = _("Attribute not supported: %(attr)s")
class InvalidID(EC2InvalidException):
msg_fmt = _("The ID '%(id)s' is not valid")
class InvalidInput(EC2InvalidException):
msg_fmt = _("Invalid input received: %(reason)s")
class AuthFailure(EC2InvalidException):
msg_fmt = _('Not authorized.')
class ValidationError(EC2InvalidException):
msg_fmt = _("The input fails to satisfy the constraints "
"specified by an AWS service: '%(reason)s'")
class MissingParameter(EC2InvalidException):
msg_fmt = _("The required parameter '%(param)s' is missing")
class InvalidParameter(EC2InvalidException):
msg_fmt = _("The property '%(name)s' is not valid")
class InvalidParameterValue(EC2InvalidException):
msg_fmt = _("Value (%(value)s) for parameter %(parameter)s is invalid. "
"%(reason)s")
class InvalidFilter(EC2InvalidException):
msg_fmt = _('The filter is invalid.')
class InvalidParameterCombination(EC2InvalidException):
msg_fmt = _('The combination of parameters in incorrect')
class InvalidVpcRange(EC2InvalidException):
ec2_code = 'InvalidVpc.Range'
msg_fmt = _("The CIDR '%(cidr_block)s' is invalid.")
class InvalidVpcState(EC2InvalidException):
msg_fmt = _('VPC %(vpc_id)s is currently attached to '
'the Virtual Private Gateway %(vgw_id)s')
class InvalidSubnetRange(EC2InvalidException):
ec2_code = 'InvalidSubnet.Range'
msg_fmt = _("The CIDR '%(cidr_block)s' is invalid.")
class InvalidSubnetConflict(EC2InvalidException):
ec2_code = 'InvalidSubnet.Conflict'
msg_fmt = _("The CIDR '%(cidr_block)s' conflicts with another subnet")
class InvalidInstanceId(EC2InvalidException):
ec2_code = 'InvalidInstanceID'
msg_fmt = _("There are multiple interfaces attached to instance "
"'%(instance_id)s'. Please specify an interface ID for "
"the operation instead.")
class InvalidSnapshotIDMalformed(EC2InvalidException):
ec2_code = 'InvalidSnapshotID.Malformed'
# TODO(ft): Change the message with the real AWS message
msg_fmg = _('The snapshot %(id)s ID is not valid')
class InvalidBlockDeviceMapping(EC2InvalidException):
pass
class IncorrectState(EC2IncorrectStateException):
msg_fmt = _("The resource is in incorrect state for the request - reason: "
"'%(reason)s'")
class DependencyViolation(EC2IncorrectStateException):
msg_fmt = _('Object %(obj1_id)s has dependent resource %(obj2_id)s')
class CannotDelete(EC2IncorrectStateException):
msg_fmt = _('Cannot delete the default VPC security group')
class ResourceAlreadyAssociated(EC2IncorrectStateException):
ec2_code = 'Resource.AlreadyAssociated'
class GatewayNotAttached(EC2IncorrectStateException):
ec2_code = 'Gateway.NotAttached'
msg_fmt = _("resource %(gw_id)s is not attached to network %(vpc_id)s")
class IncorrectInstanceState(EC2IncorrectStateException):
msg_fmt = _("The instance '%(instance_id)s' is not in a state from which "
"the requested operation can be performed.")
class InvalidAMIIDUnavailable(EC2IncorrectStateException):
ec2_code = 'InvalidAMIID.Unavailable'
# TODO(ft): Change the message with the real AWS message
msg_fmt = _("Image %(image_id)s is not active.")
class InvalidNetworkInterfaceInUse(EC2InUseException):
ec2_code = 'InvalidNetworkInterface.InUse'
msg_fmt = _('Interface: %(interface_ids)s in use.')
class InvalidIPAddressInUse(EC2InUseException):
ec2_code = 'InvalidIPAddress.InUse'
msg_fmt = _('Address %(ip_address)s is in use.')
class InvalidKeyPairDuplicate(EC2DuplicateException):
ec2_code = 'InvalidKeyPair.Duplicate'
msg_fmt = _("Key pair '%(key_name)s' already exists.")
class InvalidPermissionDuplicate(EC2DuplicateException):
ec2_code = 'InvalidPermission.Duplicate'
msg_fmt = _('The specified rule already exists for that security group.')
class InvalidGroupDuplicate(EC2DuplicateException):
ec2_code = 'InvalidGroup.Duplicate'
msg_fmt = _("Security group '%(name)s' already exists.")
class RouteAlreadyExists(EC2DuplicateException):
msg_fmt = _('The route identified by %(destination_cidr_block)s '
'already exists.')
class InvalidCustomerGatewayDuplicateIpAddress(EC2DuplicateException):
ec2_code = 'InvalidCustomerGateway.DuplicateIpAddress'
msg_fmt = _('Conflict among chosen gateway IP addresses.')
class InvalidVpcIDNotFound(EC2NotFoundException):
ec2_code = 'InvalidVpcID.NotFound'
msg_fmt = _("The vpc ID '%(id)s' does not exist")
class InvalidInternetGatewayIDNotFound(EC2NotFoundException):
ec2_code = 'InvalidInternetGatewayID.NotFound'
msg_fmt = _("The internetGateway ID '%(id)s' does not exist")
class InvalidSubnetIDNotFound(EC2NotFoundException):
ec2_code = 'InvalidSubnetID.NotFound'
msg_fmt = _("The subnet ID '%(id)s' does not exist")
class InvalidNetworkInterfaceIDNotFound(EC2NotFoundException):
ec2_code = 'InvalidNetworkInterfaceID.NotFound'
msg_fmt = _("Network interface %(id)s could not "
"be found.")
class InvalidAttachmentIDNotFound(EC2NotFoundException):
ec2_code = 'InvalidAttachmentID.NotFound'
msg_fmt = _("Attachment %(id)s could not "
"be found.")
class InvalidInstanceIDNotFound(EC2NotFoundException):
ec2_code = 'InvalidInstanceID.NotFound'
msg_fmt = _("The instance ID '%(id)s' does not exist")
class InvalidDhcpOptionsIDNotFound(EC2NotFoundException):
ec2_code = 'InvalidDhcpOptionsID.NotFound'
msg_fmt = _("The dhcp options ID '%(id)s' does not exist")
class InvalidAddressNotFound(EC2NotFoundException):
ec2_code = 'InvalidAddress.NotFound'
msg_fmt = _('The specified elastic IP address %(ip)s cannot be found.')
class InvalidAllocationIDNotFound(EC2NotFoundException):
ec2_code = 'InvalidAllocationID.NotFound'
msg_fmt = _("The allocation ID '%(id)s' does not exist")
class InvalidAssociationIDNotFound(EC2NotFoundException):
ec2_code = 'InvalidAssociationID.NotFound'
msg_fmt = _("The association ID '%(id)s' does not exist")
class InvalidSecurityGroupIDNotFound(EC2NotFoundException):
ec2_code = 'InvalidSecurityGroupID.NotFound'
msg_fmt = _("The securityGroup ID '%(id)s' does not exist")
class InvalidGroupNotFound(EC2NotFoundException):
ec2_code = 'InvalidGroup.NotFound'
msg_fmg = _("The security group ID '%(id)s' does not exist")
class InvalidPermissionNotFound(EC2NotFoundException):
ec2_code = 'InvalidPermission.NotFound'
msg_fmg = _('The specified permission does not exist')
class InvalidRouteTableIDNotFound(EC2NotFoundException):
ec2_code = 'InvalidRouteTableID.NotFound'
msg_fmt = _("The routeTable ID '%(id)s' does not exist")
class InvalidRouteNotFound(EC2NotFoundException):
ec2_code = 'InvalidRoute.NotFound'
msg_fmt = _('No route with destination-cidr-block '
'%(destination_cidr_block)s in route table %(route_table_id)s')
class InvalidAMIIDNotFound(EC2NotFoundException):
ec2_code = 'InvalidAMIID.NotFound'
msg_fmt = _("The image id '[%(id)s]' does not exist")
class InvalidVolumeNotFound(EC2NotFoundException):
ec2_code = 'InvalidVolume.NotFound'
msg_fmt = _("The volume '%(id)s' does not exist.")
class InvalidSnapshotNotFound(EC2NotFoundException):
ec2_code = 'InvalidSnapshot.NotFound'
msg_fmt = _("Snapshot %(id)s could not be found.")
class InvalidKeypairNotFound(EC2NotFoundException):
ec2_code = 'InvalidKeyPair.NotFound'
msg_fmt = _("Keypair %(id)s is not found")
class InvalidAvailabilityZoneNotFound(EC2NotFoundException):
ec2_code = 'InvalidAvailabilityZone.NotFound'
msg_fmt = _("Availability zone %(id)s not found")
class InvalidGatewayIDNotFound(EC2NotFoundException):
ec2_code = 'InvalidGatewayID.NotFound'
msg_fmt = _("The gateway ID '%(id)s' does not exist")
class InvalidVpnGatewayIDNotFound(EC2NotFoundException):
ec2_code = 'InvalidVpnGatewayID.NotFound'
msg_fmt = _("The vpnGateway ID '%(id)s' does not exist")
class InvalidCustomerGatewayIDNotFound(EC2NotFoundException):
ec2_code = 'InvalidCustomerGatewayID.NotFound'
msg_fmt = _("The customerGateway ID '%(id)s' does not exist")
class InvalidVpnConnectionIDNotFound(EC2NotFoundException):
ec2_code = 'InvalidVpnConnectionID.NotFound'
msg_fmt = _("The vpnConnection ID '%(id)s' does not exist")
class InvalidVpnGatewayAttachmentNotFound(EC2NotFoundException):
ec2_code = 'InvalidVpnGatewayAttachment.NotFound'
msg_fmt = _("The attachment with vpn gateway ID '%(vgw_id)s' "
"and vpc ID '%(vpc_id)s' does not exist")
class ResourceLimitExceeded(EC2OverlimitException):
msg_fmt = _('You have reached the limit of %(resource)s')
class VpcLimitExceeded(EC2OverlimitException):
msg_fmt = _('The maximum number of VPCs has been reached.')
class SubnetLimitExceeded(EC2OverlimitException):
msg_fmt = _('You have reached the limit on the number of subnets that you '
'can create')
class InsufficientFreeAddressesInSubnet(EC2OverlimitException):
msg_fmt = _('The specified subnet does not have enough free addresses to '
'satisfy the request.')
class AddressLimitExceeded(EC2OverlimitException):
msg_fmt = _('The maximum number of addresses has been reached.')
class SecurityGroupLimitExceeded(EC2OverlimitException):
msg_fmt = _('You have reached the limit of security groups')
class RulesPerSecurityGroupLimitExceeded(EC2OverlimitException):
msg_fmt = _("You've reached the limit on the number of rules that "
"you can add to a security group.")
class VpnGatewayAttachmentLimitExceeded(EC2OverlimitException):
msg_fmt = _('The maximum number of virtual private gateway attachments '
'has been reached.')
class InvalidGroupReserved(EC2InvalidException):
ec2_code = 'InvalidGroup.Reserved'
msg_fmt = _("The security group '%(group_name)' is reserved.")