Disable XML now that we have WSME/Pecan support

We've had a desire to disable XML from the Ironic API for some
time, however to do so needed support in WSME/Pecan.  That's now
been added, so we can implement the Ironic side.

To do so, we wrap wsmeext.pecan.expose() and replace all the decorators
with a call to ironic.api.expose.expose().

Change-Id: I94d0387722225c4356c867f63b6f1a61356f317d
Closes-bug: 1271317
This commit is contained in:
Michael Davies 2015-03-31 21:33:41 -07:00 committed by Devananda van der Veen
parent 7e3896d248
commit f91a1fd6e7
9 changed files with 76 additions and 47 deletions

View File

@ -19,11 +19,11 @@
import pecan import pecan
from pecan import rest from pecan import rest
from wsme import types as wtypes from wsme import types as wtypes
import wsmeext.pecan as wsme_pecan
from ironic.api.controllers import base from ironic.api.controllers import base
from ironic.api.controllers import link from ironic.api.controllers import link
from ironic.api.controllers import v1 from ironic.api.controllers import v1
from ironic.api import expose
class Version(base.APIBase): class Version(base.APIBase):
@ -79,7 +79,7 @@ class RootController(rest.RestController):
v1 = v1.Controller() v1 = v1.Controller()
@wsme_pecan.wsexpose(Root) @expose.expose(Root)
def get(self): def get(self):
# NOTE: The reason why convert() it's being called for every # NOTE: The reason why convert() it's being called for every
# request is because we need to get the host url from # request is because we need to get the host url from

View File

@ -26,7 +26,6 @@ import pecan
from pecan import rest from pecan import rest
from webob import exc from webob import exc
from wsme import types as wtypes from wsme import types as wtypes
import wsmeext.pecan as wsme_pecan
from ironic.api.controllers import base from ironic.api.controllers import base
from ironic.api.controllers import link from ironic.api.controllers import link
@ -34,6 +33,7 @@ from ironic.api.controllers.v1 import chassis
from ironic.api.controllers.v1 import driver from ironic.api.controllers.v1 import driver
from ironic.api.controllers.v1 import node from ironic.api.controllers.v1 import node
from ironic.api.controllers.v1 import port from ironic.api.controllers.v1 import port
from ironic.api import expose
from ironic.common.i18n import _ from ironic.common.i18n import _
BASE_VERSION = 1 BASE_VERSION = 1
@ -158,7 +158,7 @@ class Controller(rest.RestController):
chassis = chassis.ChassisController() chassis = chassis.ChassisController()
drivers = driver.DriversController() drivers = driver.DriversController()
@wsme_pecan.wsexpose(V1) @expose.expose(V1)
def get(self): def get(self):
# NOTE: The reason why convert() it's being called for every # NOTE: The reason why convert() it's being called for every
# request is because we need to get the host url from # request is because we need to get the host url from

View File

