Added wsme support to the magnum apis
Co-Authored-By: Digambar Patil <digambarpat@gmail.com> Co-Authored-By: Steven Dake <sdake@redhat.com> Change-Id: I1daa79f8de7744d81b629a0c1836b3dc0ca59c71
This commit is contained in:
parent
e404e944ad
commit
f90f540db4
@ -1,27 +1,202 @@
|
||||
|
||||
import ast
|
||||
import base64
|
||||
import copy
|
||||
import datetime
|
||||
import functools
|
||||
import inspect
|
||||
import json
|
||||
#import pytz
|
||||
import uuid
|
||||
import pecan
|
||||
import wsme
|
||||
from oslo.config import cfg
|
||||
from oslo.utils import netutils
|
||||
from oslo.utils import strutils
|
||||
from oslo.utils import timeutils
|
||||
from wsme import types as wtypes
|
||||
import wsmeext.pecan as weme_pecan
|
||||
import wsmeext.pecan as wsme_pecan
|
||||
from pecan import rest, response
|
||||
import six
|
||||
|
||||
|
||||
state_kind = ["ok", "alarm", "insufficient data"]
|
||||
state_kind_enum = wtypes.Enum(str, *state_kind)
|
||||
operation_kind = ('lt', 'le', 'eq', 'ne', 'ge', 'gt')
|
||||
operation_kind_enum = wtypes.Enum(str, *operation_kind)
|
||||
|
||||
class _Base(wtypes.Base):
|
||||
|
||||
@classmethod
|
||||
def from_db_model(cls, m):
|
||||
return cls(**(m.as_dict()))
|
||||
|
||||
@classmethod
|
||||
def from_db_and_links(cls, m, links):
|
||||
return cls(links=links, **(m.as_dict()))
|
||||
|
||||
def as_dict(self, db_model):
|
||||
valid_keys = inspect.getargspec(db_model.__init__)[0]
|
||||
if 'self' in valid_keys:
|
||||
valid_keys.remove('self')
|
||||
return self.as_dict_from_keys(valid_keys)
|
||||
|
||||
def as_dict_from_keys(self, keys):
|
||||
return dict((k, getattr(self, k))
|
||||
for k in keys
|
||||
if hasattr(self, k) and
|
||||
getattr(self, k) != wsme.Unset)
|
||||
|
||||
class Query(_Base):
|
||||
"""Query filter."""
|
||||
|
||||
# The data types supported by the query.
|
||||
_supported_types = ['integer', 'float', 'string', 'boolean']
|
||||
|
||||
# Functions to convert the data field to the correct type.
|
||||
_type_converters = {'integer': int,
|
||||
'float': float,
|
||||
'boolean': functools.partial(
|
||||
strutils.bool_from_string, strict=True),
|
||||
'string': six.text_type,
|
||||
'datetime': timeutils.parse_isotime}
|
||||
|
||||
_op = None # provide a default
|
||||
|
||||
def get_op(self):
|
||||
return self._op or 'eq'
|
||||
|
||||
def set_op(self, value):
|
||||
self._op = value
|
||||
|
||||
field = wtypes.text
|
||||
"The name of the field to test"
|
||||
|
||||
# op = wsme.wsattr(operation_kind, default='eq')
|
||||
# this ^ doesn't seem to work.
|
||||
op = wsme.wsproperty(operation_kind_enum, get_op, set_op)
|
||||
"The comparison operator. Defaults to 'eq'."
|
||||
|
||||
value = wtypes.text
|
||||
"The value to compare against the stored data"
|
||||
|
||||
type = wtypes.text
|
||||
"The data type of value to compare against the stored data"
|
||||
|
||||
def __repr__(self):
|
||||
# for logging calls
|
||||
return '<Query %r %s %r %s>' % (self.field,
|
||||
self.op,
|
||||
self.value,
|
||||
self.type)
|
||||
|
||||
@classmethod
|
||||
def sample(cls):
|
||||
return cls(field='resource_id',
|
||||
op='eq',
|
||||
value='bd9431c1-8d69-4ad3-803a-8d4a6b89fd36',
|
||||
type='string'
|
||||
)
|
||||
|
||||
def as_dict(self):
|
||||
return self.as_dict_from_keys(['field', 'op', 'type', 'value'])
|
||||
|
||||
def _get_value_as_type(self, forced_type=None):
|
||||
"""Convert metadata value to the specified data type.
|
||||
|
||||
This method is called during metadata query to help convert the
|
||||
querying metadata to the data type specified by user. If there is no
|
||||
data type given, the metadata will be parsed by ast.literal_eval to
|
||||
try to do a smart converting.
|
||||
|
||||
NOTE (flwang) Using "_" as prefix to avoid an InvocationError raised
|
||||
from wsmeext/sphinxext.py. It's OK to call it outside the Query class.
|
||||
Because the "public" side of that class is actually the outside of the
|
||||
API, and the "private" side is the API implementation. The method is
|
||||
only used in the API implementation, so it's OK.
|
||||
|
||||
:returns: metadata value converted with the specified data type.
|
||||
"""
|
||||
type = forced_type or self.type
|
||||
try:
|
||||
converted_value = self.value
|
||||
if not type:
|
||||
try:
|
||||
converted_value = ast.literal_eval(self.value)
|
||||
except (ValueError, SyntaxError):
|
||||
# Unable to convert the metadata value automatically
|
||||
# let it default to self.value
|
||||
pass
|
||||
else:
|
||||
if type not in self._supported_types:
|
||||
# Types must be explicitly declared so the
|
||||
# correct type converter may be used. Subclasses
|
||||
# of Query may define _supported_types and
|
||||
# _type_converters to define their own types.
|
||||
raise TypeError()
|
||||
converted_value = self._type_converters[type](self.value)
|
||||
except ValueError:
|
||||
msg = (_('Unable to convert the value %(value)s'
|
||||
' to the expected data type %(type)s.') %
|
||||
{'value': self.value, 'type': type})
|
||||
raise ClientSideError(msg)
|
||||
except TypeError:
|
||||
msg = (_('The data type %(type)s is not supported. The supported'
|
||||
' data type list is: %(supported)s') %
|
||||
{'type': type, 'supported': self._supported_types})
|
||||
raise ClientSideError(msg)
|
||||
except Exception:
|
||||
msg = (_('Unexpected exception converting %(value)s to'
|
||||
' the expected data type %(type)s.') %
|
||||
{'value': self.value, 'type': type})
|
||||
raise ClientSideError(msg)
|
||||
return converted_value
|
||||
|
||||
|
||||
|
||||
class Container(_Base):
|
||||
container_id = wtypes.text
|
||||
""" The ID of the containers."""
|
||||
|
||||
name = wsme.wsattr(wtypes.text, mandatory=True)
|
||||
""" The name of the container."""
|
||||
|
||||
desc = wsme.wsattr(wtypes.text, mandatory=True)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(Container, self).__init__(**kwargs)
|
||||
|
||||
@classmethod
|
||||
def sample(cls):
|
||||
return cls(id=str(uuid.uuid1(),
|
||||
name="Docker",
|
||||
desc='Docker Containers'))
|
||||
|
||||
|
||||
class ContainerController(rest.RestController):
|
||||
|
||||
@weme_pecan.wsexpose(Container)
|
||||
def get(self):
|
||||
#TODO: Returns all the containers
|
||||
|
||||
@wsme_pecan.wsexpose([Container], [Query], int)
|
||||
def get_all(self, q=None, limit=None):
|
||||
# TODO: Returns all the containers
|
||||
return {
|
||||
"200": "It returns all the containers."
|
||||
}
|
||||
|
||||
@wsme_pecan.wsexpose(Container, wtypes.text)
|
||||
def get_one(self, container_id):
|
||||
# TODO: Returns all the containers
|
||||
return {
|
||||
"200": "It returns all the containers."
|
||||
}
|
||||
|
||||
@wsme_pecan.wsexpose(Container, body=Container, status_code=201)
|
||||
def post(self):
|
||||
}
|
||||
|
||||
@wsme_pecan.wsexpose([Container], body=[Container])
|
||||
def post(self, data):
|
||||
# TODO: Create a new container
|
||||
response.status = 201
|
||||
response.status=201
|
||||
return
|
||||
|
||||
|
||||
@wsme_pecan.wsexpose(None, status_code=204)
|
||||
def delete(self):
|
||||
# TODO: DELETE the containers
|
||||
response.status = 200
|
||||
response.status=200
|
||||
return
|
||||
|
Loading…
x
Reference in New Issue
Block a user