Merge "API: fixes and error handling"
This commit is contained in:
commit
0c506e7a2c
@ -21,6 +21,7 @@ import pwd
|
|||||||
import pecan
|
import pecan
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
import wsme_overrides
|
||||||
from libra.api import config as api_config
|
from libra.api import config as api_config
|
||||||
from libra.api import model
|
from libra.api import model
|
||||||
from libra.api import acl
|
from libra.api import acl
|
||||||
@ -28,6 +29,10 @@ from libra.common.options import Options, setup_logging
|
|||||||
from eventlet import wsgi
|
from eventlet import wsgi
|
||||||
|
|
||||||
|
|
||||||
|
# Gets rid of pep8 error
|
||||||
|
assert wsme_overrides
|
||||||
|
|
||||||
|
|
||||||
def get_pecan_config():
|
def get_pecan_config():
|
||||||
# Set up the pecan configuration
|
# Set up the pecan configuration
|
||||||
filename = api_config.__file__.replace('.pyc', '.py')
|
filename = api_config.__file__.replace('.pyc', '.py')
|
||||||
|
@ -26,9 +26,9 @@ app = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wsme = {
|
#wsme = {
|
||||||
'debug': True
|
# 'debug': True
|
||||||
}
|
#}
|
||||||
|
|
||||||
#database = {
|
#database = {
|
||||||
# 'username': 'root',
|
# 'username': 'root',
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import socket
|
||||||
# pecan imports
|
# pecan imports
|
||||||
from pecan import expose, abort, response, request
|
from pecan import expose, abort, response, request
|
||||||
from pecan.rest import RestController
|
from pecan.rest import RestController
|
||||||
@ -26,9 +27,11 @@ from logs import LogsController
|
|||||||
# models
|
# models
|
||||||
from libra.api.model.lbaas import LoadBalancer, Device, Node, session
|
from libra.api.model.lbaas import LoadBalancer, Device, Node, session
|
||||||
from libra.api.model.lbaas import loadbalancers_devices, Limits
|
from libra.api.model.lbaas import loadbalancers_devices, Limits
|
||||||
from libra.api.model.validators import LBPut, LBPost, LBResp, LBVipResp, LBNode
|
from libra.api.model.validators import LBPut, LBPost, LBResp, LBVipResp
|
||||||
|
from libra.api.model.validators import LBRespNode
|
||||||
from libra.api.library.gearman_client import submit_job
|
from libra.api.library.gearman_client import submit_job
|
||||||
from libra.api.acl import get_limited_to_project
|
from libra.api.acl import get_limited_to_project
|
||||||
|
from libra.api.library.exp import OverLimit
|
||||||
|
|
||||||
|
|
||||||
class LoadBalancersController(RestController):
|
class LoadBalancersController(RestController):
|
||||||
@ -58,13 +61,20 @@ class LoadBalancersController(RestController):
|
|||||||
|
|
||||||
# if we don't have an id then we want a list of them own by this tenent
|
# if we don't have an id then we want a list of them own by this tenent
|
||||||
if not load_balancer_id:
|
if not load_balancer_id:
|
||||||
load_balancers = {'loadBalancers': session.query(
|
lbs = session.query(
|
||||||
LoadBalancer.name, LoadBalancer.id, LoadBalancer.protocol,
|
LoadBalancer.name, LoadBalancer.id, LoadBalancer.protocol,
|
||||||
LoadBalancer.port, LoadBalancer.algorithm,
|
LoadBalancer.port, LoadBalancer.algorithm,
|
||||||
LoadBalancer.status, LoadBalancer.created,
|
LoadBalancer.status, LoadBalancer.created,
|
||||||
LoadBalancer.updated
|
LoadBalancer.updated
|
||||||
).filter(LoadBalancer.tenantid == tenant_id).
|
).filter(LoadBalancer.tenantid == tenant_id).\
|
||||||
filter(LoadBalancer.status != 'DELETED').all()}
|
filter(LoadBalancer.status != 'DELETED').all()
|
||||||
|
|
||||||
|
load_balancers = {'loadBalancers': []}
|
||||||
|
|
||||||
|
for lb in lbs:
|
||||||
|
lb = lb._asdict()
|
||||||
|
lb['id'] = str(lb['id'])
|
||||||
|
load_balancers['loadBalancers'].append(lb)
|
||||||
else:
|
else:
|
||||||
load_balancers = session.query(
|
load_balancers = session.query(
|
||||||
LoadBalancer.name, LoadBalancer.id, LoadBalancer.protocol,
|
LoadBalancer.name, LoadBalancer.id, LoadBalancer.protocol,
|
||||||
@ -97,6 +107,8 @@ class LoadBalancersController(RestController):
|
|||||||
vip = item._asdict()
|
vip = item._asdict()
|
||||||
vip['type'] = 'PUBLIC'
|
vip['type'] = 'PUBLIC'
|
||||||
vip['ipVersion'] = 'IPV4'
|
vip['ipVersion'] = 'IPV4'
|
||||||
|
vip['address'] = vip['floatingIpAddr']
|
||||||
|
del(vip['floatingIpAddr'])
|
||||||
load_balancers['virtualIps'].append(vip)
|
load_balancers['virtualIps'].append(vip)
|
||||||
|
|
||||||
nodes = session.query(
|
nodes = session.query(
|
||||||
@ -106,6 +118,10 @@ class LoadBalancersController(RestController):
|
|||||||
filter(LoadBalancer.id == load_balancer_id).\
|
filter(LoadBalancer.id == load_balancer_id).\
|
||||||
all()
|
all()
|
||||||
|
|
||||||
|
load_balancers['id'] = str(load_balancers['id'])
|
||||||
|
if not load_balancers['statusDescription']:
|
||||||
|
load_balancers['statusDescription'] = ''
|
||||||
|
|
||||||
load_balancers['nodes'] = []
|
load_balancers['nodes'] = []
|
||||||
for item in nodes:
|
for item in nodes:
|
||||||
node = item._asdict()
|
node = item._asdict()
|
||||||
@ -114,9 +130,11 @@ class LoadBalancersController(RestController):
|
|||||||
else:
|
else:
|
||||||
node['condition'] = 'DISABLED'
|
node['condition'] = 'DISABLED'
|
||||||
del node['enabled']
|
del node['enabled']
|
||||||
|
node['port'] = str(node['port'])
|
||||||
|
node['id'] = str(node['id'])
|
||||||
load_balancers['nodes'].append(node)
|
load_balancers['nodes'].append(node)
|
||||||
|
|
||||||
session.commit()
|
session.rollback()
|
||||||
response.status = 200
|
response.status = 200
|
||||||
return load_balancers
|
return load_balancers
|
||||||
|
|
||||||
@ -140,27 +158,48 @@ class LoadBalancersController(RestController):
|
|||||||
Returns: dict
|
Returns: dict
|
||||||
"""
|
"""
|
||||||
tenant_id = get_limited_to_project(request.headers)
|
tenant_id = get_limited_to_project(request.headers)
|
||||||
if body.nodes == Unset:
|
if body.nodes == Unset or not len(body.nodes):
|
||||||
raise ClientSideError(
|
raise ClientSideError(
|
||||||
'At least one backend node needs to be supplied'
|
'At least one backend node needs to be supplied'
|
||||||
)
|
)
|
||||||
|
for node in body.nodes:
|
||||||
|
if node.address == Unset:
|
||||||
|
raise ClientSideError(
|
||||||
|
'A supplied node has no address'
|
||||||
|
)
|
||||||
|
if node.port == Unset:
|
||||||
|
raise ClientSideError(
|
||||||
|
'Node {0} is missing a port'.format(node.address)
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
socket.inet_aton(node.address)
|
||||||
|
except socket.error:
|
||||||
|
raise ClientSideError(
|
||||||
|
'IP Address {0} not valid'.format(node.address)
|
||||||
|
)
|
||||||
|
|
||||||
lblimit = session.query(Limits.value).\
|
lblimit = session.query(Limits.value).\
|
||||||
filter(Limits.name == 'maxLoadBalancers').scalar()
|
filter(Limits.name == 'maxLoadBalancers').scalar()
|
||||||
nodelimit = session.query(Limits.value).\
|
nodelimit = session.query(Limits.value).\
|
||||||
filter(Limits.name == 'maxNodesPerLoadBalancer').scalar()
|
filter(Limits.name == 'maxNodesPerLoadBalancer').scalar()
|
||||||
|
namelimit = session.query(Limits.value).\
|
||||||
|
filter(Limits.name == 'maxLoadBalancerNameLength').scalar()
|
||||||
count = session.query(LoadBalancer).\
|
count = session.query(LoadBalancer).\
|
||||||
filter(LoadBalancer.tenantid == tenant_id).\
|
filter(LoadBalancer.tenantid == tenant_id).\
|
||||||
filter(LoadBalancer.status != 'DELETED').count()
|
filter(LoadBalancer.status != 'DELETED').count()
|
||||||
|
|
||||||
|
if len(body.name) > namelimit:
|
||||||
|
raise ClientSideError(
|
||||||
|
'Length of Load Balancer name too long'
|
||||||
|
)
|
||||||
# TODO: this should probably be a 413, not sure how to do that yet
|
# TODO: this should probably be a 413, not sure how to do that yet
|
||||||
if count >= lblimit:
|
if count >= lblimit:
|
||||||
raise ClientSideError(
|
raise OverLimit(
|
||||||
'Account has hit limit of {0} Load Balancers'.
|
'Account has hit limit of {0} Load Balancers'.
|
||||||
format(lblimit)
|
format(lblimit)
|
||||||
)
|
)
|
||||||
if len(body.nodes) > nodelimit:
|
if len(body.nodes) > nodelimit:
|
||||||
raise ClientSideError(
|
raise OverLimit(
|
||||||
'Too many backend nodes supplied (limit is {0}'.
|
'Too many backend nodes supplied (limit is {0}'.
|
||||||
format(nodelimit)
|
format(nodelimit)
|
||||||
)
|
)
|
||||||
@ -261,7 +300,7 @@ class LoadBalancersController(RestController):
|
|||||||
enabled = 1
|
enabled = 1
|
||||||
out_node = Node(
|
out_node = Node(
|
||||||
lbid=lb.id, port=node.port, address=node.address,
|
lbid=lb.id, port=node.port, address=node.address,
|
||||||
enabled=enabled, status='ONLINE', weight=0
|
enabled=enabled, status='ONLINE', weight=1
|
||||||
)
|
)
|
||||||
session.add(out_node)
|
session.add(out_node)
|
||||||
|
|
||||||
@ -273,23 +312,23 @@ class LoadBalancersController(RestController):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
return_data = LBResp()
|
return_data = LBResp()
|
||||||
return_data.id = lb.id
|
return_data.id = str(lb.id)
|
||||||
return_data.name = lb.name
|
return_data.name = lb.name
|
||||||
return_data.protocol = lb.protocol
|
return_data.protocol = lb.protocol
|
||||||
return_data.port = lb.port
|
return_data.port = str(lb.port)
|
||||||
return_data.algorithm = lb.algorithm
|
return_data.algorithm = lb.algorithm
|
||||||
return_data.status = lb.status
|
return_data.status = lb.status
|
||||||
return_data.created = lb.created
|
return_data.created = lb.created
|
||||||
return_data.updated = lb.updated
|
return_data.updated = lb.updated
|
||||||
vip_resp = LBVipResp(
|
vip_resp = LBVipResp(
|
||||||
address=device.floatingIpAddr, id=device.id,
|
address=device.floatingIpAddr, id=str(device.id),
|
||||||
type='PUBLIC', ipVersion='IPV4'
|
type='PUBLIC', ipVersion='IPV4'
|
||||||
)
|
)
|
||||||
return_data.virtualIps = [vip_resp]
|
return_data.virtualIps = [vip_resp]
|
||||||
return_data.nodes = []
|
return_data.nodes = []
|
||||||
for node in body.nodes:
|
for node in body.nodes:
|
||||||
out_node = LBNode(
|
out_node = LBRespNode(
|
||||||
port=node.port, address=node.address,
|
port=str(node.port), address=node.address,
|
||||||
condition=node.condition
|
condition=node.condition
|
||||||
)
|
)
|
||||||
return_data.nodes.append(out_node)
|
return_data.nodes.append(out_node)
|
||||||
@ -326,6 +365,12 @@ class LoadBalancersController(RestController):
|
|||||||
raise ClientSideError('Load Balancer ID is not valid')
|
raise ClientSideError('Load Balancer ID is not valid')
|
||||||
|
|
||||||
if body.name != Unset:
|
if body.name != Unset:
|
||||||
|
namelimit = session.query(Limits.value).\
|
||||||
|
filter(Limits.name == 'maxLoadBalancerNameLength').scalar()
|
||||||
|
if len(body.name) > namelimit:
|
||||||
|
raise ClientSideError(
|
||||||
|
'Length of Load Balancer name too long'
|
||||||
|
)
|
||||||
lb.name = body.name
|
lb.name = body.name
|
||||||
|
|
||||||
if body.algorithm != Unset:
|
if body.algorithm != Unset:
|
||||||
@ -341,7 +386,7 @@ class LoadBalancersController(RestController):
|
|||||||
submit_job(
|
submit_job(
|
||||||
'UPDATE', device.name, device.id, lb.id
|
'UPDATE', device.name, device.id, lb.id
|
||||||
)
|
)
|
||||||
return
|
return ''
|
||||||
|
|
||||||
@expose('json')
|
@expose('json')
|
||||||
def delete(self, load_balancer_id):
|
def delete(self, load_balancer_id):
|
||||||
@ -388,7 +433,7 @@ class LoadBalancersController(RestController):
|
|||||||
'DELETE', device.name, device.id, lb.id
|
'DELETE', device.name, device.id, lb.id
|
||||||
)
|
)
|
||||||
response.status = 202
|
response.status = 202
|
||||||
return None
|
return ''
|
||||||
except:
|
except:
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
logger.exception('Error communicating with load balancer pool')
|
logger.exception('Error communicating with load balancer pool')
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import socket
|
||||||
from pecan import expose, response, request, abort
|
from pecan import expose, response, request, abort
|
||||||
from pecan.rest import RestController
|
from pecan.rest import RestController
|
||||||
import wsmeext.pecan as wsme_pecan
|
import wsmeext.pecan as wsme_pecan
|
||||||
@ -24,6 +25,7 @@ from libra.api.acl import get_limited_to_project
|
|||||||
from libra.api.model.validators import LBNodeResp, LBNodePost, NodeResp
|
from libra.api.model.validators import LBNodeResp, LBNodePost, NodeResp
|
||||||
from libra.api.model.validators import LBNodePut
|
from libra.api.model.validators import LBNodePut
|
||||||
from libra.api.library.gearman_client import submit_job
|
from libra.api.library.gearman_client import submit_job
|
||||||
|
from libra.api.library.exp import OverLimit
|
||||||
|
|
||||||
|
|
||||||
class NodesController(RestController):
|
class NodesController(RestController):
|
||||||
@ -112,9 +114,25 @@ class NodesController(RestController):
|
|||||||
if self.lbid is None:
|
if self.lbid is None:
|
||||||
raise ClientSideError('Load Balancer ID has not been supplied')
|
raise ClientSideError('Load Balancer ID has not been supplied')
|
||||||
|
|
||||||
if not len(body.nodes):
|
if body.nodes == Unset or not len(body.nodes):
|
||||||
raise ClientSideError('No nodes have been supplied')
|
raise ClientSideError('No nodes have been supplied')
|
||||||
|
|
||||||
|
for node in body.nodes:
|
||||||
|
if node.address == Unset:
|
||||||
|
raise ClientSideError(
|
||||||
|
'A supplied node has no address'
|
||||||
|
)
|
||||||
|
if node.port == Unset:
|
||||||
|
raise ClientSideError(
|
||||||
|
'Node {0} is missing a port'.format(node.address)
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
socket.inet_aton(node.address)
|
||||||
|
except socket.error:
|
||||||
|
raise ClientSideError(
|
||||||
|
'IP Address {0} not valid'.format(node.address)
|
||||||
|
)
|
||||||
|
|
||||||
load_balancer = session.query(LoadBalancer).\
|
load_balancer = session.query(LoadBalancer).\
|
||||||
filter(LoadBalancer.tenantid == tenant_id).\
|
filter(LoadBalancer.tenantid == tenant_id).\
|
||||||
filter(LoadBalancer.id == self.lbid).\
|
filter(LoadBalancer.id == self.lbid).\
|
||||||
@ -130,8 +148,8 @@ class NodesController(RestController):
|
|||||||
nodecount = session.query(Node).\
|
nodecount = session.query(Node).\
|
||||||
filter(Node.lbid == self.lbid).count()
|
filter(Node.lbid == self.lbid).count()
|
||||||
|
|
||||||
if (nodecount + len(body.nodes)) >= nodelimit:
|
if (nodecount + len(body.nodes)) > nodelimit:
|
||||||
raise ClientSideError(
|
raise OverLimit(
|
||||||
'Command would exceed Load Balancer node limit'
|
'Command would exceed Load Balancer node limit'
|
||||||
)
|
)
|
||||||
return_data = LBNodeResp()
|
return_data = LBNodeResp()
|
||||||
@ -143,7 +161,7 @@ class NodesController(RestController):
|
|||||||
enabled = 1
|
enabled = 1
|
||||||
new_node = Node(
|
new_node = Node(
|
||||||
lbid=self.lbid, port=node.port, address=node.address,
|
lbid=self.lbid, port=node.port, address=node.address,
|
||||||
enabled=enabled, status='ONLINE', weight=0
|
enabled=enabled, status='ONLINE', weight=1
|
||||||
)
|
)
|
||||||
session.add(new_node)
|
session.add(new_node)
|
||||||
session.flush()
|
session.flush()
|
||||||
@ -206,7 +224,7 @@ class NodesController(RestController):
|
|||||||
submit_job(
|
submit_job(
|
||||||
'UPDATE', device.name, device.id, lb.id
|
'UPDATE', device.name, device.id, lb.id
|
||||||
)
|
)
|
||||||
return
|
return ''
|
||||||
|
|
||||||
@expose('json')
|
@expose('json')
|
||||||
def delete(self, node_id):
|
def delete(self, node_id):
|
||||||
|
27
libra/api/library/exp.py
Normal file
27
libra/api/library/exp.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Copyright 2013 Hewlett-Packard Development Company, L.P.
|
||||||
|
#
|
||||||
|
# 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 six
|
||||||
|
from wsme.exc import ClientSideError
|
||||||
|
from wsme.utils import _
|
||||||
|
|
||||||
|
|
||||||
|
class OverLimit(ClientSideError):
|
||||||
|
def __init__(self, msg=''):
|
||||||
|
self.msg = msg
|
||||||
|
super(OverLimit, self).__init__()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def faultstring(self):
|
||||||
|
return _(six.u("OverLimit: %s")) % (self.msg)
|
@ -107,7 +107,8 @@ class GearmanClientThread(object):
|
|||||||
# Device should never be used again
|
# Device should never be used again
|
||||||
device = session.query(Device).\
|
device = session.query(Device).\
|
||||||
filter(Device.id == data).first()
|
filter(Device.id == data).first()
|
||||||
device.status = 'DELETED'
|
#TODO: change this to 'DELETED' when pool mgm deletes
|
||||||
|
device.status = 'OFFLINE'
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
def _set_error(self, device_id, errmsg):
|
def _set_error(self, device_id, errmsg):
|
||||||
|
@ -24,6 +24,12 @@ class LBNode(Base):
|
|||||||
condition = Enum(wtypes.text, 'ENABLED', 'DISABLED')
|
condition = Enum(wtypes.text, 'ENABLED', 'DISABLED')
|
||||||
|
|
||||||
|
|
||||||
|
class LBRespNode(Base):
|
||||||
|
port = wtypes.text
|
||||||
|
address = wtypes.text
|
||||||
|
condition = wtypes.text
|
||||||
|
|
||||||
|
|
||||||
class LBNodePut(Base):
|
class LBNodePut(Base):
|
||||||
condition = Enum(wtypes.text, 'ENABLED', 'DISABLED')
|
condition = Enum(wtypes.text, 'ENABLED', 'DISABLED')
|
||||||
|
|
||||||
@ -63,7 +69,7 @@ class LBPut(Base):
|
|||||||
|
|
||||||
|
|
||||||
class LBVipResp(Base):
|
class LBVipResp(Base):
|
||||||
id = int
|
id = wtypes.text
|
||||||
address = wtypes.text
|
address = wtypes.text
|
||||||
type = wtypes.text
|
type = wtypes.text
|
||||||
ipVersion = wtypes.text
|
ipVersion = wtypes.text
|
||||||
@ -77,13 +83,13 @@ class LBLogsPost(Base):
|
|||||||
|
|
||||||
|
|
||||||
class LBResp(Base):
|
class LBResp(Base):
|
||||||
id = int
|
id = wtypes.text
|
||||||
name = wtypes.text
|
name = wtypes.text
|
||||||
protocol = wtypes.text
|
protocol = wtypes.text
|
||||||
port = int
|
port = wtypes.text
|
||||||
algorithm = wtypes.text
|
algorithm = wtypes.text
|
||||||
status = wtypes.text
|
status = wtypes.text
|
||||||
created = wtypes.text
|
created = wtypes.text
|
||||||
updated = wtypes.text
|
updated = wtypes.text
|
||||||
virtualIps = wsattr(['LBVipResp'])
|
virtualIps = wsattr(['LBVipResp'])
|
||||||
nodes = wsattr(['LBNode'])
|
nodes = wsattr(['LBRespNode'])
|
||||||
|
118
libra/api/wsme_overrides.py
Normal file
118
libra/api/wsme_overrides.py
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
# Copyright 2013 Hewlett-Packard Development Company, L.P.
|
||||||
|
#
|
||||||
|
# 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 logging
|
||||||
|
import traceback
|
||||||
|
import functools
|
||||||
|
import inspect
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import wsme
|
||||||
|
import wsme.rest.args
|
||||||
|
import wsme.rest.json
|
||||||
|
import wsme.rest.xml
|
||||||
|
import wsmeext.pecan
|
||||||
|
import pecan
|
||||||
|
from libra.api.library.exp import OverLimit
|
||||||
|
|
||||||
|
|
||||||
|
def format_exception(excinfo, debug=False):
|
||||||
|
"""Extract informations that can be sent to the client."""
|
||||||
|
error = excinfo[1]
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
if isinstance(error, wsme.exc.ClientSideError):
|
||||||
|
r = dict(faultcode="Client",
|
||||||
|
faultstring=error.faultstring)
|
||||||
|
log.warning("Client-side error: %s" % r['faultstring'])
|
||||||
|
return r
|
||||||
|
else:
|
||||||
|
faultstring = str(error)
|
||||||
|
debuginfo = "\n".join(traceback.format_exception(*excinfo))
|
||||||
|
|
||||||
|
log.error('Server-side error: "%s". Detail: \n%s' % (
|
||||||
|
faultstring, debuginfo))
|
||||||
|
|
||||||
|
if isinstance(error, ValueError):
|
||||||
|
r = dict(faultcode="Client", faultstring=faultstring)
|
||||||
|
else:
|
||||||
|
r = dict(faultcode="Server", faultstring=faultstring)
|
||||||
|
if debug:
|
||||||
|
r['debuginfo'] = debuginfo
|
||||||
|
return r
|
||||||
|
|
||||||
|
wsme.api.format_exception = format_exception
|
||||||
|
|
||||||
|
|
||||||
|
def wsexpose(*args, **kwargs):
|
||||||
|
pecan_json_decorate = pecan.expose(
|
||||||
|
template='wsmejson:',
|
||||||
|
content_type='application/json',
|
||||||
|
generic=False)
|
||||||
|
pecan_xml_decorate = pecan.expose(
|
||||||
|
template='wsmexml:',
|
||||||
|
content_type='application/xml',
|
||||||
|
generic=False
|
||||||
|
)
|
||||||
|
sig = wsme.signature(*args, **kwargs)
|
||||||
|
|
||||||
|
def decorate(f):
|
||||||
|
sig(f)
|
||||||
|
funcdef = wsme.api.FunctionDefinition.get(f)
|
||||||
|
funcdef.resolve_types(wsme.types.registry)
|
||||||
|
|
||||||
|
@functools.wraps(f)
|
||||||
|
def callfunction(self, *args, **kwargs):
|
||||||
|
try:
|
||||||
|
args, kwargs = wsme.rest.args.get_args(
|
||||||
|
funcdef, args, kwargs, pecan.request.params, None,
|
||||||
|
pecan.request.body, pecan.request.content_type
|
||||||
|
)
|
||||||
|
if funcdef.pass_request:
|
||||||
|
kwargs[funcdef.pass_request] = pecan.request
|
||||||
|
result = f(self, *args, **kwargs)
|
||||||
|
|
||||||
|
# NOTE: Support setting of status_code with default 201
|
||||||
|
pecan.response.status = funcdef.status_code
|
||||||
|
if isinstance(result, wsme.api.Response):
|
||||||
|
pecan.response.status = result.status_code
|
||||||
|
result = result.obj
|
||||||
|
|
||||||
|
except:
|
||||||
|
data = wsme.api.format_exception(
|
||||||
|
sys.exc_info(),
|
||||||
|
pecan.conf.get('wsme', {}).get('debug', False)
|
||||||
|
)
|
||||||
|
e = sys.exc_info()[1]
|
||||||
|
if isinstance(e, OverLimit):
|
||||||
|
pecan.response.status = 413
|
||||||
|
elif data['faultcode'] == 'Client':
|
||||||
|
pecan.response.status = 400
|
||||||
|
else:
|
||||||
|
pecan.response.status = 500
|
||||||
|
return data
|
||||||
|
|
||||||
|
return dict(
|
||||||
|
datatype=funcdef.return_type,
|
||||||
|
result=result
|
||||||
|
)
|
||||||
|
|
||||||
|
pecan_xml_decorate(callfunction)
|
||||||
|
pecan_json_decorate(callfunction)
|
||||||
|
pecan.util._cfg(callfunction)['argspec'] = inspect.getargspec(f)
|
||||||
|
callfunction._wsme_definition = funcdef
|
||||||
|
return callfunction
|
||||||
|
|
||||||
|
return decorate
|
||||||
|
|
||||||
|
wsmeext.pecan.wsexpose = wsexpose
|
Loading…
x
Reference in New Issue
Block a user