@ -19,7 +19,6 @@ import pecan
from pecan import rest from pecan import rest
import wsme import wsme
from wsme import types as wtypes from wsme import types as wtypes
import wsmeext.pecan as wsme_pecan
from ironic.api.controllers import base from ironic.api.controllers import base
from ironic.api.controllers import link from ironic.api.controllers import link
@ -27,6 +26,7 @@ from ironic.api.controllers.v1 import collection
from ironic.api.controllers.v1 import node from ironic.api.controllers.v1 import node
from ironic.api.controllers.v1 import types from ironic.api.controllers.v1 import types
from ironic.api.controllers.v1 import utils as api_utils from ironic.api.controllers.v1 import utils as api_utils
from ironic.api import expose
from ironic.common import exception from ironic.common import exception
from ironic import objects from ironic import objects
@ -164,7 +164,7 @@ class ChassisController(rest.RestController):
sort_key=sort_key, sort_key=sort_key,
sort_dir=sort_dir) sort_dir=sort_dir)
@wsme_pecan.wsexpose(ChassisCollection, types.uuid, @expose.expose(ChassisCollection, types.uuid,
int, wtypes.text, wtypes.text) int, wtypes.text, wtypes.text)
def get_all(self, marker=None, limit=None, sort_key='id', sort_dir='asc'): def get_all(self, marker=None, limit=None, sort_key='id', sort_dir='asc'):
"""Retrieve a list of chassis. """Retrieve a list of chassis.
@ -176,7 +176,7 @@ class ChassisController(rest.RestController):
""" """
return self._get_chassis_collection(marker, limit, sort_key, sort_dir) return self._get_chassis_collection(marker, limit, sort_key, sort_dir)
@wsme_pecan.wsexpose(ChassisCollection, types.uuid, int, @expose.expose(ChassisCollection, types.uuid, int,
wtypes.text, wtypes.text) wtypes.text, wtypes.text)
def detail(self, marker=None, limit=None, sort_key='id', sort_dir='asc'): def detail(self, marker=None, limit=None, sort_key='id', sort_dir='asc'):
"""Retrieve a list of chassis with detail. """Retrieve a list of chassis with detail.
@ -196,7 +196,7 @@ class ChassisController(rest.RestController):
return self._get_chassis_collection(marker, limit, sort_key, sort_dir, return self._get_chassis_collection(marker, limit, sort_key, sort_dir,
expand, resource_url) expand, resource_url)
@wsme_pecan.wsexpose(Chassis, types.uuid) @expose.expose(Chassis, types.uuid)
def get_one(self, chassis_uuid): def get_one(self, chassis_uuid):
"""Retrieve information about the given chassis. """Retrieve information about the given chassis.
@ -206,7 +206,7 @@ class ChassisController(rest.RestController):
chassis_uuid) chassis_uuid)
return Chassis.convert_with_links(rpc_chassis) return Chassis.convert_with_links(rpc_chassis)
@wsme_pecan.wsexpose(Chassis, body=Chassis, status_code=201) @expose.expose(Chassis, body=Chassis, status_code=201)
def post(self, chassis): def post(self, chassis):
"""Create a new chassis. """Create a new chassis.
@ -220,7 +220,7 @@ class ChassisController(rest.RestController):
return Chassis.convert_with_links(new_chassis) return Chassis.convert_with_links(new_chassis)
@wsme.validate(types.uuid, [ChassisPatchType]) @wsme.validate(types.uuid, [ChassisPatchType])
@wsme_pecan.wsexpose(Chassis, types.uuid, body=[ChassisPatchType]) @expose.expose(Chassis, types.uuid, body=[ChassisPatchType])
def patch(self, chassis_uuid, patch): def patch(self, chassis_uuid, patch):
"""Update an existing chassis. """Update an existing chassis.
@ -250,7 +250,7 @@ class ChassisController(rest.RestController):
rpc_chassis.save() rpc_chassis.save()
return Chassis.convert_with_links(rpc_chassis) return Chassis.convert_with_links(rpc_chassis)
@wsme_pecan.wsexpose(None, types.uuid, status_code=204) @expose.expose(None, types.uuid, status_code=204)
def delete(self, chassis_uuid): def delete(self, chassis_uuid):
"""Delete a chassis. """Delete a chassis.

View File

@ -17,10 +17,10 @@ import pecan
from pecan import rest from pecan import rest
import wsme import wsme
from wsme import types as wtypes from wsme import types as wtypes
import wsmeext.pecan as wsme_pecan
from ironic.api.controllers import base from ironic.api.controllers import base
from ironic.api.controllers import link from ironic.api.controllers import link
from ironic.api import expose
from ironic.common import exception from ironic.common import exception
from ironic.common.i18n import _ from ironic.common.i18n import _
@ -114,7 +114,7 @@ class DriverPassthruController(rest.RestController):
'methods': ['GET'] 'methods': ['GET']
} }
@wsme_pecan.wsexpose(wtypes.text, wtypes.text) @expose.expose(wtypes.text, wtypes.text)
def methods(self, driver_name): def methods(self, driver_name):
"""Retrieve information about vendor methods of the given driver. """Retrieve information about vendor methods of the given driver.
@ -132,7 +132,7 @@ class DriverPassthruController(rest.RestController):
return _VENDOR_METHODS[driver_name] return _VENDOR_METHODS[driver_name]
@wsme_pecan.wsexpose(wtypes.text, wtypes.text, wtypes.text, @expose.expose(wtypes.text, wtypes.text, wtypes.text,
body=wtypes.text) body=wtypes.text)
def _default(self, driver_name, method, data=None): def _default(self, driver_name, method, data=None):
"""Call a driver API extension. """Call a driver API extension.
@ -166,7 +166,7 @@ class DriversController(rest.RestController):
'properties': ['GET'], 'properties': ['GET'],
} }
@wsme_pecan.wsexpose(DriverList) @expose.expose(DriverList)
def get_all(self): def get_all(self):
"""Retrieve a list of drivers.""" """Retrieve a list of drivers."""
# FIXME(deva): formatting of the auto-generated REST API docs # FIXME(deva): formatting of the auto-generated REST API docs
@ -176,7 +176,7 @@ class DriversController(rest.RestController):
driver_list = pecan.request.dbapi.get_active_driver_dict() driver_list = pecan.request.dbapi.get_active_driver_dict()
return DriverList.convert_with_links(driver_list) return DriverList.convert_with_links(driver_list)
@wsme_pecan.wsexpose(Driver, wtypes.text) @expose.expose(Driver, wtypes.text)
def get_one(self, driver_name): def get_one(self, driver_name):
"""Retrieve a single driver.""" """Retrieve a single driver."""
# NOTE(russell_h): There is no way to make this more efficient than # NOTE(russell_h): There is no way to make this more efficient than
@ -191,7 +191,7 @@ class DriversController(rest.RestController):
raise exception.DriverNotFound(driver_name=driver_name) raise exception.DriverNotFound(driver_name=driver_name)
@wsme_pecan.wsexpose(wtypes.text, wtypes.text) @expose.expose(wtypes.text, wtypes.text)
def properties(self, driver_name): def properties(self, driver_name):
"""Retrieve property information of the given driver. """Retrieve property information of the given driver.

