
In advance of a microversion 1.38, add the necessary database and object code to support saving consumer types when creating consumers and reporting those types when requesting usage information. This patch adds a new table called ``consumer_types`` and also add a new column called ``consumer_type_id`` that references the id in the consumer_types table. The consumer_type_id is nullable and records with a NULL consumer_type_id are considered as 'unknown'. In future changes we may wish to AttributeCache consumer types in the same way that traits and resource classes are cached. Usage object can now be retrieved by consumer type and include consumer type information when retrieved. Until 1.38 that info will not be used in results. Allocations are written and retrieved with a consumer type but the data is not yet presented in HTTP requests. Co-Authored-By: Chris Dent <cdent@anticdent.org> Co-Authored-By: melanie witt <melwittt@gmail.com> Story: 2005473 Task: 35683 Task: 36420 Change-Id: Ic74c3d1b8aa272e9c7d1070fe7658b928e693889
212 lines
6.6 KiB
Python
212 lines
6.6 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.
|
|
"""Exceptions for use in the Placement API."""
|
|
|
|
from oslo_log import log as logging
|
|
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
class _BaseException(Exception):
|
|
"""Base 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:
|
|
# NOTE(melwitt): This is done in a separate method so it can be
|
|
# monkey-patched during testing to make it a hard failure.
|
|
self._log_exception()
|
|
message = self.msg_fmt
|
|
|
|
self.message = message
|
|
super(_BaseException, self).__init__(message)
|
|
|
|
def _log_exception(self):
|
|
# kwargs doesn't match a variable in the message
|
|
# log the issue and the kwargs
|
|
LOG.exception('Exception in string format operation')
|
|
for name, value in self.kwargs.items():
|
|
LOG.error("%s: %s" % (name, value)) # noqa
|
|
|
|
def format_message(self):
|
|
# Use the first argument to the python Exception object which
|
|
# should be our full exception message, (see __init__).
|
|
return self.args[0]
|
|
|
|
|
|
class NotFound(_BaseException):
|
|
msg_fmt = "Resource could not be found."
|
|
|
|
|
|
class Exists(_BaseException):
|
|
msg_fmt = "Resource already exists."
|
|
|
|
|
|
class InvalidInventory(_BaseException):
|
|
msg_fmt = ("Inventory for '%(resource_class)s' on "
|
|
"resource provider '%(resource_provider)s' invalid.")
|
|
|
|
|
|
class CannotDeleteParentResourceProvider(_BaseException):
|
|
msg_fmt = ("Cannot delete resource provider that is a parent of "
|
|
"another. Delete child providers first.")
|
|
|
|
|
|
class ConcurrentUpdateDetected(_BaseException):
|
|
msg_fmt = ("Another thread concurrently updated the data. "
|
|
"Please retry your update")
|
|
|
|
|
|
class ResourceProviderConcurrentUpdateDetected(ConcurrentUpdateDetected):
|
|
msg_fmt = ("Another thread concurrently updated the resource provider "
|
|
"data. Please retry your update")
|
|
|
|
|
|
class ResourceProviderNotFound(NotFound):
|
|
# Marker exception indicating that we've filtered down to zero possible
|
|
# allocation candidates. Does not represent an API error; should only be
|
|
# used internally: no results is a 200 with empty allocation_requests.
|
|
msg_fmt = "No results are possible."
|
|
|
|
|
|
class InvalidAllocationCapacityExceeded(InvalidInventory):
|
|
msg_fmt = ("Unable to create allocation for '%(resource_class)s' on "
|
|
"resource provider '%(resource_provider)s'. The requested "
|
|
"amount would exceed the capacity.")
|
|
|
|
|
|
class InvalidAllocationConstraintsViolated(InvalidInventory):
|
|
msg_fmt = ("Unable to create allocation for '%(resource_class)s' on "
|
|
"resource provider '%(resource_provider)s'. The requested "
|
|
"amount would violate inventory constraints.")
|
|
|
|
|
|
class InvalidInventoryCapacity(InvalidInventory):
|
|
msg_fmt = ("Invalid inventory for '%(resource_class)s' on "
|
|
"resource provider '%(resource_provider)s'. "
|
|
"The reserved value is greater than or equal to total.")
|
|
|
|
|
|
class InvalidInventoryCapacityReservedCanBeTotal(InvalidInventoryCapacity):
|
|
msg_fmt = ("Invalid inventory for '%(resource_class)s' on "
|
|
"resource provider '%(resource_provider)s'. "
|
|
"The reserved value is greater than total.")
|
|
|
|
|
|
# An exception with this name is used on both sides of the placement/
|
|
# nova interaction.
|
|
class InventoryInUse(InvalidInventory):
|
|
msg_fmt = ("Inventory for '%(resource_classes)s' on "
|
|
"resource provider '%(resource_provider)s' in use.")
|
|
|
|
|
|
class InventoryWithResourceClassNotFound(NotFound):
|
|
msg_fmt = "No inventory of class %(resource_class)s found."
|
|
|
|
|
|
class MaxDBRetriesExceeded(_BaseException):
|
|
msg_fmt = ("Max retries of DB transaction exceeded attempting to "
|
|
"perform %(action)s.")
|
|
|
|
|
|
class ObjectActionError(_BaseException):
|
|
msg_fmt = 'Object action %(action)s failed because: %(reason)s'
|
|
|
|
|
|
class PolicyNotAuthorized(_BaseException):
|
|
msg_fmt = "Policy does not allow %(action)s to be performed."
|
|
|
|
|
|
class ResourceClassCannotDeleteStandard(_BaseException):
|
|
msg_fmt = "Cannot delete standard resource class %(resource_class)s."
|
|
|
|
|
|
class ResourceClassCannotUpdateStandard(_BaseException):
|
|
msg_fmt = "Cannot update standard resource class %(resource_class)s."
|
|
|
|
|
|
class ResourceClassExists(_BaseException):
|
|
msg_fmt = "Resource class %(resource_class)s already exists."
|
|
|
|
|
|
class ResourceClassInUse(_BaseException):
|
|
msg_fmt = ("Cannot delete resource class %(resource_class)s. "
|
|
"Class is in use in inventory.")
|
|
|
|
|
|
class ResourceClassNotFound(NotFound):
|
|
msg_fmt = "No such resource class %(name)s."
|
|
|
|
|
|
class ResourceProviderInUse(_BaseException):
|
|
msg_fmt = "Resource provider has allocations."
|
|
|
|
|
|
class TraitCannotDeleteStandard(_BaseException):
|
|
msg_fmt = "Cannot delete standard trait %(name)s."
|
|
|
|
|
|
class TraitExists(_BaseException):
|
|
msg_fmt = "The Trait %(name)s already exists"
|
|
|
|
|
|
class TraitInUse(_BaseException):
|
|
msg_fmt = "The trait %(name)s is in use by a resource provider."
|
|
|
|
|
|
class TraitNotFound(NotFound):
|
|
msg_fmt = "No such trait(s): %(name)s."
|
|
|
|
|
|
class ProjectNotFound(NotFound):
|
|
msg_fmt = "No such project(s): %(external_id)s."
|
|
|
|
|
|
class ProjectExists(Exists):
|
|
msg_fmt = "The project %(external_id)s already exists."
|
|
|
|
|
|
class UserNotFound(NotFound):
|
|
msg_fmt = "No such user(s): %(external_id)s."
|
|
|
|
|
|
class UserExists(Exists):
|
|
msg_fmt = "The user %(external_id)s already exists."
|
|
|
|
|
|
class ConsumerNotFound(NotFound):
|
|
msg_fmt = "No such consumer(s): %(uuid)s."
|
|
|
|
|
|
class ConsumerExists(Exists):
|
|
msg_fmt = "The consumer %(uuid)s already exists."
|
|
|
|
|
|
class ConsumerTypeNotFound(NotFound):
|
|
msg_fmt = "No such consumer type: %(name)s."
|
|
|
|
|
|
class ConsumerTypeExists(Exists):
|
|
msg_fmt = "The consumer type %(name)s already exists."
|