Source code for ironic.api.controllers.v1.types

# coding: utf-8
#
# Copyright 2013 Red Hat, Inc.
# All Rights Reserved.
#
#    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.

import json

from oslo_utils import strutils
from oslo_utils import uuidutils
import six
import wsme
from wsme import types as wtypes

from ironic.api.controllers.v1 import utils as v1_utils
from ironic.common import exception
from ironic.common.i18n import _
from ironic.common import utils


[docs]class MacAddressType(wtypes.UserType): """A simple MAC address type.""" basetype = wtypes.text name = 'macaddress' # FIXME(lucasagomes): When used with wsexpose decorator WSME will try # to get the name of the type by accessing it's __name__ attribute. # Remove this __name__ attribute once it's fixed in WSME. # https://bugs.launchpad.net/wsme/+bug/1265590 __name__ = name @staticmethod
[docs] def validate(value): return utils.validate_and_normalize_mac(value)
@staticmethod
[docs] def frombasetype(value): if value is None: return None return MacAddressType.validate(value)
[docs]class UuidOrNameType(wtypes.UserType): """A simple UUID or logical name type.""" basetype = wtypes.text name = 'uuid_or_name' # FIXME(lucasagomes): When used with wsexpose decorator WSME will try # to get the name of the type by accessing it's __name__ attribute. # Remove this __name__ attribute once it's fixed in WSME. # https://bugs.launchpad.net/wsme/+bug/1265590 __name__ = name @staticmethod
[docs] def validate(value): if not (uuidutils.is_uuid_like(value) or v1_utils.is_valid_logical_name(value)): raise exception.InvalidUuidOrName(name=value) return value
@staticmethod
[docs] def frombasetype(value): if value is None: return None return UuidOrNameType.validate(value)
[docs]class NameType(wtypes.UserType): """A simple logical name type.""" basetype = wtypes.text name = 'name' # FIXME(lucasagomes): When used with wsexpose decorator WSME will try # to get the name of the type by accessing it's __name__ attribute. # Remove this __name__ attribute once it's fixed in WSME. # https://bugs.launchpad.net/wsme/+bug/1265590 __name__ = name @staticmethod
[docs] def validate(value): if not v1_utils.is_valid_logical_name(value): raise exception.InvalidName(name=value) return value
@staticmethod
[docs] def frombasetype(value): if value is None: return None return NameType.validate(value)
[docs]class UuidType(wtypes.UserType): """A simple UUID type.""" basetype = wtypes.text name = 'uuid' # FIXME(lucasagomes): When used with wsexpose decorator WSME will try # to get the name of the type by accessing it's __name__ attribute. # Remove this __name__ attribute once it's fixed in WSME. # https://bugs.launchpad.net/wsme/+bug/1265590 __name__ = name @staticmethod
[docs] def validate(value): if not uuidutils.is_uuid_like(value): raise exception.InvalidUUID(uuid=value) return value
@staticmethod
[docs] def frombasetype(value): if value is None: return None return UuidType.validate(value)
[docs]class BooleanType(wtypes.UserType): """A simple boolean type.""" basetype = wtypes.text name = 'boolean' # FIXME(lucasagomes): When used with wsexpose decorator WSME will try # to get the name of the type by accessing it's __name__ attribute. # Remove this __name__ attribute once it's fixed in WSME. # https://bugs.launchpad.net/wsme/+bug/1265590 __name__ = name @staticmethod
[docs] def validate(value): try: return strutils.bool_from_string(value, strict=True) except ValueError as e: # raise Invalid to return 400 (BadRequest) in the API raise exception.Invalid(e)
@staticmethod
[docs] def frombasetype(value): if value is None: return None return BooleanType.validate(value)
[docs]class JsonType(wtypes.UserType): """A simple JSON type.""" basetype = wtypes.text name = 'json' # FIXME(lucasagomes): When used with wsexpose decorator WSME will try # to get the name of the type by accessing it's __name__ attribute. # Remove this __name__ attribute once it's fixed in WSME. # https://bugs.launchpad.net/wsme/+bug/1265590 __name__ = name def __str__(self): # These are the json serializable native types return ' | '.join(map(str, (wtypes.text, six.integer_types, float, BooleanType, list, dict, None))) @staticmethod
[docs] def validate(value): try: json.dumps(value) except TypeError: raise exception.Invalid(_('%s is not JSON serializable') % value) else: return value
@staticmethod
[docs] def frombasetype(value): return JsonType.validate(value)
[docs]class ListType(wtypes.UserType): """A simple list type.""" basetype = wtypes.text name = 'list' # FIXME(lucasagomes): When used with wsexpose decorator WSME will try # to get the name of the type by accessing it's __name__ attribute. # Remove this __name__ attribute once it's fixed in WSME. # https://bugs.launchpad.net/wsme/+bug/1265590 __name__ = name @staticmethod
[docs] def validate(value): """Validate and convert the input to a ListType. :param value: A comma separated string of values :returns: A list of values. """ items = [v.strip().lower() for v in six.text_type(value).split(',')] # filter() to remove empty items # set() to remove duplicated items return set(filter(None, items))
@staticmethod
[docs] def frombasetype(value): if value is None: return None return ListType.validate(value)
macaddress = MacAddressType() uuid_or_name = UuidOrNameType() name = NameType() uuid = UuidType() boolean = BooleanType() listtype = ListType() # Can't call it 'json' because that's the name of the stdlib module jsontype = JsonType()
[docs]class JsonPatchType(wtypes.Base): """A complex type that represents a single json-patch operation.""" path = wtypes.wsattr(wtypes.StringType(pattern='^(/[\w-]+)+$'), mandatory=True) op = wtypes.wsattr(wtypes.Enum(str, 'add', 'replace', 'remove'), mandatory=True) value = wsme.wsattr(jsontype, default=wtypes.Unset) @staticmethod
[docs] def internal_attrs(): """Returns a list of internal attributes. Internal attributes can't be added, replaced or removed. This method may be overwritten by derived class. """ return ['/created_at', '/id', '/links', '/updated_at', '/uuid']
@staticmethod
[docs] def mandatory_attrs(): """Retruns a list of mandatory attributes. Mandatory attributes can't be removed from the document. This method should be overwritten by derived class. """ return []
@staticmethod
[docs] def validate(patch): _path = '/' + patch.path.split('/')[1] if _path in patch.internal_attrs(): msg = _("'%s' is an internal attribute and can not be updated") raise wsme.exc.ClientSideError(msg % patch.path) if patch.path in patch.mandatory_attrs() and patch.op == 'remove': msg = _("'%s' is a mandatory attribute and can not be removed") raise wsme.exc.ClientSideError(msg % patch.path) if patch.op != 'remove': if patch.value is wsme.Unset: msg = _("'add' and 'replace' operations need a value") raise wsme.exc.ClientSideError(msg) ret = {'path': patch.path, 'op': patch.op} if patch.value is not wsme.Unset: ret['value'] = patch.value return ret