View File

@ -23,7 +23,6 @@ import pecan
from pecan import rest from pecan import rest
import wsme import wsme
from wsme import types as wtypes from wsme import types as wtypes
import wsmeext.pecan as wsme_pecan
from ironic.api.controllers import base from ironic.api.controllers import base
from ironic.api.controllers import link from ironic.api.controllers import link
@ -31,6 +30,7 @@ from ironic.api.controllers.v1 import collection
from ironic.api.controllers.v1 import port from ironic.api.controllers.v1 import port
from ironic.api.controllers.v1 import types from ironic.api.controllers.v1 import types
from ironic.api.controllers.v1 import utils as api_utils from ironic.api.controllers.v1 import utils as api_utils
from ironic.api import expose
from ironic.common import exception from ironic.common import exception
from ironic.common.i18n import _ from ironic.common.i18n import _
from ironic.common import states as ir_states from ironic.common import states as ir_states
@ -132,7 +132,7 @@ class BootDeviceController(rest.RestController):
return pecan.request.rpcapi.get_boot_device(pecan.request.context, return pecan.request.rpcapi.get_boot_device(pecan.request.context,
rpc_node.uuid, topic) rpc_node.uuid, topic)
@wsme_pecan.wsexpose(None, types.uuid_or_name, wtypes.text, types.boolean, @expose.expose(None, types.uuid_or_name, wtypes.text, types.boolean,
status_code=204) status_code=204)
def put(self, node_ident, boot_device, persistent=False): def put(self, node_ident, boot_device, persistent=False):
"""Set the boot device for a node. """Set the boot device for a node.
@ -155,7 +155,7 @@ class BootDeviceController(rest.RestController):
persistent=persistent, persistent=persistent,
topic=topic) topic=topic)
@wsme_pecan.wsexpose(wtypes.text, types.uuid_or_name) @expose.expose(wtypes.text, types.uuid_or_name)
def get(self, node_ident): def get(self, node_ident):
"""Get the current boot device for a node. """Get the current boot device for a node.
@ -170,7 +170,7 @@ class BootDeviceController(rest.RestController):
""" """
return self._get_boot_device(node_ident) return self._get_boot_device(node_ident)
@wsme_pecan.wsexpose(wtypes.text, types.uuid_or_name) @expose.expose(wtypes.text, types.uuid_or_name)
def supported(self, node_ident): def supported(self, node_ident):
"""Get a list of the supported boot devices. """Get a list of the supported boot devices.
@ -207,7 +207,7 @@ class ConsoleInfo(base.APIBase):
class NodeConsoleController(rest.RestController): class NodeConsoleController(rest.RestController):
@wsme_pecan.wsexpose(ConsoleInfo, types.uuid_or_name) @expose.expose(ConsoleInfo, types.uuid_or_name)
def get(self, node_ident): def get(self, node_ident):
"""Get connection information about the console. """Get connection information about the console.
@ -225,7 +225,7 @@ class NodeConsoleController(rest.RestController):
return ConsoleInfo(console_enabled=console_state, console_info=console) return ConsoleInfo(console_enabled=console_state, console_info=console)
@wsme_pecan.wsexpose(None, types.uuid_or_name, types.boolean, @expose.expose(None, types.uuid_or_name, types.boolean,
status_code=202) status_code=202)
def put(self, node_ident, enabled): def put(self, node_ident, enabled):
"""Start and stop the node console. """Start and stop the node console.
@ -302,7 +302,7 @@ class NodeStatesController(rest.RestController):
console = NodeConsoleController() console = NodeConsoleController()
"""Expose console as a sub-element of states""" """Expose console as a sub-element of states"""
@wsme_pecan.wsexpose(NodeStates, types.uuid_or_name) @expose.expose(NodeStates, types.uuid_or_name)
def get(self, node_ident): def get(self, node_ident):
"""List the states of the node. """List the states of the node.
@ -314,7 +314,7 @@ class NodeStatesController(rest.RestController):
rpc_node = api_utils.get_rpc_node(node_ident) rpc_node = api_utils.get_rpc_node(node_ident)
return NodeStates.convert(rpc_node) return NodeStates.convert(rpc_node)
@wsme_pecan.wsexpose(None, types.uuid_or_name, wtypes.text, @expose.expose(None, types.uuid_or_name, wtypes.text,
status_code=202) status_code=202)
def power(self, node_ident, target): def power(self, node_ident, target):
"""Set the power state of the node. """Set the power state of the node.
@ -352,7 +352,7 @@ class NodeStatesController(rest.RestController):
url_args = '/'.join([node_ident, 'states']) url_args = '/'.join([node_ident, 'states'])
pecan.response.location = link.build_url('nodes', url_args) pecan.response.location = link.build_url('nodes', url_args)
@wsme_pecan.wsexpose(None, types.uuid_or_name, wtypes.text, @expose.expose(None, types.uuid_or_name, wtypes.text,
wtypes.text, status_code=202) wtypes.text, status_code=202)
def provision(self, node_ident, target, configdrive=None): def provision(self, node_ident, target, configdrive=None):
"""Asynchronous trigger the provisioning of the node. """Asynchronous trigger the provisioning of the node.
@ -665,7 +665,7 @@ class NodeVendorPassthruController(rest.RestController):
'methods': ['GET'] 'methods': ['GET']
} }
@wsme_pecan.wsexpose(wtypes.text, types.uuid_or_name) @expose.expose(wtypes.text, types.uuid_or_name)
def methods(self, node_ident): def methods(self, node_ident):
"""Retrieve information about vendor methods of the given node. """Retrieve information about vendor methods of the given node.
@ -685,7 +685,7 @@ class NodeVendorPassthruController(rest.RestController):
return _VENDOR_METHODS[rpc_node.driver] return _VENDOR_METHODS[rpc_node.driver]
@wsme_pecan.wsexpose(wtypes.text, types.uuid_or_name, wtypes.text, @expose.expose(wtypes.text, types.uuid_or_name, wtypes.text,
body=wtypes.text) body=wtypes.text)
def _default(self, node_ident, method, data=None): def _default(self, node_ident, method, data=None):
"""Call a vendor extension. """Call a vendor extension.
@ -728,7 +728,7 @@ class NodeMaintenanceController(rest.RestController):
pecan.request.rpcapi.update_node(pecan.request.context, pecan.request.rpcapi.update_node(pecan.request.context,
rpc_node, topic=topic) rpc_node, topic=topic)
@wsme_pecan.wsexpose(None, types.uuid_or_name, wtypes.text, @expose.expose(None, types.uuid_or_name, wtypes.text,
status_code=202) status_code=202)
def put(self, node_ident, reason=None): def put(self, node_ident, reason=None):
"""Put the node in maintenance mode. """Put the node in maintenance mode.
@ -739,7 +739,7 @@ class NodeMaintenanceController(rest.RestController):
""" """
self._set_maintenance(node_ident, True, reason=reason) self._set_maintenance(node_ident, True, reason=reason)
@wsme_pecan.wsexpose(None, types.uuid_or_name, status_code=202) @expose.expose(None, types.uuid_or_name, status_code=202)
def delete(self, node_ident): def delete(self, node_ident):
"""Remove the node from maintenance mode. """Remove the node from maintenance mode.
@ -832,7 +832,7 @@ class NodesController(rest.RestController):
except exception.InstanceNotFound: except exception.InstanceNotFound:
return [] return []
@wsme_pecan.wsexpose(NodeCollection, types.uuid, types.uuid, @expose.expose(NodeCollection, types.uuid, types.uuid,
types.boolean, types.boolean, types.uuid, int, wtypes.text, types.boolean, types.boolean, types.uuid, int, wtypes.text,
wtypes.text) wtypes.text)
def get_all(self, chassis_uuid=None, instance_uuid=None, associated=None, def get_all(self, chassis_uuid=None, instance_uuid=None, associated=None,
@ -859,7 +859,7 @@ class NodesController(rest.RestController):
associated, maintenance, marker, associated, maintenance, marker,
limit, sort_key, sort_dir) limit, sort_key, sort_dir)
@wsme_pecan.wsexpose(NodeCollection, types.uuid, types.uuid, @expose.expose(NodeCollection, types.uuid, types.uuid,
types.boolean, types.boolean, types.uuid, int, wtypes.text, types.boolean, types.boolean, types.uuid, int, wtypes.text,
wtypes.text) wtypes.text)
def detail(self, chassis_uuid=None, instance_uuid=None, associated=None, def detail(self, chassis_uuid=None, instance_uuid=None, associated=None,
@ -894,7 +894,7 @@ class NodesController(rest.RestController):
limit, sort_key, sort_dir, expand, limit, sort_key, sort_dir, expand,
resource_url) resource_url)
@wsme_pecan.wsexpose(wtypes.text, types.uuid_or_name, types.uuid) @expose.expose(wtypes.text, types.uuid_or_name, types.uuid)
def validate(self, node=None, node_uuid=None): def validate(self, node=None, node_uuid=None):
"""Validate the driver interfaces, using the node's UUID or name. """Validate the driver interfaces, using the node's UUID or name.
@ -917,7 +917,7 @@ class NodesController(rest.RestController):
return pecan.request.rpcapi.validate_driver_interfaces( return pecan.request.rpcapi.validate_driver_interfaces(
pecan.request.context, rpc_node.uuid, topic) pecan.request.context, rpc_node.uuid, topic)
@wsme_pecan.wsexpose(Node, types.uuid_or_name) @expose.expose(Node, types.uuid_or_name)
def get_one(self, node_ident): def get_one(self, node_ident):
"""Retrieve information about the given node. """Retrieve information about the given node.
@ -929,7 +929,7 @@ class NodesController(rest.RestController):
rpc_node = api_utils.get_rpc_node(node_ident) rpc_node = api_utils.get_rpc_node(node_ident)
return Node.convert_with_links(rpc_node) return Node.convert_with_links(rpc_node)
@wsme_pecan.wsexpose(Node, body=Node, status_code=201) @expose.expose(Node, body=Node, status_code=201)
def post(self, node): def post(self, node):
"""Create a new node. """Create a new node.
@ -972,7 +972,7 @@ class NodesController(rest.RestController):
return Node.convert_with_links(new_node) return Node.convert_with_links(new_node)
@wsme.validate(types.uuid, [NodePatchType]) @wsme.validate(types.uuid, [NodePatchType])
@wsme_pecan.wsexpose(Node, types.uuid_or_name, body=[NodePatchType]) @expose.expose(Node, types.uuid_or_name, body=[NodePatchType])
def patch(self, node_ident, patch): def patch(self, node_ident, patch):
"""Update an existing node. """Update an existing node.
@ -1066,7 +1066,7 @@ class NodesController(rest.RestController):
return Node.convert_with_links(new_node) return Node.convert_with_links(new_node)
@wsme_pecan.wsexpose(None, types.uuid_or_name, status_code=204) @expose.expose(None, types.uuid_or_name, status_code=204)
def delete(self, node_ident): def delete(self, node_ident):
"""Delete a node. """Delete a node.

View File

@ -20,13 +20,13 @@ import pecan
from pecan import rest from pecan import rest
import wsme import wsme
from wsme import types as wtypes from wsme import types as wtypes
import wsmeext.pecan as wsme_pecan
from ironic.api.controllers import base from ironic.api.controllers import base
from ironic.api.controllers import link from ironic.api.controllers import link
from ironic.api.controllers.v1 import collection from ironic.api.controllers.v1 import collection
from ironic.api.controllers.v1 import types from ironic.api.controllers.v1 import types
from ironic.api.controllers.v1 import utils as api_utils from ironic.api.controllers.v1 import utils as api_utils
from ironic.api import expose
from ironic.common import exception from ironic.common import exception
from ironic.common.i18n import _ from ironic.common.i18n import _
from ironic import objects from ironic import objects
@ -228,7 +228,7 @@ class PortsController(rest.RestController):
except exception.PortNotFound: except exception.PortNotFound:
return [] return []
@wsme_pecan.wsexpose(PortCollection, types.uuid_or_name, types.uuid, @expose.expose(PortCollection, types.uuid_or_name, types.uuid,
types.macaddress, types.uuid, int, wtypes.text, types.macaddress, types.uuid, int, wtypes.text,
wtypes.text) wtypes.text)
def get_all(self, node=None, node_uuid=None, address=None, marker=None, def get_all(self, node=None, node_uuid=None, address=None, marker=None,
@ -260,7 +260,7 @@ class PortsController(rest.RestController):
return self._get_ports_collection(node_uuid or node, address, marker, return self._get_ports_collection(node_uuid or node, address, marker,
limit, sort_key, sort_dir) limit, sort_key, sort_dir)
@wsme_pecan.wsexpose(PortCollection, types.uuid_or_name, types.uuid, @expose.expose(PortCollection, types.uuid_or_name, types.uuid,
types.macaddress, types.uuid, int, wtypes.text, types.macaddress, types.uuid, int, wtypes.text,
wtypes.text) wtypes.text)
def detail(self, node=None, node_uuid=None, address=None, marker=None, def detail(self, node=None, node_uuid=None, address=None, marker=None,
@ -300,7 +300,7 @@ class PortsController(rest.RestController):
limit, sort_key, sort_dir, expand, limit, sort_key, sort_dir, expand,
resource_url) resource_url)
@wsme_pecan.wsexpose(Port, types.uuid) @expose.expose(Port, types.uuid)
def get_one(self, port_uuid): def get_one(self, port_uuid):
"""Retrieve information about the given port. """Retrieve information about the given port.
@ -312,7 +312,7 @@ class PortsController(rest.RestController):
rpc_port = objects.Port.get_by_uuid(pecan.request.context, port_uuid) rpc_port = objects.Port.get_by_uuid(pecan.request.context, port_uuid)
return Port.convert_with_links(rpc_port) return Port.convert_with_links(rpc_port)
@wsme_pecan.wsexpose(Port, body=Port, status_code=201) @expose.expose(Port, body=Port, status_code=201)
def post(self, port): def post(self, port):
"""Create a new port. """Create a new port.
@ -329,7 +329,7 @@ class PortsController(rest.RestController):
return Port.convert_with_links(new_port) return Port.convert_with_links(new_port)
@wsme.validate(types.uuid, [PortPatchType]) @wsme.validate(types.uuid, [PortPatchType])
@wsme_pecan.wsexpose(Port, types.uuid, body=[PortPatchType]) @expose.expose(Port, types.uuid, body=[PortPatchType])
def patch(self, port_uuid, patch): def patch(self, port_uuid, patch):
"""Update an existing port. """Update an existing port.
@ -372,7 +372,7 @@ class PortsController(rest.RestController):
return Port.convert_with_links(new_port) return Port.convert_with_links(new_port)
@wsme_pecan.wsexpose(None, types.uuid, status_code=204) @expose.expose(None, types.uuid, status_code=204)
def delete(self, port_uuid): def delete(self, port_uuid):
"""Delete a port. """Delete a port.

24
ironic/api/expose.py Normal file
View File

@ -0,0 +1,24 @@
#
# Copyright 2015 Rackspace, 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 wsmeext.pecan as wsme_pecan
def expose(*args, **kwargs):
"""Ensure that only JSON, and not XML, is supported."""
if 'rest_content_types' not in kwargs:
kwargs['rest_content_types'] = ('json',)
return wsme_pecan.wsexpose(*args, **kwargs)

View File

@ -32,6 +32,8 @@ class AuthTokenMiddleware(auth_token.AuthProtocol):
""" """
def __init__(self, app, conf, public_api_routes=[]): def __init__(self, app, conf, public_api_routes=[]):
# TODO(mrda): Remove .xml and ensure that doesn't result in a
# 401 Authentication Required instead of 404 Not Found
route_pattern_tpl = '%s(\.json|\.xml)?$' route_pattern_tpl = '%s(\.json|\.xml)?$'
try: try:

View File

@ -88,7 +88,10 @@ class TestACL(base.FunctionalTest):
self.assertEqual(200, response.status_int) self.assertEqual(200, response.status_int)
def test_public_api_with_path_extensions(self): def test_public_api_with_path_extensions(self):
for route in ('/v1/', '/v1.json', '/v1.xml'): routes = {'/v1/': 200,
response = self.get_json(route, '/v1.json': 200,
'/v1.xml': 404}
for url in routes:
response = self.get_json(url,
path_prefix='', expect_errors=True) path_prefix='', expect_errors=True)
self.assertEqual(200, response.status_int) self.assertEqual(routes[url], response.status_int)