Remove OSAPI v1.0
Change-Id: I92302c9c2b8f98d140c4844d4522adbcb45c8dd7
This commit is contained in:
@@ -11,7 +11,6 @@ graft contrib
|
||||
graft po
|
||||
graft plugins
|
||||
graft nova/api/openstack/schemas
|
||||
include nova/api/openstack/notes.txt
|
||||
include nova/auth/*.schema
|
||||
include nova/auth/novarc.template
|
||||
include nova/auth/opendj.sh
|
||||
|
@@ -16,7 +16,6 @@ use = egg:Paste#urlmap
|
||||
/2008-02-01: ec2metadata
|
||||
/2008-09-01: ec2metadata
|
||||
/2009-04-04: ec2metadata
|
||||
/1.0: ec2metadata
|
||||
|
||||
[pipeline:ec2cloud]
|
||||
pipeline = logrequest ec2noauth cloudrequest authorizer ec2executor
|
||||
@@ -73,14 +72,8 @@ paste.app_factory = nova.api.ec2.metadatarequesthandler:MetadataRequestHandler.f
|
||||
[composite:osapi]
|
||||
use = call:nova.api.openstack.urlmap:urlmap_factory
|
||||
/: osversions
|
||||
/v1.0: openstackapi10
|
||||
/v1.1: openstackapi11
|
||||
|
||||
[pipeline:openstackapi10]
|
||||
pipeline = faultwrap noauth ratelimit osapiapp10
|
||||
# NOTE(vish): use the following pipeline for deprecated auth
|
||||
# pipeline = faultwrap auth ratelimit osapiapp10
|
||||
|
||||
[pipeline:openstackapi11]
|
||||
pipeline = faultwrap noauth ratelimit extensions osapiapp11
|
||||
# NOTE(vish): use the following pipeline for deprecated auth
|
||||
@@ -101,11 +94,8 @@ paste.filter_factory = nova.api.openstack.limits:RateLimitingMiddleware.factory
|
||||
[filter:extensions]
|
||||
paste.filter_factory = nova.api.openstack.extensions:ExtensionMiddleware.factory
|
||||
|
||||
[app:osapiapp10]
|
||||
paste.app_factory = nova.api.openstack:APIRouterV10.factory
|
||||
|
||||
[app:osapiapp11]
|
||||
paste.app_factory = nova.api.openstack:APIRouterV11.factory
|
||||
paste.app_factory = nova.api.openstack:APIRouter.factory
|
||||
|
||||
[pipeline:osversions]
|
||||
pipeline = faultwrap osversionapp
|
||||
|
@@ -24,12 +24,8 @@ import routes
|
||||
import webob.dec
|
||||
import webob.exc
|
||||
|
||||
from nova import flags
|
||||
from nova import log as logging
|
||||
from nova import wsgi as base_wsgi
|
||||
from nova.api.openstack import accounts
|
||||
from nova.api.openstack import faults
|
||||
from nova.api.openstack import backup_schedules
|
||||
from nova.api.openstack import consoles
|
||||
from nova.api.openstack import flavors
|
||||
from nova.api.openstack import images
|
||||
@@ -38,11 +34,13 @@ from nova.api.openstack import ips
|
||||
from nova.api.openstack import limits
|
||||
from nova.api.openstack import servers
|
||||
from nova.api.openstack import server_metadata
|
||||
from nova.api.openstack import shared_ip_groups
|
||||
from nova.api.openstack import users
|
||||
from nova.api.openstack import versions
|
||||
from nova.api.openstack import wsgi
|
||||
from nova.api.openstack import zones
|
||||
from nova import flags
|
||||
from nova import log as logging
|
||||
from nova import wsgi as base_wsgi
|
||||
|
||||
|
||||
LOG = logging.getLogger('nova.api.openstack')
|
||||
@@ -97,19 +95,11 @@ class APIRouter(base_wsgi.Router):
|
||||
|
||||
def __init__(self, ext_mgr=None):
|
||||
self.server_members = {}
|
||||
mapper = self._mapper()
|
||||
mapper = ProjectMapper()
|
||||
self._setup_routes(mapper)
|
||||
super(APIRouter, self).__init__(mapper)
|
||||
|
||||
def _mapper(self):
|
||||
return routes.Mapper()
|
||||
|
||||
def _setup_routes(self, mapper):
|
||||
raise NotImplementedError(_("You must implement _setup_routes."))
|
||||
|
||||
def _setup_base_routes(self, mapper, version):
|
||||
"""Routes common to all versions."""
|
||||
|
||||
server_members = self.server_members
|
||||
server_members['action'] = 'POST'
|
||||
if FLAGS.allow_admin_api:
|
||||
@@ -127,13 +117,13 @@ class APIRouter(base_wsgi.Router):
|
||||
collection={'detail': 'GET'})
|
||||
|
||||
mapper.resource("zone", "zones",
|
||||
controller=zones.create_resource(version),
|
||||
controller=zones.create_resource(),
|
||||
collection={'detail': 'GET',
|
||||
'info': 'GET',
|
||||
'select': 'POST'})
|
||||
|
||||
mapper.connect("versions", "/",
|
||||
controller=versions.create_resource(version),
|
||||
controller=versions.create_resource(),
|
||||
action='show')
|
||||
|
||||
mapper.resource("console", "consoles",
|
||||
@@ -142,53 +132,25 @@ class APIRouter(base_wsgi.Router):
|
||||
collection_name='servers'))
|
||||
|
||||
mapper.resource("server", "servers",
|
||||
controller=servers.create_resource(version),
|
||||
controller=servers.create_resource(),
|
||||
collection={'detail': 'GET'},
|
||||
member=self.server_members)
|
||||
|
||||
mapper.resource("ip", "ips", controller=ips.create_resource(version),
|
||||
mapper.resource("ip", "ips", controller=ips.create_resource(),
|
||||
parent_resource=dict(member_name='server',
|
||||
collection_name='servers'))
|
||||
|
||||
mapper.resource("image", "images",
|
||||
controller=images.create_resource(version),
|
||||
controller=images.create_resource(),
|
||||
collection={'detail': 'GET'})
|
||||
|
||||
mapper.resource("limit", "limits",
|
||||
controller=limits.create_resource(version))
|
||||
controller=limits.create_resource())
|
||||
|
||||
mapper.resource("flavor", "flavors",
|
||||
controller=flavors.create_resource(version),
|
||||
controller=flavors.create_resource(),
|
||||
collection={'detail': 'GET'})
|
||||
|
||||
super(APIRouter, self).__init__(mapper)
|
||||
|
||||
|
||||
class APIRouterV10(APIRouter):
|
||||
"""Define routes specific to OpenStack API V1.0."""
|
||||
|
||||
def _setup_routes(self, mapper):
|
||||
self._setup_base_routes(mapper, '1.0')
|
||||
|
||||
mapper.resource("shared_ip_group", "shared_ip_groups",
|
||||
collection={'detail': 'GET'},
|
||||
controller=shared_ip_groups.create_resource())
|
||||
|
||||
mapper.resource("backup_schedule", "backup_schedule",
|
||||
controller=backup_schedules.create_resource(),
|
||||
parent_resource=dict(member_name='server',
|
||||
collection_name='servers'))
|
||||
|
||||
|
||||
class APIRouterV11(APIRouter):
|
||||
"""Define routes specific to OpenStack API V1.1."""
|
||||
|
||||
def _mapper(self):
|
||||
return ProjectMapper()
|
||||
|
||||
def _setup_routes(self, mapper):
|
||||
self._setup_base_routes(mapper, '1.1')
|
||||
|
||||
image_metadata_controller = image_metadata.create_resource()
|
||||
|
||||
mapper.resource("image_meta", "metadata",
|
||||
|
@@ -1,67 +0,0 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2010 OpenStack LLC.
|
||||
# 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 time
|
||||
|
||||
from webob import exc
|
||||
|
||||
from nova.api.openstack import wsgi
|
||||
|
||||
|
||||
def _translate_keys(inst):
|
||||
""" Coerces the backup schedule into proper dictionary format """
|
||||
return dict(backupSchedule=inst)
|
||||
|
||||
|
||||
class Controller(object):
|
||||
""" The backup schedule API controller for the Openstack API """
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def index(self, req, server_id, **kwargs):
|
||||
""" Returns the list of backup schedules for a given instance """
|
||||
raise exc.HTTPNotImplemented()
|
||||
|
||||
def show(self, req, server_id, id, **kwargs):
|
||||
""" Returns a single backup schedule for a given instance """
|
||||
raise exc.HTTPNotImplemented()
|
||||
|
||||
def create(self, req, server_id, **kwargs):
|
||||
""" No actual update method required, since the existing API allows
|
||||
both create and update through a POST """
|
||||
raise exc.HTTPNotImplemented()
|
||||
|
||||
def delete(self, req, server_id, id, **kwargs):
|
||||
""" Deletes an existing backup schedule """
|
||||
raise exc.HTTPNotImplemented()
|
||||
|
||||
|
||||
def create_resource():
|
||||
metadata = {
|
||||
'attributes': {
|
||||
'backupSchedule': [],
|
||||
},
|
||||
}
|
||||
|
||||
body_serializers = {
|
||||
'application/xml': wsgi.XMLDictSerializer(xmlns=wsgi.XMLNS_V10,
|
||||
metadata=metadata),
|
||||
}
|
||||
|
||||
serializer = wsgi.ResponseSerializer(body_serializers)
|
||||
return wsgi.Resource(Controller(), serializer=serializer)
|
@@ -37,7 +37,6 @@ LOG = logging.getLogger('nova.api.openstack.common')
|
||||
FLAGS = flags.FLAGS
|
||||
|
||||
|
||||
XML_NS_V10 = 'http://docs.rackspacecloud.com/servers/api/v1.0'
|
||||
XML_NS_V11 = 'http://docs.openstack.org/compute/api/v1.1'
|
||||
|
||||
|
||||
|
@@ -20,7 +20,7 @@ from nova.api.openstack import servers
|
||||
from nova.api.openstack import wsgi
|
||||
|
||||
|
||||
class CreateServerController(servers.ControllerV11):
|
||||
class CreateServerController(servers.Controller):
|
||||
def _build_view(self, req, instance, is_detail=False):
|
||||
server = super(CreateServerController, self)._build_view(req,
|
||||
instance,
|
||||
@@ -65,7 +65,7 @@ class Createserverext(extensions.ExtensionDescriptor):
|
||||
}
|
||||
|
||||
body_deserializers = {
|
||||
'application/xml': servers.ServerXMLDeserializerV11(),
|
||||
'application/xml': servers.ServerXMLDeserializer(),
|
||||
}
|
||||
|
||||
serializer = wsgi.ResponseSerializer(body_serializers,
|
||||
|
@@ -489,7 +489,7 @@ class VsaVPoolController(object):
|
||||
return faults.Fault(exc.HTTPBadRequest())
|
||||
|
||||
|
||||
class VsaVCController(servers.ControllerV11):
|
||||
class VsaVCController(servers.Controller):
|
||||
"""The VSA Virtual Controller API controller for the OpenStack API."""
|
||||
|
||||
def __init__(self):
|
||||
|
@@ -331,7 +331,7 @@ class VolumeAttachmentController(object):
|
||||
return {'volumeAttachments': res}
|
||||
|
||||
|
||||
class BootFromVolumeController(servers.ControllerV11):
|
||||
class BootFromVolumeController(servers.Controller):
|
||||
"""The boot from volume API controller for the Openstack API."""
|
||||
|
||||
def _get_block_device_mapping(self, data):
|
||||
|
@@ -60,13 +60,9 @@ class Fault(webob.exc.HTTPException):
|
||||
# 'code' is an attribute on the fault tag itself
|
||||
metadata = {'attributes': {fault_name: 'code'}}
|
||||
|
||||
xml_serializer = wsgi.XMLDictSerializer(metadata, wsgi.XMLNS_V11)
|
||||
|
||||
content_type = req.best_match_content_type()
|
||||
|
||||
xml_serializer = {
|
||||
'1.0': wsgi.XMLDictSerializer(metadata, wsgi.XMLNS_V10),
|
||||
'1.1': wsgi.XMLDictSerializer(metadata, wsgi.XMLNS_V11),
|
||||
}[common.get_version_from_href(req.url)]
|
||||
|
||||
serializer = {
|
||||
'application/xml': xml_serializer,
|
||||
'application/json': wsgi.JSONDictSerializer(),
|
||||
@@ -105,11 +101,7 @@ class OverLimitFault(webob.exc.HTTPException):
|
||||
content_type = request.best_match_content_type()
|
||||
metadata = {"attributes": {"overLimitFault": "code"}}
|
||||
|
||||
xml_serializer = {
|
||||
'1.0': wsgi.XMLDictSerializer(metadata, wsgi.XMLNS_V10),
|
||||
'1.1': wsgi.XMLDictSerializer(metadata, wsgi.XMLNS_V11),
|
||||
}[common.get_version_from_href(request.url)]
|
||||
|
||||
xml_serializer = wsgi.XMLDictSerializer(metadata, wsgi.XMLNS_V11)
|
||||
serializer = {
|
||||
'application/xml': xml_serializer,
|
||||
'application/json': wsgi.JSONDictSerializer(),
|
||||
|
@@ -75,19 +75,10 @@ class Controller(object):
|
||||
values = builder.build(flavor, is_detail=True)
|
||||
return dict(flavor=values)
|
||||
|
||||
|
||||
class ControllerV10(Controller):
|
||||
|
||||
def _get_view_builder(self, req):
|
||||
return views.flavors.ViewBuilder()
|
||||
|
||||
|
||||
class ControllerV11(Controller):
|
||||
|
||||
def _get_view_builder(self, req):
|
||||
base_url = req.application_url
|
||||
project_id = getattr(req.environ['nova.context'], 'project_id', '')
|
||||
return views.flavors.ViewBuilderV11(base_url, project_id)
|
||||
return views.flavors.ViewBuilder(base_url, project_id)
|
||||
|
||||
|
||||
class FlavorXMLSerializer(wsgi.XMLDictSerializer):
|
||||
@@ -136,21 +127,7 @@ class FlavorXMLSerializer(wsgi.XMLDictSerializer):
|
||||
return self._to_xml(flavors)
|
||||
|
||||
|
||||
def create_resource(version='1.0'):
|
||||
controller = {
|
||||
'1.0': ControllerV10,
|
||||
'1.1': ControllerV11,
|
||||
}[version]()
|
||||
|
||||
xml_serializer = {
|
||||
'1.0': wsgi.XMLDictSerializer(xmlns=wsgi.XMLNS_V10),
|
||||
'1.1': FlavorXMLSerializer(),
|
||||
}[version]
|
||||
|
||||
body_serializers = {
|
||||
'application/xml': xml_serializer,
|
||||
}
|
||||
|
||||
def create_resource():
|
||||
body_serializers = {'application/xml': FlavorXMLSerializer()}
|
||||
serializer = wsgi.ResponseSerializer(body_serializers)
|
||||
|
||||
return wsgi.Resource(controller, serializer=serializer)
|
||||
return wsgi.Resource(Controller(), serializer=serializer)
|
||||
|
@@ -104,83 +104,11 @@ class Controller(object):
|
||||
raise webob.exc.HTTPNotFound(explanation=explanation)
|
||||
return webob.exc.HTTPNoContent()
|
||||
|
||||
def get_builder(self, request):
|
||||
"""Indicates that you must use a Controller subclass."""
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class ControllerV10(Controller):
|
||||
"""Version 1.0 specific controller logic."""
|
||||
|
||||
@common.check_snapshots_enabled
|
||||
def create(self, req, body):
|
||||
"""Snapshot a server instance and save the image."""
|
||||
try:
|
||||
image = body["image"]
|
||||
except (KeyError, TypeError):
|
||||
msg = _("Invalid image entity")
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
try:
|
||||
image_name = image["name"]
|
||||
instance_id = image["serverId"]
|
||||
except KeyError as missing_key:
|
||||
msg = _("Image entity requires %s") % missing_key
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
context = req.environ["nova.context"]
|
||||
props = {'instance_id': instance_id}
|
||||
|
||||
try:
|
||||
image = self._compute_service.snapshot(context,
|
||||
instance_id,
|
||||
image_name,
|
||||
extra_properties=props)
|
||||
except exception.InstanceBusy:
|
||||
msg = _("Server is currently creating an image. Please wait.")
|
||||
raise webob.exc.HTTPConflict(explanation=msg)
|
||||
|
||||
return dict(image=self.get_builder(req).build(image, detail=True))
|
||||
|
||||
def get_builder(self, request):
|
||||
"""Property to get the ViewBuilder class we need to use."""
|
||||
base_url = request.application_url
|
||||
return images_view.ViewBuilderV10(base_url)
|
||||
|
||||
def index(self, req):
|
||||
"""Return an index listing of images available to the request.
|
||||
|
||||
:param req: `wsgi.Request` object
|
||||
|
||||
"""
|
||||
context = req.environ['nova.context']
|
||||
filters = self._get_filters(req)
|
||||
images = self._image_service.index(context, filters=filters)
|
||||
images = common.limited(images, req)
|
||||
return self.get_builder(req).build_list(images)
|
||||
|
||||
def detail(self, req):
|
||||
"""Return a detailed index listing of images available to the request.
|
||||
|
||||
:param req: `wsgi.Request` object.
|
||||
|
||||
"""
|
||||
context = req.environ['nova.context']
|
||||
filters = self._get_filters(req)
|
||||
images = self._image_service.detail(context, filters=filters)
|
||||
images = common.limited(images, req)
|
||||
builder = self.get_builder(req).build
|
||||
return dict(images=[builder(image, detail=True) for image in images])
|
||||
|
||||
|
||||
class ControllerV11(Controller):
|
||||
"""Version 1.1 specific controller logic."""
|
||||
|
||||
def get_builder(self, req):
|
||||
"""Property to get the ViewBuilder class we need to use."""
|
||||
base_url = req.application_url
|
||||
project_id = getattr(req.environ['nova.context'], 'project_id', '')
|
||||
return images_view.ViewBuilderV11(base_url, project_id)
|
||||
return images_view.ViewBuilder(base_url, project_id)
|
||||
|
||||
def index(self, req):
|
||||
"""Return an index listing of images available to the request.
|
||||
@@ -298,29 +226,7 @@ class ImageXMLSerializer(wsgi.XMLDictSerializer):
|
||||
return self._to_xml(image)
|
||||
|
||||
|
||||
def create_resource(version='1.0'):
|
||||
controller = {
|
||||
'1.0': ControllerV10,
|
||||
'1.1': ControllerV11,
|
||||
}[version]()
|
||||
|
||||
metadata = {
|
||||
"attributes": {
|
||||
"image": ["id", "name", "updated", "created", "status",
|
||||
"serverId", "progress", "serverRef"],
|
||||
"link": ["rel", "type", "href"],
|
||||
},
|
||||
}
|
||||
|
||||
xml_serializer = {
|
||||
'1.0': wsgi.XMLDictSerializer(metadata, wsgi.XMLNS_V10),
|
||||
'1.1': ImageXMLSerializer(),
|
||||
}[version]
|
||||
|
||||
body_serializers = {
|
||||
'application/xml': xml_serializer,
|
||||
}
|
||||
|
||||
def create_resource():
|
||||
body_serializers = {'application/xml': ImageXMLSerializer()}
|
||||
serializer = wsgi.ResponseSerializer(body_serializers)
|
||||
|
||||
return wsgi.Resource(controller, serializer=serializer)
|
||||
return wsgi.Resource(Controller(), serializer=serializer)
|
||||
|
@@ -52,37 +52,6 @@ class Controller(object):
|
||||
def delete(self, req, server_id, id):
|
||||
raise exc.HTTPNotImplemented()
|
||||
|
||||
|
||||
class ControllerV10(Controller):
|
||||
|
||||
def index(self, req, server_id):
|
||||
context = req.environ['nova.context']
|
||||
instance = self._get_instance(context, server_id)
|
||||
networks = common.get_networks_for_instance(context, instance)
|
||||
builder = self._get_view_builder(req)
|
||||
return {'addresses': builder.build(networks)}
|
||||
|
||||
def show(self, req, server_id, id):
|
||||
context = req.environ['nova.context']
|
||||
instance = self._get_instance(context, server_id)
|
||||
networks = common.get_networks_for_instance(context, instance)
|
||||
builder = self._get_view_builder(req)
|
||||
if id == 'private':
|
||||
view = builder.build_private_parts(networks)
|
||||
elif id == 'public':
|
||||
view = builder.build_public_parts(networks)
|
||||
else:
|
||||
msg = _("Only private and public networks available")
|
||||
raise exc.HTTPNotFound(explanation=msg)
|
||||
|
||||
return {id: view}
|
||||
|
||||
def _get_view_builder(self, req):
|
||||
return views_addresses.ViewBuilderV10()
|
||||
|
||||
|
||||
class ControllerV11(Controller):
|
||||
|
||||
def index(self, req, server_id):
|
||||
context = req.environ['nova.context']
|
||||
instance = self._get_instance(context, server_id)
|
||||
@@ -102,7 +71,7 @@ class ControllerV11(Controller):
|
||||
return network
|
||||
|
||||
def _get_view_builder(self, req):
|
||||
return views_addresses.ViewBuilderV11()
|
||||
return views_addresses.ViewBuilder()
|
||||
|
||||
|
||||
class IPXMLSerializer(wsgi.XMLDictSerializer):
|
||||
@@ -138,24 +107,7 @@ class IPXMLSerializer(wsgi.XMLDictSerializer):
|
||||
return self._to_xml(addresses)
|
||||
|
||||
|
||||
def create_resource(version):
|
||||
controller = {
|
||||
'1.0': ControllerV10,
|
||||
'1.1': ControllerV11,
|
||||
}[version]()
|
||||
|
||||
metadata = {
|
||||
'list_collections': {
|
||||
'public': {'item_name': 'ip', 'item_key': 'addr'},
|
||||
'private': {'item_name': 'ip', 'item_key': 'addr'},
|
||||
},
|
||||
}
|
||||
|
||||
xml_serializer = {
|
||||
'1.0': wsgi.XMLDictSerializer(metadata=metadata, xmlns=wsgi.XMLNS_V11),
|
||||
'1.1': IPXMLSerializer(),
|
||||
}[version]
|
||||
|
||||
serializer = wsgi.ResponseSerializer({'application/xml': xml_serializer})
|
||||
|
||||
return wsgi.Resource(controller, serializer=serializer)
|
||||
def create_resource():
|
||||
body_serializers = {'application/xml': IPXMLSerializer()}
|
||||
serializer = wsgi.ResponseSerializer(body_serializers)
|
||||
return wsgi.Resource(Controller(), serializer=serializer)
|
||||
|
@@ -65,17 +65,7 @@ class LimitsController(object):
|
||||
return builder.build(rate_limits, abs_limits)
|
||||
|
||||
def _get_view_builder(self, req):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class LimitsControllerV10(LimitsController):
|
||||
def _get_view_builder(self, req):
|
||||
return limits_views.ViewBuilderV10()
|
||||
|
||||
|
||||
class LimitsControllerV11(LimitsController):
|
||||
def _get_view_builder(self, req):
|
||||
return limits_views.ViewBuilderV11()
|
||||
return limits_views.ViewBuilder()
|
||||
|
||||
|
||||
class LimitsXMLSerializer(wsgi.XMLDictSerializer):
|
||||
@@ -127,39 +117,10 @@ class LimitsXMLSerializer(wsgi.XMLDictSerializer):
|
||||
return self._to_xml(limits)
|
||||
|
||||
|
||||
def create_resource(version='1.0'):
|
||||
controller = {
|
||||
'1.0': LimitsControllerV10,
|
||||
'1.1': LimitsControllerV11,
|
||||
}[version]()
|
||||
|
||||
xmlns = {
|
||||
'1.0': wsgi.XMLNS_V10,
|
||||
'1.1': wsgi.XMLNS_V11,
|
||||
}[version]
|
||||
|
||||
metadata = {
|
||||
"attributes": {
|
||||
"limit": ["verb", "URI", "uri", "regex", "value", "unit",
|
||||
"resetTime", "next-available", "remaining", "name"],
|
||||
},
|
||||
"plurals": {
|
||||
"rate": "limit",
|
||||
},
|
||||
}
|
||||
|
||||
xml_serializer = {
|
||||
'1.0': wsgi.XMLDictSerializer(xmlns=xmlns, metadata=metadata),
|
||||
'1.1': LimitsXMLSerializer(),
|
||||
}[version]
|
||||
|
||||
body_serializers = {
|
||||
'application/xml': xml_serializer,
|
||||
}
|
||||
|
||||
def create_resource():
|
||||
body_serializers = {'application/xml': LimitsXMLSerializer()}
|
||||
serializer = wsgi.ResponseSerializer(body_serializers)
|
||||
|
||||
return wsgi.Resource(controller, serializer=serializer)
|
||||
return wsgi.Resource(LimitsController(), serializer=serializer)
|
||||
|
||||
|
||||
class Limit(object):
|
||||
|
@@ -1,20 +0,0 @@
|
||||
We will need:
|
||||
|
||||
ImageService
|
||||
a service that can do crud on image information. not user-specific. opaque
|
||||
image ids.
|
||||
|
||||
GlanceImageService(ImageService):
|
||||
image ids are URIs.
|
||||
|
||||
OpenstackAPITranslationStore:
|
||||
translates RS server/images/flavor/etc ids into formats required
|
||||
by a given ImageService strategy.
|
||||
|
||||
api.openstack.images.Controller:
|
||||
uses an ImageService strategy behind the scenes to do its fetching; it just
|
||||
converts int image id into a strategy-specific image id.
|
||||
|
||||
who maintains the mapping from user to [images he owns]? nobody, because
|
||||
we have no way of enforcing access to his images, without kryptex which
|
||||
won't be in Austin.
|
@@ -85,18 +85,6 @@ class Controller(object):
|
||||
return exc.HTTPNotFound()
|
||||
return servers
|
||||
|
||||
def _build_view(self, req, instance, is_detail=False):
|
||||
raise NotImplementedError()
|
||||
|
||||
def _build_list(self, req, instances, is_detail=False):
|
||||
raise NotImplementedError()
|
||||
|
||||
def _limit_items(self, items, req):
|
||||
raise NotImplementedError()
|
||||
|
||||
def _action_rebuild(self, info, request, instance_id):
|
||||
raise NotImplementedError()
|
||||
|
||||
def _get_block_device_mapping(self, data):
|
||||
"""Get block_device_mapping from 'server' dictionary.
|
||||
Overidden by volumes controller.
|
||||
@@ -346,10 +334,6 @@ class Controller(object):
|
||||
except exception.NotFound:
|
||||
raise exc.HTTPNotFound()
|
||||
|
||||
def _get_key_name(self, req, body):
|
||||
""" Get default keypair if not set """
|
||||
raise NotImplementedError()
|
||||
|
||||
def create(self, req, body):
|
||||
""" Creates a new server for a given user """
|
||||
|
||||
@@ -556,10 +540,8 @@ class Controller(object):
|
||||
except exception.NotFound:
|
||||
raise exc.HTTPNotFound()
|
||||
|
||||
return self._update(ctxt, req, id, body)
|
||||
|
||||
def _update(self, context, req, id, inst_dict):
|
||||
return exc.HTTPNotImplemented()
|
||||
instance = self.compute_api.routing_get(ctxt, id)
|
||||
return self._build_view(req, instance, is_detail=True)
|
||||
|
||||
@exception.novaclient_converter
|
||||
@scheduler_api.redirect_handler
|
||||
@@ -654,13 +636,6 @@ class Controller(object):
|
||||
resp.headers['Location'] = image_ref
|
||||
return resp
|
||||
|
||||
@common.check_snapshots_enabled
|
||||
def _action_create_image(self, input_dict, req, id):
|
||||
return exc.HTTPNotImplemented()
|
||||
|
||||
def _action_change_password(self, input_dict, req, id):
|
||||
return exc.HTTPNotImplemented()
|
||||
|
||||
def _action_confirm_resize(self, input_dict, req, id):
|
||||
try:
|
||||
self.compute_api.confirm_resize(req.environ['nova.context'], id)
|
||||
@@ -683,9 +658,6 @@ class Controller(object):
|
||||
raise exc.HTTPBadRequest()
|
||||
return webob.Response(status_int=202)
|
||||
|
||||
def _action_resize(self, input_dict, req, id):
|
||||
return exc.HTTPNotImplemented()
|
||||
|
||||
def _action_reboot(self, input_dict, req, id):
|
||||
if 'reboot' in input_dict and 'type' in input_dict['reboot']:
|
||||
valid_reboot_types = ['HARD', 'SOFT']
|
||||
@@ -783,96 +755,6 @@ class Controller(object):
|
||||
|
||||
return webob.Response(status_int=202)
|
||||
|
||||
|
||||
class ControllerV10(Controller):
|
||||
"""v1.0 OpenStack API controller"""
|
||||
|
||||
@exception.novaclient_converter
|
||||
@scheduler_api.redirect_handler
|
||||
def delete(self, req, id):
|
||||
""" Destroys a server """
|
||||
try:
|
||||
self._delete(req.environ['nova.context'], id)
|
||||
except exception.NotFound:
|
||||
raise exc.HTTPNotFound()
|
||||
return webob.Response(status_int=202)
|
||||
|
||||
def _get_key_name(self, req, body):
|
||||
context = req.environ["nova.context"]
|
||||
keypairs = db.key_pair_get_all_by_user(context,
|
||||
context.user_id)
|
||||
if keypairs:
|
||||
return keypairs[0]['name']
|
||||
|
||||
def _image_ref_from_req_data(self, data):
|
||||
return data['server']['imageId']
|
||||
|
||||
def _flavor_id_from_req_data(self, data):
|
||||
return data['server']['flavorId']
|
||||
|
||||
def _build_view(self, req, instance, is_detail=False):
|
||||
context = req.environ['nova.context']
|
||||
addresses = views_addresses.ViewBuilderV10()
|
||||
builder = views_servers.ViewBuilderV10(context, addresses)
|
||||
return builder.build(instance, is_detail=is_detail)
|
||||
|
||||
def _build_list(self, req, instances, is_detail=False):
|
||||
context = req.environ['nova.context']
|
||||
addresses = views_addresses.ViewBuilderV10()
|
||||
builder = views_servers.ViewBuilderV10(context, addresses)
|
||||
return builder.build_list(instances, is_detail=is_detail)
|
||||
|
||||
def _limit_items(self, items, req):
|
||||
return common.limited(items, req)
|
||||
|
||||
def _update(self, context, req, id, inst_dict):
|
||||
if 'adminPass' in inst_dict['server']:
|
||||
self.compute_api.set_admin_password(context, id,
|
||||
inst_dict['server']['adminPass'])
|
||||
return exc.HTTPNoContent()
|
||||
|
||||
def _action_resize(self, input_dict, req, id):
|
||||
""" Resizes a given instance to the flavor size requested """
|
||||
try:
|
||||
flavor_id = input_dict["resize"]["flavorId"]
|
||||
except (KeyError, TypeError):
|
||||
msg = _("Resize requests require 'flavorId' attribute.")
|
||||
raise exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
return self.resize(req, id, flavor_id)
|
||||
|
||||
def _action_rebuild(self, info, request, instance_id):
|
||||
context = request.environ['nova.context']
|
||||
|
||||
try:
|
||||
image_id = info["rebuild"]["imageId"]
|
||||
except (KeyError, TypeError):
|
||||
msg = _("Could not parse imageId from request.")
|
||||
LOG.debug(msg)
|
||||
raise exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
password = utils.generate_password(FLAGS.password_length)
|
||||
|
||||
try:
|
||||
self.compute_api.rebuild(context, instance_id, image_id, password)
|
||||
except exception.RebuildRequiresActiveInstance:
|
||||
msg = _("Instance %s must be active to rebuild.") % instance_id
|
||||
raise exc.HTTPConflict(explanation=msg)
|
||||
|
||||
return webob.Response(status_int=202)
|
||||
|
||||
def _get_server_admin_password(self, server):
|
||||
""" Determine the admin password for a server on creation """
|
||||
return self._get_server_admin_password_old_style(server)
|
||||
|
||||
def _get_server_search_options(self):
|
||||
"""Return server search options allowed by non-admin"""
|
||||
return 'reservation_id', 'fixed_ip', 'name', 'local_zone_only'
|
||||
|
||||
|
||||
class ControllerV11(Controller):
|
||||
"""v1.1 OpenStack API controller"""
|
||||
|
||||
@exception.novaclient_converter
|
||||
@scheduler_api.redirect_handler
|
||||
def delete(self, req, id):
|
||||
@@ -910,10 +792,10 @@ class ControllerV11(Controller):
|
||||
context = req.environ['nova.context']
|
||||
project_id = getattr(context, 'project_id', '')
|
||||
base_url = req.application_url
|
||||
flavor_builder = views_flavors.ViewBuilderV11(base_url, project_id)
|
||||
image_builder = views_images.ViewBuilderV11(base_url, project_id)
|
||||
addresses_builder = views_addresses.ViewBuilderV11()
|
||||
builder = views_servers.ViewBuilderV11(context, addresses_builder,
|
||||
flavor_builder = views_flavors.ViewBuilder(base_url, project_id)
|
||||
image_builder = views_images.ViewBuilder(base_url, project_id)
|
||||
addresses_builder = views_addresses.ViewBuilder()
|
||||
builder = views_servers.ViewBuilder(context, addresses_builder,
|
||||
flavor_builder, image_builder, base_url, project_id)
|
||||
return builder.build(instance, is_detail=is_detail)
|
||||
|
||||
@@ -927,10 +809,10 @@ class ControllerV11(Controller):
|
||||
context = req.environ['nova.context']
|
||||
project_id = getattr(context, 'project_id', '')
|
||||
base_url = req.application_url
|
||||
flavor_builder = views_flavors.ViewBuilderV11(base_url, project_id)
|
||||
image_builder = views_images.ViewBuilderV11(base_url, project_id)
|
||||
addresses_builder = views_addresses.ViewBuilderV11()
|
||||
builder = views_servers.ViewBuilderV11(context, addresses_builder,
|
||||
flavor_builder = views_flavors.ViewBuilder(base_url, project_id)
|
||||
image_builder = views_images.ViewBuilder(base_url, project_id)
|
||||
addresses_builder = views_addresses.ViewBuilder()
|
||||
builder = views_servers.ViewBuilder(context, addresses_builder,
|
||||
flavor_builder, image_builder, base_url, project_id)
|
||||
return builder.build_list(instances, is_detail=is_detail, **params)
|
||||
|
||||
@@ -977,10 +859,6 @@ class ControllerV11(Controller):
|
||||
LOG.info(msg)
|
||||
raise exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
def _update(self, context, req, id, inst_dict):
|
||||
instance = self.compute_api.routing_get(context, id)
|
||||
return self._build_view(req, instance, is_detail=True)
|
||||
|
||||
def _action_resize(self, input_dict, req, id):
|
||||
""" Resizes a given instance to the flavor size requested """
|
||||
try:
|
||||
@@ -1235,55 +1113,7 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer):
|
||||
return self._to_xml(server)
|
||||
|
||||
|
||||
class ServerXMLDeserializer(wsgi.XMLDeserializer):
|
||||
"""
|
||||
Deserializer to handle xml-formatted server create requests.
|
||||
|
||||
Handles standard server attributes as well as optional metadata
|
||||
and personality attributes
|
||||
"""
|
||||
|
||||
metadata_deserializer = common.MetadataXMLDeserializer()
|
||||
|
||||
def create(self, string):
|
||||
"""Deserialize an xml-formatted server create request"""
|
||||
dom = minidom.parseString(string)
|
||||
server = self._extract_server(dom)
|
||||
return {'body': {'server': server}}
|
||||
|
||||
def _extract_server(self, node):
|
||||
"""Marshal the server attribute of a parsed request"""
|
||||
server = {}
|
||||
server_node = self.find_first_child_named(node, 'server')
|
||||
|
||||
attributes = ["name", "imageId", "flavorId", "adminPass"]
|
||||
for attr in attributes:
|
||||
if server_node.getAttribute(attr):
|
||||
server[attr] = server_node.getAttribute(attr)
|
||||
|
||||
metadata_node = self.find_first_child_named(server_node, "metadata")
|
||||
server["metadata"] = self.metadata_deserializer.extract_metadata(
|
||||
metadata_node)
|
||||
|
||||
server["personality"] = self._extract_personality(server_node)
|
||||
|
||||
return server
|
||||
|
||||
def _extract_personality(self, server_node):
|
||||
"""Marshal the personality attribute of a parsed request"""
|
||||
node = self.find_first_child_named(server_node, "personality")
|
||||
personality = []
|
||||
if node is not None:
|
||||
for file_node in self.find_children_named(node, "file"):
|
||||
item = {}
|
||||
if file_node.hasAttribute("path"):
|
||||
item["path"] = file_node.getAttribute("path")
|
||||
item["contents"] = self.extract_text(file_node)
|
||||
personality.append(item)
|
||||
return personality
|
||||
|
||||
|
||||
class ServerXMLDeserializerV11(wsgi.MetadataXMLDeserializer):
|
||||
class ServerXMLDeserializer(wsgi.MetadataXMLDeserializer):
|
||||
"""
|
||||
Deserializer to handle xml-formatted server create requests.
|
||||
|
||||
@@ -1456,57 +1286,13 @@ class ServerXMLDeserializerV11(wsgi.MetadataXMLDeserializer):
|
||||
return None
|
||||
|
||||
|
||||
def create_resource(version='1.0'):
|
||||
controller = {
|
||||
'1.0': ControllerV10,
|
||||
'1.1': ControllerV11,
|
||||
}[version]()
|
||||
|
||||
metadata = {
|
||||
"attributes": {
|
||||
"server": ["id", "imageId", "name", "flavorId", "hostId",
|
||||
"status", "progress", "adminPass", "flavorRef",
|
||||
"imageRef", "userId", "tenantId"],
|
||||
"link": ["rel", "type", "href"],
|
||||
},
|
||||
"dict_collections": {
|
||||
"metadata": {"item_name": "meta", "item_key": "key"},
|
||||
},
|
||||
"list_collections": {
|
||||
"public": {"item_name": "ip", "item_key": "addr"},
|
||||
"private": {"item_name": "ip", "item_key": "addr"},
|
||||
},
|
||||
}
|
||||
|
||||
xmlns = {
|
||||
'1.0': wsgi.XMLNS_V10,
|
||||
'1.1': wsgi.XMLNS_V11,
|
||||
}[version]
|
||||
|
||||
def create_resource():
|
||||
headers_serializer = HeadersSerializer()
|
||||
|
||||
xml_serializer = {
|
||||
'1.0': wsgi.XMLDictSerializer(metadata, wsgi.XMLNS_V10),
|
||||
'1.1': ServerXMLSerializer(),
|
||||
}[version]
|
||||
|
||||
body_serializers = {
|
||||
'application/xml': xml_serializer,
|
||||
}
|
||||
|
||||
xml_deserializer = {
|
||||
'1.0': ServerXMLDeserializer(),
|
||||
'1.1': ServerXMLDeserializerV11(),
|
||||
}[version]
|
||||
|
||||
body_deserializers = {
|
||||
'application/xml': xml_deserializer,
|
||||
}
|
||||
|
||||
body_serializers = {'application/xml': ServerXMLSerializer()}
|
||||
serializer = wsgi.ResponseSerializer(body_serializers, headers_serializer)
|
||||
body_deserializers = {'application/xml': ServerXMLDeserializer()}
|
||||
deserializer = wsgi.RequestDeserializer(body_deserializers)
|
||||
|
||||
return wsgi.Resource(controller, deserializer, serializer)
|
||||
return wsgi.Resource(Controller(), deserializer, serializer)
|
||||
|
||||
|
||||
def remove_invalid_options(context, search_options, allowed_search_options):
|
||||
|
@@ -1,52 +0,0 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2010 OpenStack LLC.
|
||||
# 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.
|
||||
|
||||
from webob import exc
|
||||
|
||||
from nova.api.openstack import wsgi
|
||||
|
||||
|
||||
class Controller(object):
|
||||
""" The Shared IP Groups Controller for the Openstack API """
|
||||
|
||||
def index(self, req, **kwargs):
|
||||
""" Returns a list of Shared IP Groups for the user """
|
||||
raise exc.HTTPNotImplemented()
|
||||
|
||||
def show(self, req, id, **kwargs):
|
||||
""" Shows in-depth information on a specific Shared IP Group """
|
||||
raise exc.HTTPNotImplemented()
|
||||
|
||||
def update(self, req, id, **kwargs):
|
||||
""" You can't update a Shared IP Group """
|
||||
raise exc.HTTPNotImplemented()
|
||||
|
||||
def delete(self, req, id, **kwargs):
|
||||
""" Deletes a Shared IP Group """
|
||||
raise exc.HTTPNotImplemented()
|
||||
|
||||
def detail(self, req, **kwargs):
|
||||
""" Returns a complete list of Shared IP Groups """
|
||||
raise exc.HTTPNotImplemented()
|
||||
|
||||
def create(self, req, **kwargs):
|
||||
""" Creates a new Shared IP group """
|
||||
raise exc.HTTPNotImplemented()
|
||||
|
||||
|
||||
def create_resource():
|
||||
return wsgi.Resource(Controller())
|
@@ -26,35 +26,6 @@ from nova.api.openstack import xmlutil
|
||||
|
||||
|
||||
VERSIONS = {
|
||||
"v1.0": {
|
||||
"id": "v1.0",
|
||||
"status": "DEPRECATED",
|
||||
"updated": "2011-01-21T11:33:21Z",
|
||||
"links": [
|
||||
{
|
||||
"rel": "describedby",
|
||||
"type": "application/pdf",
|
||||
"href": "http://docs.rackspacecloud.com/"
|
||||
"servers/api/v1.0/cs-devguide-20110125.pdf",
|
||||
},
|
||||
{
|
||||
"rel": "describedby",
|
||||
"type": "application/vnd.sun.wadl+xml",
|
||||
"href": "http://docs.rackspacecloud.com/"
|
||||
"servers/api/v1.0/application.wadl",
|
||||
},
|
||||
],
|
||||
"media-types": [
|
||||
{
|
||||
"base": "application/xml",
|
||||
"type": "application/vnd.openstack.compute+xml;version=1.0",
|
||||
},
|
||||
{
|
||||
"base": "application/json",
|
||||
"type": "application/vnd.openstack.compute+json;version=1.0",
|
||||
}
|
||||
],
|
||||
},
|
||||
"v1.1": {
|
||||
"id": "v1.1",
|
||||
"status": "CURRENT",
|
||||
@@ -122,12 +93,6 @@ class Versions(wsgi.Resource):
|
||||
return builder.build_choices(VERSIONS, request)
|
||||
|
||||
|
||||
class VersionV10(object):
|
||||
def show(self, req):
|
||||
builder = nova.api.openstack.views.versions.get_view_builder(req)
|
||||
return builder.build_version(VERSIONS['v1.0'])
|
||||
|
||||
|
||||
class VersionV11(object):
|
||||
def show(self, req):
|
||||
builder = nova.api.openstack.views.versions.get_view_builder(req)
|
||||
@@ -282,12 +247,7 @@ class VersionsHeadersSerializer(wsgi.ResponseHeadersSerializer):
|
||||
response.status_int = 300
|
||||
|
||||
|
||||
def create_resource(version='1.0'):
|
||||
controller = {
|
||||
'1.0': VersionV10,
|
||||
'1.1': VersionV11,
|
||||
}[version]()
|
||||
|
||||
def create_resource():
|
||||
body_serializers = {
|
||||
'application/xml': VersionsXMLSerializer(),
|
||||
'application/atom+xml': VersionsAtomSerializer(),
|
||||
@@ -296,5 +256,5 @@ def create_resource(version='1.0'):
|
||||
|
||||
deserializer = wsgi.RequestDeserializer()
|
||||
|
||||
return wsgi.Resource(controller, serializer=serializer,
|
||||
return wsgi.Resource(VersionV11(), serializer=serializer,
|
||||
deserializer=deserializer)
|
||||
|
@@ -28,9 +28,6 @@ LOG = logging.getLogger('nova.api.openstack.views.addresses')
|
||||
class ViewBuilder(object):
|
||||
"""Models a server addresses response as a python dictionary."""
|
||||
|
||||
def build(self, inst):
|
||||
raise NotImplementedError()
|
||||
|
||||
def _extract_ips(self, network, key=None):
|
||||
if key:
|
||||
chain = network[key]
|
||||
@@ -41,28 +38,6 @@ class ViewBuilder(object):
|
||||
continue
|
||||
yield ip
|
||||
|
||||
|
||||
class ViewBuilderV10(ViewBuilder):
|
||||
|
||||
def build(self, networks):
|
||||
if not networks:
|
||||
return dict(public=[], private=[])
|
||||
|
||||
return dict(public=self.build_public_parts(networks),
|
||||
private=self.build_private_parts(networks))
|
||||
|
||||
def build_public_parts(self, nets):
|
||||
ips = [self._extract_ips(nets[label],
|
||||
key='floating_ips') for label in nets]
|
||||
return [ip['addr'] for ip in itertools.chain(*ips)]
|
||||
|
||||
def build_private_parts(self, nets):
|
||||
ips = [self._extract_ips(nets[label], key='ips') for label in nets]
|
||||
return [ip['addr'] for ip in itertools.chain(*ips)]
|
||||
|
||||
|
||||
class ViewBuilderV11(ViewBuilder):
|
||||
|
||||
def build(self, networks):
|
||||
result = {}
|
||||
for network in networks:
|
||||
|
@@ -23,6 +23,13 @@ from nova.api.openstack import common
|
||||
|
||||
class ViewBuilder(object):
|
||||
|
||||
def __init__(self, base_url, project_id=""):
|
||||
"""
|
||||
:param base_url: url of the root wsgi application
|
||||
"""
|
||||
self.base_url = base_url
|
||||
self.project_id = project_id
|
||||
|
||||
def build(self, flavor_obj, is_detail=False):
|
||||
"""Generic method used to generate a flavor entity."""
|
||||
if is_detail:
|
||||
@@ -30,7 +37,7 @@ class ViewBuilder(object):
|
||||
else:
|
||||
flavor = self._build_simple(flavor_obj)
|
||||
|
||||
self._build_extra(flavor)
|
||||
flavor["links"] = self._build_links(flavor)
|
||||
|
||||
return flavor
|
||||
|
||||
@@ -57,26 +64,9 @@ class ViewBuilder(object):
|
||||
|
||||
return detail
|
||||
|
||||
def _build_extra(self, flavor_obj):
|
||||
"""Hook for version-specific changes to newly created flavor object."""
|
||||
pass
|
||||
|
||||
|
||||
class ViewBuilderV11(ViewBuilder):
|
||||
"""Openstack API v1.1 flavors view builder."""
|
||||
|
||||
def __init__(self, base_url, project_id=""):
|
||||
"""
|
||||
:param base_url: url of the root wsgi application
|
||||
"""
|
||||
self.base_url = base_url
|
||||
self.project_id = project_id
|
||||
|
||||
def _build_extra(self, flavor_obj):
|
||||
flavor_obj["links"] = self._build_links(flavor_obj)
|
||||
|
||||
def _build_links(self, flavor_obj):
|
||||
"""Generate a container of links that refer to the provided flavor."""
|
||||
print flavor_obj
|
||||
href = self.generate_href(flavor_obj["id"])
|
||||
bookmark = self.generate_bookmark(flavor_obj["id"])
|
||||
|
||||
|
@@ -71,15 +71,6 @@ class ViewBuilder(object):
|
||||
"""Return an href string pointing to this object."""
|
||||
return os.path.join(self.base_url, "images", str(image_id))
|
||||
|
||||
def build_list(self, image_objs, detail=False, **kwargs):
|
||||
"""Return a standardized image list structure for display."""
|
||||
images = []
|
||||
for image_obj in image_objs:
|
||||
image = self.build(image_obj, detail=detail)
|
||||
images.append(image)
|
||||
|
||||
return dict(images=images)
|
||||
|
||||
def build(self, image_obj, detail=False):
|
||||
"""Return a standardized image structure for display by the API."""
|
||||
self._format_dates(image_obj)
|
||||
@@ -95,6 +86,27 @@ class ViewBuilder(object):
|
||||
self._build_server(image, image_obj)
|
||||
self._build_image_id(image, image_obj)
|
||||
|
||||
href = self.generate_href(image_obj["id"])
|
||||
bookmark = self.generate_bookmark(image_obj["id"])
|
||||
alternate = self.generate_alternate(image_obj["id"])
|
||||
|
||||
image["links"] = [
|
||||
{
|
||||
"rel": "self",
|
||||
"href": href,
|
||||
},
|
||||
{
|
||||
"rel": "bookmark",
|
||||
"href": bookmark,
|
||||
},
|
||||
{
|
||||
"rel": "alternate",
|
||||
"type": "application/vnd.openstack.image",
|
||||
"href": alternate,
|
||||
},
|
||||
|
||||
]
|
||||
|
||||
if detail:
|
||||
image.update({
|
||||
"created": image_obj.get("created_at"),
|
||||
@@ -103,28 +115,24 @@ class ViewBuilder(object):
|
||||
})
|
||||
image["progress"] = self._get_progress_for_status(orig_status)
|
||||
|
||||
image["metadata"] = image_obj.get("properties", {})
|
||||
|
||||
min_ram = image_obj.get('min_ram') or 0
|
||||
try:
|
||||
min_ram = int(min_ram)
|
||||
except ValueError:
|
||||
min_ram = 0
|
||||
image['minRam'] = min_ram
|
||||
|
||||
min_disk = image_obj.get('min_disk') or 0
|
||||
try:
|
||||
min_disk = int(min_disk)
|
||||
except ValueError:
|
||||
min_disk = 0
|
||||
image['minDisk'] = min_disk
|
||||
|
||||
return image
|
||||
|
||||
|
||||
class ViewBuilderV10(ViewBuilder):
|
||||
"""OpenStack API v1.0 Image Builder"""
|
||||
|
||||
def _build_server(self, image, image_obj):
|
||||
try:
|
||||
image['serverId'] = int(image_obj['properties']['instance_id'])
|
||||
except (KeyError, ValueError):
|
||||
pass
|
||||
|
||||
def _build_image_id(self, image, image_obj):
|
||||
try:
|
||||
image['id'] = int(image_obj['id'])
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
|
||||
class ViewBuilderV11(ViewBuilder):
|
||||
"""OpenStack API v1.1 Image Builder"""
|
||||
|
||||
def _build_server(self, image, image_obj):
|
||||
try:
|
||||
serverRef = image_obj['properties']['instance_ref']
|
||||
@@ -179,49 +187,6 @@ class ViewBuilderV11(ViewBuilder):
|
||||
|
||||
return reval
|
||||
|
||||
def build(self, image_obj, detail=False):
|
||||
"""Return a standardized image structure for display by the API."""
|
||||
image = ViewBuilder.build(self, image_obj, detail)
|
||||
href = self.generate_href(image_obj["id"])
|
||||
bookmark = self.generate_bookmark(image_obj["id"])
|
||||
alternate = self.generate_alternate(image_obj["id"])
|
||||
|
||||
image["links"] = [
|
||||
{
|
||||
"rel": "self",
|
||||
"href": href,
|
||||
},
|
||||
{
|
||||
"rel": "bookmark",
|
||||
"href": bookmark,
|
||||
},
|
||||
{
|
||||
"rel": "alternate",
|
||||
"type": "application/vnd.openstack.image",
|
||||
"href": alternate,
|
||||
},
|
||||
|
||||
]
|
||||
|
||||
if detail:
|
||||
image["metadata"] = image_obj.get("properties", {})
|
||||
|
||||
min_ram = image_obj.get('min_ram') or 0
|
||||
try:
|
||||
min_ram = int(min_ram)
|
||||
except ValueError:
|
||||
min_ram = 0
|
||||
image['minRam'] = min_ram
|
||||
|
||||
min_disk = image_obj.get('min_disk') or 0
|
||||
try:
|
||||
min_disk = int(min_disk)
|
||||
except ValueError:
|
||||
min_disk = 0
|
||||
image['minDisk'] = min_disk
|
||||
|
||||
return image
|
||||
|
||||
def generate_bookmark(self, image_id):
|
||||
"""Create a URL that refers to a specific flavor id."""
|
||||
return os.path.join(common.remove_version_from_href(self.base_url),
|
||||
|
@@ -25,12 +25,6 @@ from nova import utils
|
||||
class ViewBuilder(object):
|
||||
"""Openstack API base limits view builder."""
|
||||
|
||||
def _build_rate_limits(self, rate_limits):
|
||||
raise NotImplementedError()
|
||||
|
||||
def _build_rate_limit(self, rate_limit):
|
||||
raise NotImplementedError()
|
||||
|
||||
def build(self, rate_limits, absolute_limits):
|
||||
rate_limits = self._build_rate_limits(rate_limits)
|
||||
absolute_limits = self._build_absolute_limits(absolute_limits)
|
||||
@@ -66,28 +60,6 @@ class ViewBuilder(object):
|
||||
limits[name] = value
|
||||
return limits
|
||||
|
||||
|
||||
class ViewBuilderV10(ViewBuilder):
|
||||
"""Openstack API v1.0 limits view builder."""
|
||||
|
||||
def _build_rate_limits(self, rate_limits):
|
||||
return [self._build_rate_limit(r) for r in rate_limits]
|
||||
|
||||
def _build_rate_limit(self, rate_limit):
|
||||
return {
|
||||
"verb": rate_limit["verb"],
|
||||
"URI": rate_limit["URI"],
|
||||
"regex": rate_limit["regex"],
|
||||
"value": rate_limit["value"],
|
||||
"remaining": int(rate_limit["remaining"]),
|
||||
"unit": rate_limit["unit"],
|
||||
"resetTime": rate_limit["resetTime"],
|
||||
}
|
||||
|
||||
|
||||
class ViewBuilderV11(ViewBuilder):
|
||||
"""Openstack API v1.1 limits view builder."""
|
||||
|
||||
def _build_rate_limits(self, rate_limits):
|
||||
limits = []
|
||||
for rate_limit in rate_limits:
|
||||
|
@@ -30,16 +30,16 @@ LOG = logging.getLogger('nova.api.openstack.views.servers')
|
||||
|
||||
|
||||
class ViewBuilder(object):
|
||||
"""Model a server response as a python dictionary.
|
||||
"""Model a server response as a python dictionary."""
|
||||
|
||||
Public methods: build
|
||||
Abstract methods: _build_image, _build_flavor
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, context, addresses_builder):
|
||||
def __init__(self, context, addresses_builder, flavor_builder,
|
||||
image_builder, base_url, project_id=""):
|
||||
self.context = context
|
||||
self.addresses_builder = addresses_builder
|
||||
self.flavor_builder = flavor_builder
|
||||
self.image_builder = image_builder
|
||||
self.base_url = base_url
|
||||
self.project_id = project_id
|
||||
|
||||
def build(self, inst, is_detail=False):
|
||||
"""Return a dict that represenst a server."""
|
||||
@@ -51,20 +51,11 @@ class ViewBuilder(object):
|
||||
else:
|
||||
server = self._build_simple(inst)
|
||||
|
||||
self._build_extra(server['server'], inst)
|
||||
self._build_links(server['server'], inst)
|
||||
server['server']['uuid'] = inst['uuid']
|
||||
|
||||
return server
|
||||
|
||||
def build_list(self, server_objs, is_detail=False, **kwargs):
|
||||
limit = kwargs.get('limit', None)
|
||||
servers = []
|
||||
servers_links = []
|
||||
|
||||
for server_obj in server_objs:
|
||||
servers.append(self.build(server_obj, is_detail)['server'])
|
||||
|
||||
return dict(servers=servers)
|
||||
|
||||
def _build_simple(self, inst):
|
||||
"""Return a simple model of a server."""
|
||||
return dict(server=dict(id=inst['id'], name=inst['display_name']))
|
||||
@@ -96,69 +87,25 @@ class ViewBuilder(object):
|
||||
networks = common.get_networks_for_instance(self.context, inst)
|
||||
self._build_addresses(inst_dict, networks)
|
||||
|
||||
inst_dict['created'] = utils.isotime(inst['created_at'])
|
||||
inst_dict['updated'] = utils.isotime(inst['updated_at'])
|
||||
|
||||
status = inst_dict.get('status')
|
||||
if status in ('ACTIVE', 'BUILD', 'REBUILD', 'RESIZE',
|
||||
'VERIFY_RESIZE'):
|
||||
inst_dict['progress'] = inst['progress'] or 0
|
||||
|
||||
inst_dict['accessIPv4'] = inst.get('access_ip_v4') or ""
|
||||
inst_dict['accessIPv6'] = inst.get('access_ip_v6') or ""
|
||||
inst_dict['key_name'] = inst.get('key_name', '')
|
||||
inst_dict['config_drive'] = inst.get('config_drive')
|
||||
|
||||
return dict(server=inst_dict)
|
||||
|
||||
def _build_addresses(self, response, networks):
|
||||
"""Return the addresses sub-resource of a server."""
|
||||
response['addresses'] = self.addresses_builder.build(networks)
|
||||
|
||||
def _build_image(self, response, inst):
|
||||
"""Return the image sub-resource of a server."""
|
||||
raise NotImplementedError()
|
||||
|
||||
def _build_flavor(self, response, inst):
|
||||
"""Return the flavor sub-resource of a server."""
|
||||
raise NotImplementedError()
|
||||
|
||||
def _build_extra(self, response, inst):
|
||||
pass
|
||||
|
||||
|
||||
class ViewBuilderV10(ViewBuilder):
|
||||
"""Model an Openstack API V1.0 server response."""
|
||||
|
||||
def _build_extra(self, response, inst):
|
||||
response['uuid'] = inst['uuid']
|
||||
|
||||
def _build_image(self, response, inst):
|
||||
if inst.get('image_ref', None):
|
||||
image_ref = inst['image_ref']
|
||||
if str(image_ref).startswith('http'):
|
||||
raise exception.ListingImageRefsNotSupported()
|
||||
response['imageId'] = int(image_ref)
|
||||
|
||||
def _build_flavor(self, response, inst):
|
||||
if inst.get('instance_type', None):
|
||||
response['flavorId'] = inst['instance_type']['flavorid']
|
||||
|
||||
|
||||
class ViewBuilderV11(ViewBuilder):
|
||||
"""Model an Openstack API V1.0 server response."""
|
||||
def __init__(self, context, addresses_builder, flavor_builder,
|
||||
image_builder, base_url, project_id=""):
|
||||
super(ViewBuilderV11, self).__init__(context, addresses_builder)
|
||||
self.flavor_builder = flavor_builder
|
||||
self.image_builder = image_builder
|
||||
self.base_url = base_url
|
||||
self.project_id = project_id
|
||||
|
||||
def _build_detail(self, inst):
|
||||
response = super(ViewBuilderV11, self)._build_detail(inst)
|
||||
response['server']['created'] = utils.isotime(inst['created_at'])
|
||||
response['server']['updated'] = utils.isotime(inst['updated_at'])
|
||||
|
||||
status = response['server'].get('status')
|
||||
if status in ('ACTIVE', 'BUILD', 'REBUILD', 'RESIZE',
|
||||
'VERIFY_RESIZE'):
|
||||
response['server']['progress'] = inst['progress'] or 0
|
||||
|
||||
response['server']['accessIPv4'] = inst.get('access_ip_v4') or ""
|
||||
response['server']['accessIPv6'] = inst.get('access_ip_v6') or ""
|
||||
response['server']['key_name'] = inst.get('key_name', '')
|
||||
response['server']['config_drive'] = inst.get('config_drive')
|
||||
|
||||
return response
|
||||
|
||||
def _build_image(self, response, inst):
|
||||
if inst.get("image_ref", None):
|
||||
image_href = inst['image_ref']
|
||||
@@ -189,10 +136,6 @@ class ViewBuilderV11(ViewBuilder):
|
||||
]
|
||||
}
|
||||
|
||||
def _build_extra(self, response, inst):
|
||||
self._build_links(response, inst)
|
||||
response['uuid'] = inst['uuid']
|
||||
|
||||
def _build_links(self, response, inst):
|
||||
href = self.generate_href(inst["id"])
|
||||
bookmark = self.generate_bookmark(inst["id"])
|
||||
|
@@ -143,7 +143,7 @@ class Controller(object):
|
||||
return cooked
|
||||
|
||||
|
||||
def create_resource(version):
|
||||
def create_resource():
|
||||
metadata = {
|
||||
"attributes": {
|
||||
"zone": ["id", "api_url", "name", "capabilities"],
|
||||
@@ -151,7 +151,7 @@ def create_resource(version):
|
||||
}
|
||||
|
||||
body_serializers = {
|
||||
'application/xml': wsgi.XMLDictSerializer(xmlns=wsgi.XMLNS_V10,
|
||||
'application/xml': wsgi.XMLDictSerializer(xmlns=wsgi.XMLNS_V11,
|
||||
metadata=metadata),
|
||||
}
|
||||
serializer = wsgi.ResponseSerializer(body_serializers)
|
||||
|
@@ -65,32 +65,24 @@ def fake_wsgi(self, req):
|
||||
return self.application
|
||||
|
||||
|
||||
def wsgi_app(inner_app10=None, inner_app11=None, fake_auth=True,
|
||||
fake_auth_context=None):
|
||||
if not inner_app10:
|
||||
inner_app10 = openstack.APIRouterV10()
|
||||
def wsgi_app(inner_app11=None, fake_auth=True, fake_auth_context=None):
|
||||
if not inner_app11:
|
||||
inner_app11 = openstack.APIRouterV11()
|
||||
inner_app11 = openstack.APIRouter()
|
||||
|
||||
if fake_auth:
|
||||
if fake_auth_context is not None:
|
||||
ctxt = fake_auth_context
|
||||
else:
|
||||
ctxt = context.RequestContext('fake', 'fake', auth_token=True)
|
||||
api10 = openstack.FaultWrapper(api_auth.InjectContext(ctxt,
|
||||
limits.RateLimitingMiddleware(inner_app10)))
|
||||
api11 = openstack.FaultWrapper(api_auth.InjectContext(ctxt,
|
||||
limits.RateLimitingMiddleware(
|
||||
extensions.ExtensionMiddleware(inner_app11))))
|
||||
else:
|
||||
api10 = openstack.FaultWrapper(auth.AuthMiddleware(
|
||||
limits.RateLimitingMiddleware(inner_app10)))
|
||||
api11 = openstack.FaultWrapper(auth.AuthMiddleware(
|
||||
limits.RateLimitingMiddleware(
|
||||
extensions.ExtensionMiddleware(inner_app11))))
|
||||
Auth = auth
|
||||
mapper = urlmap.URLMap()
|
||||
mapper['/v1.0'] = api10
|
||||
mapper['/v1.1'] = api11
|
||||
mapper['/'] = openstack.FaultWrapper(versions.Versions())
|
||||
return mapper
|
||||
@@ -401,7 +393,7 @@ class FakeAuthManager(object):
|
||||
if p:
|
||||
return p
|
||||
else:
|
||||
raise exc.NotFound
|
||||
raise exc.ProjectNotFound(project_id=pid)
|
||||
|
||||
def get_projects(self, user_id=None):
|
||||
if not user_id:
|
||||
|
@@ -55,7 +55,7 @@ class AccountsTest(test.TestCase):
|
||||
fakemgr.create_project('test2', superuser)
|
||||
|
||||
def test_get_account(self):
|
||||
req = webob.Request.blank('/v1.0/accounts/test1')
|
||||
req = webob.Request.blank('/v1.1/fake/accounts/test1')
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
res_dict = json.loads(res.body)
|
||||
|
||||
@@ -65,7 +65,7 @@ class AccountsTest(test.TestCase):
|
||||
self.assertEqual(res.status_int, 200)
|
||||
|
||||
def test_account_delete(self):
|
||||
req = webob.Request.blank('/v1.0/accounts/test1')
|
||||
req = webob.Request.blank('/v1.1/fake/accounts/test1')
|
||||
req.method = 'DELETE'
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertTrue('test1' not in fakes.FakeAuthManager.projects)
|
||||
@@ -74,7 +74,7 @@ class AccountsTest(test.TestCase):
|
||||
def test_account_create(self):
|
||||
body = dict(account=dict(description='test account',
|
||||
manager='id1'))
|
||||
req = webob.Request.blank('/v1.0/accounts/newacct')
|
||||
req = webob.Request.blank('/v1.1/fake/accounts/newacct')
|
||||
req.headers["Content-Type"] = "application/json"
|
||||
req.method = 'PUT'
|
||||
req.body = json.dumps(body)
|
||||
@@ -94,7 +94,7 @@ class AccountsTest(test.TestCase):
|
||||
def test_account_update(self):
|
||||
body = dict(account=dict(description='test account',
|
||||
manager='id2'))
|
||||
req = webob.Request.blank('/v1.0/accounts/test1')
|
||||
req = webob.Request.blank('/v1.1/fake/accounts/test1')
|
||||
req.headers["Content-Type"] = "application/json"
|
||||
req.method = 'PUT'
|
||||
req.body = json.dumps(body)
|
||||
|
@@ -1,47 +0,0 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2010 OpenStack LLC.
|
||||
# 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 webob
|
||||
|
||||
from nova import test
|
||||
from nova.tests.api.openstack import fakes
|
||||
|
||||
|
||||
class AdminAPITest(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(AdminAPITest, self).setUp()
|
||||
fakes.stub_out_networking(self.stubs)
|
||||
fakes.stub_out_rate_limiting(self.stubs)
|
||||
self.flags(verbose=True)
|
||||
|
||||
def test_admin_enabled(self):
|
||||
self.flags(allow_admin_api=True)
|
||||
# We should still be able to access public operations.
|
||||
req = webob.Request.blank('/v1.0/flavors')
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 200)
|
||||
# TODO: Confirm admin operations are available.
|
||||
|
||||
def test_admin_disabled(self):
|
||||
self.flags(allow_admin_api=False)
|
||||
# We should still be able to access public operations.
|
||||
req = webob.Request.blank('/v1.0/flavors')
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
# TODO: Confirm admin operations are unavailable.
|
||||
self.assertEqual(res.status_int, 200)
|
@@ -50,7 +50,7 @@ class Test(test.TestCase):
|
||||
user = nova.auth.manager.User('id1', 'user1', 'user1_key', None, None)
|
||||
f.add_user(user)
|
||||
|
||||
req = webob.Request.blank('/v1.0/')
|
||||
req = webob.Request.blank('/v1.1/')
|
||||
req.headers['X-Auth-User'] = 'user1'
|
||||
req.headers['X-Auth-Key'] = 'user1_key'
|
||||
req.headers['X-Auth-Project-Id'] = 'user1_project'
|
||||
@@ -67,21 +67,21 @@ class Test(test.TestCase):
|
||||
f.add_user(user)
|
||||
f.create_project('user1_project', user)
|
||||
|
||||
req = webob.Request.blank('/v1.0/', {'HTTP_HOST': 'foo'})
|
||||
req = webob.Request.blank('/v1.1/', {'HTTP_HOST': 'foo'})
|
||||
req.headers['X-Auth-User'] = 'user1'
|
||||
req.headers['X-Auth-Key'] = 'user1_key'
|
||||
result = req.get_response(fakes.wsgi_app(fake_auth=False))
|
||||
self.assertEqual(result.status, '204 No Content')
|
||||
self.assertEqual(len(result.headers['X-Auth-Token']), 40)
|
||||
self.assertEqual(result.headers['X-Server-Management-Url'],
|
||||
"http://foo/v1.0")
|
||||
"http://foo/v1.1/user1_project")
|
||||
self.assertEqual(result.headers['X-CDN-Management-Url'],
|
||||
"")
|
||||
self.assertEqual(result.headers['X-Storage-Url'], "")
|
||||
|
||||
token = result.headers['X-Auth-Token']
|
||||
self.stubs.Set(nova.api.openstack, 'APIRouterV10', fakes.FakeRouter)
|
||||
req = webob.Request.blank('/v1.0/user1_project')
|
||||
self.stubs.Set(nova.api.openstack, 'APIRouter', fakes.FakeRouter)
|
||||
req = webob.Request.blank('/v1.1/user1_project')
|
||||
req.headers['X-Auth-Token'] = token
|
||||
result = req.get_response(fakes.wsgi_app(fake_auth=False))
|
||||
self.assertEqual(result.status, '200 OK')
|
||||
@@ -105,7 +105,7 @@ class Test(test.TestCase):
|
||||
self.stubs.Set(fakes.FakeAuthDatabase, 'auth_token_get',
|
||||
bad_token)
|
||||
|
||||
req = webob.Request.blank('/v1.0/')
|
||||
req = webob.Request.blank('/v1.1/')
|
||||
req.headers['X-Auth-Token'] = 'token_hash'
|
||||
result = req.get_response(fakes.wsgi_app(fake_auth=False))
|
||||
self.assertEqual(result.status, '401 Unauthorized')
|
||||
@@ -118,23 +118,22 @@ class Test(test.TestCase):
|
||||
f.create_project('user1_project', user)
|
||||
f.create_project('user2_project', user)
|
||||
|
||||
req = webob.Request.blank('/v1.0/', {'HTTP_HOST': 'foo'})
|
||||
req = webob.Request.blank('/v1.1/', {'HTTP_HOST': 'foo'})
|
||||
req.headers['X-Auth-User'] = 'user1'
|
||||
req.headers['X-Auth-Key'] = 'user1_key'
|
||||
result = req.get_response(fakes.wsgi_app(fake_auth=False))
|
||||
self.assertEqual(result.status, '204 No Content')
|
||||
|
||||
token = result.headers['X-Auth-Token']
|
||||
self.stubs.Set(nova.api.openstack, 'APIRouterV10', fakes.FakeRouter)
|
||||
req = webob.Request.blank('/v1.0/')
|
||||
self.stubs.Set(nova.api.openstack, 'APIRouter', fakes.FakeRouter)
|
||||
req = webob.Request.blank('/v1.1/user2_project')
|
||||
req.headers['X-Auth-Token'] = token
|
||||
req.headers['X-Auth-Project-Id'] = 'user2_project'
|
||||
result = req.get_response(fakes.wsgi_app(fake_auth=False))
|
||||
self.assertEqual(result.status, '200 OK')
|
||||
self.assertEqual(result.headers['X-Test-Success'], 'True')
|
||||
|
||||
def test_bad_user_bad_key(self):
|
||||
req = webob.Request.blank('/v1.0/')
|
||||
req = webob.Request.blank('/v1.1/')
|
||||
req.headers['X-Auth-User'] = 'unknown_user'
|
||||
req.headers['X-Auth-Key'] = 'unknown_user_key'
|
||||
req.headers['X-Auth-Project-Id'] = 'user_project'
|
||||
@@ -146,19 +145,19 @@ class Test(test.TestCase):
|
||||
user = nova.auth.manager.User('id1', 'user1', 'user1_key', None, None)
|
||||
f.add_user(user)
|
||||
|
||||
req = webob.Request.blank('/v1.0/')
|
||||
req = webob.Request.blank('/v1.1/')
|
||||
req.headers['X-Auth-User'] = 'unknown_user'
|
||||
req.headers['X-Auth-Key'] = 'user1_key'
|
||||
result = req.get_response(fakes.wsgi_app(fake_auth=False))
|
||||
self.assertEqual(result.status, '401 Unauthorized')
|
||||
|
||||
def test_no_user(self):
|
||||
req = webob.Request.blank('/v1.0/')
|
||||
req = webob.Request.blank('/v1.1/')
|
||||
result = req.get_response(fakes.wsgi_app(fake_auth=False))
|
||||
self.assertEqual(result.status, '401 Unauthorized')
|
||||
|
||||
def test_bad_token(self):
|
||||
req = webob.Request.blank('/v1.0/')
|
||||
req = webob.Request.blank('/v1.1/')
|
||||
req.headers['X-Auth-Token'] = 'unknown_token'
|
||||
result = req.get_response(fakes.wsgi_app(fake_auth=False))
|
||||
self.assertEqual(result.status, '401 Unauthorized')
|
||||
@@ -172,17 +171,16 @@ class Test(test.TestCase):
|
||||
f.create_project('user1_project', user1)
|
||||
f.create_project('user2_project', user2)
|
||||
|
||||
req = webob.Request.blank('/v1.0/', {'HTTP_HOST': 'foo'})
|
||||
req = webob.Request.blank('/v1.1/', {'HTTP_HOST': 'foo'})
|
||||
req.headers['X-Auth-User'] = 'user1'
|
||||
req.headers['X-Auth-Key'] = 'user1_key'
|
||||
result = req.get_response(fakes.wsgi_app(fake_auth=False))
|
||||
self.assertEqual(result.status, '204 No Content')
|
||||
|
||||
token = result.headers['X-Auth-Token']
|
||||
self.stubs.Set(nova.api.openstack, 'APIRouterV10', fakes.FakeRouter)
|
||||
req = webob.Request.blank('/v1.0/fake')
|
||||
self.stubs.Set(nova.api.openstack, 'APIRouter', fakes.FakeRouter)
|
||||
req = webob.Request.blank('/v1.1/user2_project')
|
||||
req.headers['X-Auth-Token'] = token
|
||||
req.headers['X-Auth-Project-Id'] = 'user2_project'
|
||||
result = req.get_response(fakes.wsgi_app(fake_auth=False))
|
||||
self.assertEqual(result.status, '401 Unauthorized')
|
||||
|
||||
@@ -192,17 +190,16 @@ class Test(test.TestCase):
|
||||
f.add_user(user1)
|
||||
f.create_project('user1_project', user1)
|
||||
|
||||
req = webob.Request.blank('/v1.0/', {'HTTP_HOST': 'foo'})
|
||||
req = webob.Request.blank('/v1.1/', {'HTTP_HOST': 'foo'})
|
||||
req.headers['X-Auth-User'] = 'user1'
|
||||
req.headers['X-Auth-Key'] = 'user1_key'
|
||||
result = req.get_response(fakes.wsgi_app(fake_auth=False))
|
||||
self.assertEqual(result.status, '204 No Content')
|
||||
|
||||
token = result.headers['X-Auth-Token']
|
||||
self.stubs.Set(nova.api.openstack, 'APIRouterV10', fakes.FakeRouter)
|
||||
req = webob.Request.blank('/v1.0/fake')
|
||||
self.stubs.Set(nova.api.openstack, 'APIRouter', fakes.FakeRouter)
|
||||
req = webob.Request.blank('/v1.1/')
|
||||
req.headers['X-Auth-Token'] = token
|
||||
req.headers['X-Auth-Project-Id'] = 'unknown_project'
|
||||
result = req.get_response(fakes.wsgi_app(fake_auth=False))
|
||||
self.assertEqual(result.status, '401 Unauthorized')
|
||||
|
||||
@@ -222,13 +219,13 @@ class TestFunctional(test.TestCase):
|
||||
created_at=datetime.datetime(2000, 1, 1, 12, 0, 0),
|
||||
))
|
||||
|
||||
req = webob.Request.blank('/v1.0/')
|
||||
req = webob.Request.blank('/v1.1/')
|
||||
req.headers['X-Auth-Token'] = 'test_token_hash'
|
||||
result = req.get_response(fakes.wsgi_app(fake_auth=False))
|
||||
self.assertEqual(result.status, '401 Unauthorized')
|
||||
|
||||
def test_token_doesnotexist(self):
|
||||
req = webob.Request.blank('/v1.0/')
|
||||
req = webob.Request.blank('/v1.1/')
|
||||
req.headers['X-Auth-Token'] = 'nonexistant_token_hash'
|
||||
result = req.get_response(fakes.wsgi_app(fake_auth=False))
|
||||
self.assertEqual(result.status, '401 Unauthorized')
|
||||
@@ -254,15 +251,15 @@ class TestLimiter(test.TestCase):
|
||||
f.add_user(user)
|
||||
f.create_project('test', user)
|
||||
|
||||
req = webob.Request.blank('/v1.0/')
|
||||
req = webob.Request.blank('/v1.1/')
|
||||
req.headers['X-Auth-User'] = 'user1'
|
||||
req.headers['X-Auth-Key'] = 'user1_key'
|
||||
result = req.get_response(fakes.wsgi_app(fake_auth=False))
|
||||
self.assertEqual(len(result.headers['X-Auth-Token']), 40)
|
||||
|
||||
token = result.headers['X-Auth-Token']
|
||||
self.stubs.Set(nova.api.openstack, 'APIRouterV10', fakes.FakeRouter)
|
||||
req = webob.Request.blank('/v1.0/fake')
|
||||
self.stubs.Set(nova.api.openstack, 'APIRouter', fakes.FakeRouter)
|
||||
req = webob.Request.blank('/v1.1/test')
|
||||
req.method = 'POST'
|
||||
req.headers['X-Auth-Token'] = token
|
||||
result = req.get_response(fakes.wsgi_app(fake_auth=False))
|
||||
|
@@ -106,7 +106,7 @@ class ConsolesTest(test.TestCase):
|
||||
super(ConsolesTest, self).setUp()
|
||||
self.flags(verbose=True)
|
||||
self.stubs.Set(db.api, 'instance_get', return_server_by_id)
|
||||
self.webreq = common.webob_factory('/v1.0/servers')
|
||||
self.webreq = common.webob_factory('/v1.1/fake/servers')
|
||||
|
||||
def test_create_console(self):
|
||||
def fake_create_console(cons_self, context, instance_id):
|
||||
@@ -114,7 +114,7 @@ class ConsolesTest(test.TestCase):
|
||||
return {}
|
||||
self.stubs.Set(console.API, 'create_console', fake_create_console)
|
||||
|
||||
req = webob.Request.blank('/v1.0/servers/10/consoles')
|
||||
req = webob.Request.blank('/v1.1/fake/servers/10/consoles')
|
||||
req.method = "POST"
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 200)
|
||||
@@ -136,7 +136,7 @@ class ConsolesTest(test.TestCase):
|
||||
|
||||
self.stubs.Set(console.API, 'get_console', fake_get_console)
|
||||
|
||||
req = webob.Request.blank('/v1.0/servers/10/consoles/20')
|
||||
req = webob.Request.blank('/v1.1/fake/servers/10/consoles/20')
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 200)
|
||||
res_dict = json.loads(res.body)
|
||||
@@ -148,7 +148,7 @@ class ConsolesTest(test.TestCase):
|
||||
|
||||
self.stubs.Set(console.API, 'get_console', fake_get_console)
|
||||
|
||||
req = webob.Request.blank('/v1.0/servers/10/consoles/20')
|
||||
req = webob.Request.blank('/v1.1/fake/servers/10/consoles/20')
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 404)
|
||||
|
||||
@@ -158,7 +158,7 @@ class ConsolesTest(test.TestCase):
|
||||
|
||||
self.stubs.Set(console.API, 'get_console', fake_get_console)
|
||||
|
||||
req = webob.Request.blank('/v1.0/servers/10/consoles/20')
|
||||
req = webob.Request.blank('/v1.1/fake/servers/10/consoles/20')
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 404)
|
||||
|
||||
@@ -182,7 +182,7 @@ class ConsolesTest(test.TestCase):
|
||||
|
||||
self.stubs.Set(console.API, 'get_consoles', fake_get_consoles)
|
||||
|
||||
req = webob.Request.blank('/v1.0/servers/10/consoles')
|
||||
req = webob.Request.blank('/v1.1/fake/servers/10/consoles')
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 200)
|
||||
res_dict = json.loads(res.body)
|
||||
@@ -204,7 +204,7 @@ class ConsolesTest(test.TestCase):
|
||||
self.stubs.Set(console.API, 'get_console', fake_get_console)
|
||||
self.stubs.Set(console.API, 'delete_console', fake_delete_console)
|
||||
|
||||
req = webob.Request.blank('/v1.0/servers/10/consoles/20')
|
||||
req = webob.Request.blank('/v1.1/fake/servers/10/consoles/20')
|
||||
req.method = "DELETE"
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 202)
|
||||
@@ -215,7 +215,7 @@ class ConsolesTest(test.TestCase):
|
||||
|
||||
self.stubs.Set(console.API, 'delete_console', fake_delete_console)
|
||||
|
||||
req = webob.Request.blank('/v1.0/servers/10/consoles/20')
|
||||
req = webob.Request.blank('/v1.1/fake/servers/10/consoles/20')
|
||||
req.method = "DELETE"
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 404)
|
||||
@@ -226,7 +226,7 @@ class ConsolesTest(test.TestCase):
|
||||
|
||||
self.stubs.Set(console.API, 'delete_console', fake_delete_console)
|
||||
|
||||
req = webob.Request.blank('/v1.0/servers/10/consoles/20')
|
||||
req = webob.Request.blank('/v1.1/fake/servers/10/consoles/20')
|
||||
req.method = "DELETE"
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 404)
|
||||
|
@@ -109,7 +109,7 @@ class ExtensionControllerTest(test.TestCase):
|
||||
self.ext_list.sort()
|
||||
|
||||
def test_list_extensions_json(self):
|
||||
app = openstack.APIRouterV11()
|
||||
app = openstack.APIRouter()
|
||||
ext_midware = extensions.ExtensionMiddleware(app)
|
||||
request = webob.Request.blank("/123/extensions")
|
||||
response = request.get_response(ext_midware)
|
||||
@@ -135,7 +135,7 @@ class ExtensionControllerTest(test.TestCase):
|
||||
)
|
||||
|
||||
def test_get_extension_json(self):
|
||||
app = openstack.APIRouterV11()
|
||||
app = openstack.APIRouter()
|
||||
ext_midware = extensions.ExtensionMiddleware(app)
|
||||
request = webob.Request.blank("/123/extensions/FOXNSOX")
|
||||
response = request.get_response(ext_midware)
|
||||
@@ -151,14 +151,14 @@ class ExtensionControllerTest(test.TestCase):
|
||||
"links": []})
|
||||
|
||||
def test_get_non_existing_extension_json(self):
|
||||
app = openstack.APIRouterV11()
|
||||
app = openstack.APIRouter()
|
||||
ext_midware = extensions.ExtensionMiddleware(app)
|
||||
request = webob.Request.blank("/123/extensions/4")
|
||||
response = request.get_response(ext_midware)
|
||||
self.assertEqual(404, response.status_int)
|
||||
|
||||
def test_list_extensions_xml(self):
|
||||
app = openstack.APIRouterV11()
|
||||
app = openstack.APIRouter()
|
||||
ext_midware = extensions.ExtensionMiddleware(app)
|
||||
request = webob.Request.blank("/123/extensions")
|
||||
request.accept = "application/xml"
|
||||
@@ -185,7 +185,7 @@ class ExtensionControllerTest(test.TestCase):
|
||||
xmlutil.validate_schema(root, 'extensions')
|
||||
|
||||
def test_get_extension_xml(self):
|
||||
app = openstack.APIRouterV11()
|
||||
app = openstack.APIRouter()
|
||||
ext_midware = extensions.ExtensionMiddleware(app)
|
||||
request = webob.Request.blank("/123/extensions/FOXNSOX")
|
||||
request.accept = "application/xml"
|
||||
@@ -216,7 +216,7 @@ class ResourceExtensionTest(test.TestCase):
|
||||
|
||||
def test_no_extension_present(self):
|
||||
manager = StubExtensionManager(None)
|
||||
app = openstack.APIRouterV11()
|
||||
app = openstack.APIRouter()
|
||||
ext_midware = extensions.ExtensionMiddleware(app, manager)
|
||||
request = webob.Request.blank("/blah")
|
||||
response = request.get_response(ext_midware)
|
||||
@@ -226,7 +226,7 @@ class ResourceExtensionTest(test.TestCase):
|
||||
res_ext = extensions.ResourceExtension('tweedles',
|
||||
StubController(response_body))
|
||||
manager = StubExtensionManager(res_ext)
|
||||
app = openstack.APIRouterV11()
|
||||
app = openstack.APIRouter()
|
||||
ext_midware = extensions.ExtensionMiddleware(app, manager)
|
||||
request = webob.Request.blank("/123/tweedles")
|
||||
response = request.get_response(ext_midware)
|
||||
@@ -237,7 +237,7 @@ class ResourceExtensionTest(test.TestCase):
|
||||
res_ext = extensions.ResourceExtension('tweedles',
|
||||
StubController(response_body))
|
||||
manager = StubExtensionManager(res_ext)
|
||||
app = openstack.APIRouterV11()
|
||||
app = openstack.APIRouter()
|
||||
ext_midware = extensions.ExtensionMiddleware(app, manager)
|
||||
request = webob.Request.blank("/123/tweedles")
|
||||
response = request.get_response(ext_midware)
|
||||
@@ -261,7 +261,7 @@ class ExtensionManagerTest(test.TestCase):
|
||||
self.flags(osapi_extensions_path=ext_path)
|
||||
|
||||
def test_get_resources(self):
|
||||
app = openstack.APIRouterV11()
|
||||
app = openstack.APIRouter()
|
||||
ext_midware = extensions.ExtensionMiddleware(app)
|
||||
request = webob.Request.blank("/123/foxnsocks")
|
||||
response = request.get_response(ext_midware)
|
||||
@@ -269,7 +269,7 @@ class ExtensionManagerTest(test.TestCase):
|
||||
self.assertEqual(response_body, response.body)
|
||||
|
||||
def test_invalid_extensions(self):
|
||||
app = openstack.APIRouterV11()
|
||||
app = openstack.APIRouter()
|
||||
ext_midware = extensions.ExtensionMiddleware(app)
|
||||
ext_mgr = ext_midware.ext_mgr
|
||||
ext_mgr.add_extension(InvalidExtension())
|
||||
@@ -285,7 +285,7 @@ class ActionExtensionTest(test.TestCase):
|
||||
self.flags(osapi_extensions_path=ext_path)
|
||||
|
||||
def _send_server_action_request(self, url, body):
|
||||
app = openstack.APIRouterV11()
|
||||
app = openstack.APIRouter()
|
||||
ext_midware = extensions.ExtensionMiddleware(app)
|
||||
request = webob.Request.blank(url)
|
||||
request.method = 'POST'
|
||||
|
@@ -38,27 +38,6 @@ class TestFaults(test.TestCase):
|
||||
xml_string = xml_string.replace("\t", "")
|
||||
return xml_string
|
||||
|
||||
def test_400_fault_xml(self):
|
||||
"""Test fault serialized to XML via file-extension and/or header."""
|
||||
requests = [
|
||||
webob.Request.blank('/.xml'),
|
||||
webob.Request.blank('/', headers={"Accept": "application/xml"}),
|
||||
]
|
||||
|
||||
for request in requests:
|
||||
fault = faults.Fault(webob.exc.HTTPBadRequest(explanation='scram'))
|
||||
response = request.get_response(fault)
|
||||
|
||||
expected = self._prepare_xml("""
|
||||
<badRequest code="400" xmlns="%s">
|
||||
<message>scram</message>
|
||||
</badRequest>
|
||||
""" % common.XML_NS_V10)
|
||||
actual = self._prepare_xml(response.body)
|
||||
|
||||
self.assertEqual(response.content_type, "application/xml")
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
def test_400_fault_json(self):
|
||||
"""Test fault serialized to JSON via file-extension and/or header."""
|
||||
requests = [
|
||||
@@ -81,30 +60,6 @@ class TestFaults(test.TestCase):
|
||||
self.assertEqual(response.content_type, "application/json")
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
def test_413_fault_xml(self):
|
||||
requests = [
|
||||
webob.Request.blank('/.xml'),
|
||||
webob.Request.blank('/', headers={"Accept": "application/xml"}),
|
||||
]
|
||||
|
||||
for request in requests:
|
||||
exc = webob.exc.HTTPRequestEntityTooLarge
|
||||
fault = faults.Fault(exc(explanation='sorry',
|
||||
headers={'Retry-After': 4}))
|
||||
response = request.get_response(fault)
|
||||
|
||||
expected = self._prepare_xml("""
|
||||
<overLimit code="413" xmlns="%s">
|
||||
<message>sorry</message>
|
||||
<retryAfter>4</retryAfter>
|
||||
</overLimit>
|
||||
""" % common.XML_NS_V10)
|
||||
actual = self._prepare_xml(response.body)
|
||||
|
||||
self.assertEqual(expected, actual)
|
||||
self.assertEqual(response.content_type, "application/xml")
|
||||
self.assertEqual(response.headers['Retry-After'], 4)
|
||||
|
||||
def test_413_fault_json(self):
|
||||
"""Test fault serialized to JSON via file-extension and/or header."""
|
||||
requests = [
|
||||
@@ -147,19 +102,7 @@ class TestFaults(test.TestCase):
|
||||
fault = faults.Fault(webob.exc.HTTPBadRequest(explanation='what?'))
|
||||
self.assertEqual(fault.status_int, 400)
|
||||
|
||||
def test_v10_xml_serializer(self):
|
||||
"""Ensure that a v1.0 request responds with a v1.0 xmlns"""
|
||||
request = webob.Request.blank('/',
|
||||
headers={"Accept": "application/xml"})
|
||||
|
||||
fault = faults.Fault(webob.exc.HTTPBadRequest(explanation='scram'))
|
||||
response = request.get_response(fault)
|
||||
|
||||
self.assertTrue(common.XML_NS_V10 in response.body)
|
||||
self.assertEqual(response.content_type, "application/xml")
|
||||
self.assertEqual(response.status_int, 400)
|
||||
|
||||
def test_v11_xml_serializer(self):
|
||||
def test_xml_serializer(self):
|
||||
"""Ensure that a v1.1 request responds with a v1.1 xmlns"""
|
||||
request = webob.Request.blank('/v1.1',
|
||||
headers={"Accept": "application/xml"})
|
||||
|
@@ -89,90 +89,15 @@ class FlavorsTest(test.TestCase):
|
||||
self.stubs.UnsetAll()
|
||||
super(FlavorsTest, self).tearDown()
|
||||
|
||||
def test_get_flavor_list_v1_0(self):
|
||||
req = webob.Request.blank('/v1.0/flavors')
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 200)
|
||||
flavors = json.loads(res.body)["flavors"]
|
||||
expected = [
|
||||
{
|
||||
"id": "1",
|
||||
"name": "flavor 1",
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"name": "flavor 2",
|
||||
},
|
||||
]
|
||||
self.assertEqual(flavors, expected)
|
||||
|
||||
def test_get_empty_flavor_list_v1_0(self):
|
||||
self.stubs.Set(nova.db.api, "instance_type_get_all",
|
||||
empty_instance_type_get_all)
|
||||
|
||||
req = webob.Request.blank('/v1.0/flavors')
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 200)
|
||||
flavors = json.loads(res.body)["flavors"]
|
||||
expected = []
|
||||
self.assertEqual(flavors, expected)
|
||||
|
||||
def test_get_flavor_list_detail_v1_0(self):
|
||||
req = webob.Request.blank('/v1.0/flavors/detail')
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 200)
|
||||
flavors = json.loads(res.body)["flavors"]
|
||||
expected = [
|
||||
{
|
||||
"id": "1",
|
||||
"name": "flavor 1",
|
||||
"ram": "256",
|
||||
"disk": "10",
|
||||
"rxtx_cap": "",
|
||||
"rxtx_quota": "",
|
||||
"swap": "",
|
||||
"vcpus": "",
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"name": "flavor 2",
|
||||
"ram": "512",
|
||||
"disk": "20",
|
||||
"rxtx_cap": "",
|
||||
"rxtx_quota": "",
|
||||
"swap": "",
|
||||
"vcpus": "",
|
||||
},
|
||||
]
|
||||
self.assertEqual(flavors, expected)
|
||||
|
||||
def test_get_flavor_by_id_v1_0(self):
|
||||
req = webob.Request.blank('/v1.0/flavors/1')
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 200)
|
||||
flavor = json.loads(res.body)["flavor"]
|
||||
expected = {
|
||||
"id": "1",
|
||||
"name": "flavor 1",
|
||||
"ram": "256",
|
||||
"disk": "10",
|
||||
"rxtx_cap": "",
|
||||
"rxtx_quota": "",
|
||||
"swap": "",
|
||||
"vcpus": "",
|
||||
}
|
||||
self.assertEqual(flavor, expected)
|
||||
|
||||
def test_get_flavor_by_invalid_id(self):
|
||||
self.stubs.Set(nova.db.api, "instance_type_get_by_flavor_id",
|
||||
return_instance_type_not_found)
|
||||
req = webob.Request.blank('/v1.0/flavors/asdf')
|
||||
req = webob.Request.blank('/v1.1/fake/flavors/asdf')
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 404)
|
||||
|
||||
def test_get_flavor_by_id_v1_1(self):
|
||||
def test_get_flavor_by_id(self):
|
||||
req = webob.Request.blank('/v1.1/fake/flavors/1')
|
||||
req.environ['api.version'] = '1.1'
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 200)
|
||||
flavor = json.loads(res.body)
|
||||
@@ -200,9 +125,8 @@ class FlavorsTest(test.TestCase):
|
||||
}
|
||||
self.assertEqual(flavor, expected)
|
||||
|
||||
def test_get_flavor_list_v1_1(self):
|
||||
def test_get_flavor_list(self):
|
||||
req = webob.Request.blank('/v1.1/fake/flavors')
|
||||
req.environ['api.version'] = '1.1'
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 200)
|
||||
flavor = json.loads(res.body)
|
||||
@@ -240,9 +164,8 @@ class FlavorsTest(test.TestCase):
|
||||
}
|
||||
self.assertEqual(flavor, expected)
|
||||
|
||||
def test_get_flavor_list_detail_v1_1(self):
|
||||
def test_get_flavor_list_detail(self):
|
||||
req = webob.Request.blank('/v1.1/fake/flavors/detail')
|
||||
req.environ['api.version'] = '1.1'
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 200)
|
||||
flavor = json.loads(res.body)
|
||||
@@ -292,7 +215,7 @@ class FlavorsTest(test.TestCase):
|
||||
}
|
||||
self.assertEqual(flavor, expected)
|
||||
|
||||
def test_get_empty_flavor_list_v1_1(self):
|
||||
def test_get_empty_flavor_list(self):
|
||||
self.stubs.Set(nova.db.api, "instance_type_get_all",
|
||||
empty_instance_type_get_all)
|
||||
|
||||
@@ -303,10 +226,9 @@ class FlavorsTest(test.TestCase):
|
||||
expected = []
|
||||
self.assertEqual(flavors, expected)
|
||||
|
||||
def test_get_flavor_list_filter_min_ram_v1_1(self):
|
||||
def test_get_flavor_list_filter_min_ram(self):
|
||||
"""Flavor lists may be filtered by minRam"""
|
||||
req = webob.Request.blank('/v1.1/fake/flavors?minRam=512')
|
||||
req.environ['api.version'] = '1.1'
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 200)
|
||||
flavor = json.loads(res.body)
|
||||
@@ -333,7 +255,6 @@ class FlavorsTest(test.TestCase):
|
||||
def test_get_flavor_list_filter_min_disk(self):
|
||||
"""Flavor lists may be filtered by minRam"""
|
||||
req = webob.Request.blank('/v1.1/fake/flavors?minDisk=20')
|
||||
req.environ['api.version'] = '1.1'
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 200)
|
||||
flavor = json.loads(res.body)
|
||||
@@ -357,13 +278,12 @@ class FlavorsTest(test.TestCase):
|
||||
}
|
||||
self.assertEqual(flavor, expected)
|
||||
|
||||
def test_get_flavor_list_detail_min_ram_and_min_disk_v1_1(self):
|
||||
def test_get_flavor_list_detail_min_ram_and_min_disk(self):
|
||||
"""Tests that filtering work on flavor details and that minRam and
|
||||
minDisk filters can be combined
|
||||
"""
|
||||
req = webob.Request.blank(
|
||||
'/v1.1/fake/flavors/detail?minRam=256&minDisk=20')
|
||||
req.environ['api.version'] = '1.1'
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 200)
|
||||
flavor = json.loads(res.body)
|
||||
@@ -393,11 +313,10 @@ class FlavorsTest(test.TestCase):
|
||||
}
|
||||
self.assertEqual(flavor, expected)
|
||||
|
||||
def test_get_flavor_list_detail_bogus_min_ram_v1_1(self):
|
||||
def test_get_flavor_list_detail_bogus_min_ram(self):
|
||||
"""Tests that bogus minRam filtering values are ignored"""
|
||||
req = webob.Request.blank(
|
||||
'/v1.1/fake/flavors/detail?minRam=16GB')
|
||||
req.environ['api.version'] = '1.1'
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 200)
|
||||
flavor = json.loads(res.body)
|
||||
@@ -447,11 +366,10 @@ class FlavorsTest(test.TestCase):
|
||||
}
|
||||
self.assertEqual(flavor, expected)
|
||||
|
||||
def test_get_flavor_list_detail_bogus_min_disk_v1_1(self):
|
||||
def test_get_flavor_list_detail_bogus_min_disk(self):
|
||||
"""Tests that bogus minDisk filtering values are ignored"""
|
||||
req = webob.Request.blank(
|
||||
'/v1.1/fake/flavors/detail?minDisk=16GB')
|
||||
req.environ['api.version'] = '1.1'
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 200)
|
||||
flavor = json.loads(res.body)
|
||||
|
@@ -71,48 +71,7 @@ class ImagesTest(test.TestCase):
|
||||
auth_token = True
|
||||
return Context()
|
||||
|
||||
def test_get_image_index(self):
|
||||
request = webob.Request.blank('/v1.0/images')
|
||||
app = fakes.wsgi_app(fake_auth_context=self._get_fake_context())
|
||||
response = request.get_response(app)
|
||||
|
||||
response_dict = json.loads(response.body)
|
||||
response_list = response_dict["images"]
|
||||
|
||||
expected = [{'id': 123, 'name': 'public image'},
|
||||
{'id': 124, 'name': 'queued snapshot'},
|
||||
{'id': 125, 'name': 'saving snapshot'},
|
||||
{'id': 126, 'name': 'active snapshot'},
|
||||
{'id': 127, 'name': 'killed snapshot'},
|
||||
{'id': 128, 'name': 'deleted snapshot'},
|
||||
{'id': 129, 'name': 'pending_delete snapshot'},
|
||||
{'id': 130, 'name': None}]
|
||||
|
||||
self.assertDictListMatch(response_list, expected)
|
||||
|
||||
def test_get_image(self):
|
||||
request = webob.Request.blank('/v1.0/images/123')
|
||||
app = fakes.wsgi_app(fake_auth_context=self._get_fake_context())
|
||||
response = request.get_response(app)
|
||||
|
||||
self.assertEqual(200, response.status_int)
|
||||
|
||||
actual_image = json.loads(response.body)
|
||||
|
||||
expected_image = {
|
||||
"image": {
|
||||
"id": 123,
|
||||
"name": "public image",
|
||||
"updated": NOW_API_FORMAT,
|
||||
"created": NOW_API_FORMAT,
|
||||
"status": "ACTIVE",
|
||||
"progress": 100,
|
||||
},
|
||||
}
|
||||
|
||||
self.assertDictMatch(expected_image, actual_image)
|
||||
|
||||
def test_get_image_v1_1(self):
|
||||
self.maxDiff = None
|
||||
request = webob.Request.blank('/v1.1/fake/images/124')
|
||||
app = fakes.wsgi_app(fake_auth_context=self._get_fake_context())
|
||||
@@ -169,82 +128,7 @@ class ImagesTest(test.TestCase):
|
||||
|
||||
self.assertEqual(expected_image, actual_image)
|
||||
|
||||
def test_get_image_xml(self):
|
||||
request = webob.Request.blank('/v1.0/images/123')
|
||||
request.accept = "application/xml"
|
||||
app = fakes.wsgi_app(fake_auth_context=self._get_fake_context())
|
||||
response = request.get_response(app)
|
||||
|
||||
actual_image = minidom.parseString(response.body.replace(" ", ""))
|
||||
|
||||
expected_now = NOW_API_FORMAT
|
||||
expected_image = minidom.parseString("""
|
||||
<image id="123"
|
||||
name="public image"
|
||||
updated="%(expected_now)s"
|
||||
created="%(expected_now)s"
|
||||
status="ACTIVE"
|
||||
progress="100"
|
||||
xmlns="http://docs.rackspacecloud.com/servers/api/v1.0" />
|
||||
""" % (locals()))
|
||||
|
||||
self.assertEqual(expected_image.toxml(), actual_image.toxml())
|
||||
|
||||
def test_get_image_xml_no_name(self):
|
||||
request = webob.Request.blank('/v1.0/images/130')
|
||||
request.accept = "application/xml"
|
||||
app = fakes.wsgi_app(fake_auth_context=self._get_fake_context())
|
||||
response = request.get_response(app)
|
||||
|
||||
actual_image = minidom.parseString(response.body.replace(" ", ""))
|
||||
|
||||
expected_now = NOW_API_FORMAT
|
||||
expected_image = minidom.parseString("""
|
||||
<image id="130"
|
||||
name="None"
|
||||
updated="%(expected_now)s"
|
||||
created="%(expected_now)s"
|
||||
status="ACTIVE"
|
||||
progress="100"
|
||||
xmlns="http://docs.rackspacecloud.com/servers/api/v1.0" />
|
||||
""" % (locals()))
|
||||
|
||||
self.assertEqual(expected_image.toxml(), actual_image.toxml())
|
||||
|
||||
def test_get_image_404_json(self):
|
||||
request = webob.Request.blank('/v1.0/images/NonExistantImage')
|
||||
response = request.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(404, response.status_int)
|
||||
|
||||
expected = {
|
||||
"itemNotFound": {
|
||||
"message": "Image not found.",
|
||||
"code": 404,
|
||||
},
|
||||
}
|
||||
|
||||
actual = json.loads(response.body)
|
||||
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
def test_get_image_404_xml(self):
|
||||
request = webob.Request.blank('/v1.0/images/NonExistantImage')
|
||||
request.accept = "application/xml"
|
||||
response = request.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(404, response.status_int)
|
||||
|
||||
expected = minidom.parseString("""
|
||||
<itemNotFound code="404"
|
||||
xmlns="http://docs.rackspacecloud.com/servers/api/v1.0">
|
||||
<message>Image not found.</message>
|
||||
</itemNotFound>
|
||||
""".replace(" ", "").replace("\n", ""))
|
||||
|
||||
actual = minidom.parseString(response.body.replace(" ", ""))
|
||||
|
||||
self.assertEqual(expected.toxml(), actual.toxml())
|
||||
|
||||
def test_get_image_404_v1_1_json(self):
|
||||
request = webob.Request.blank('/v1.1/fake/images/NonExistantImage')
|
||||
response = request.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(404, response.status_int)
|
||||
@@ -260,7 +144,7 @@ class ImagesTest(test.TestCase):
|
||||
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
def test_get_image_404_v1_1_xml(self):
|
||||
def test_get_image_404_xml(self):
|
||||
request = webob.Request.blank('/v1.1/fake/images/NonExistantImage')
|
||||
request.accept = "application/xml"
|
||||
response = request.get_response(fakes.wsgi_app())
|
||||
@@ -279,7 +163,7 @@ class ImagesTest(test.TestCase):
|
||||
|
||||
self.assertEqual(expected.toxml(), actual.toxml())
|
||||
|
||||
def test_get_image_index_v1_1(self):
|
||||
def test_get_image_index(self):
|
||||
request = webob.Request.blank('/v1.1/fake/images')
|
||||
app = fakes.wsgi_app(fake_auth_context=self._get_fake_context())
|
||||
response = request.get_response(app)
|
||||
@@ -454,7 +338,7 @@ class ImagesTest(test.TestCase):
|
||||
|
||||
self.assertDictListMatch(response_list, expected_images)
|
||||
|
||||
def test_get_image_index_v1_1_with_limit(self):
|
||||
def test_get_image_index_with_limit(self):
|
||||
request = webob.Request.blank('/v1.1/fake/images?limit=3')
|
||||
app = fakes.wsgi_app(fake_auth_context=self._get_fake_context())
|
||||
response = request.get_response(app)
|
||||
@@ -533,7 +417,7 @@ class ImagesTest(test.TestCase):
|
||||
params = urlparse.parse_qs(href_parts.query)
|
||||
self.assertDictMatch({'limit': ['3'], 'marker': ['125']}, params)
|
||||
|
||||
def test_get_image_index_v1_1_with_limit_and_extra_params(self):
|
||||
def test_get_image_index_with_limit_and_extra_params(self):
|
||||
request = webob.Request.blank('/v1.1/fake/images?limit=3&extra=boo')
|
||||
app = fakes.wsgi_app(fake_auth_context=self._get_fake_context())
|
||||
response = request.get_response(app)
|
||||
@@ -550,7 +434,7 @@ class ImagesTest(test.TestCase):
|
||||
{'limit': ['3'], 'marker': ['125'], 'extra': ['boo']},
|
||||
params)
|
||||
|
||||
def test_get_image_index_v1_1_with_big_limit(self):
|
||||
def test_get_image_index_with_big_limit(self):
|
||||
"""
|
||||
Make sure we don't get images_links if limit is set
|
||||
and the number of images returned is < limit
|
||||
@@ -566,81 +450,6 @@ class ImagesTest(test.TestCase):
|
||||
self.assertEqual(len(response_list), 8)
|
||||
|
||||
def test_get_image_details(self):
|
||||
request = webob.Request.blank('/v1.0/images/detail')
|
||||
app = fakes.wsgi_app(fake_auth_context=self._get_fake_context())
|
||||
response = request.get_response(app)
|
||||
|
||||
response_dict = json.loads(response.body)
|
||||
response_list = response_dict["images"]
|
||||
|
||||
expected = [{
|
||||
'id': 123,
|
||||
'name': 'public image',
|
||||
'updated': NOW_API_FORMAT,
|
||||
'created': NOW_API_FORMAT,
|
||||
'status': 'ACTIVE',
|
||||
'progress': 100,
|
||||
},
|
||||
{
|
||||
'id': 124,
|
||||
'name': 'queued snapshot',
|
||||
'updated': NOW_API_FORMAT,
|
||||
'created': NOW_API_FORMAT,
|
||||
'status': 'SAVING',
|
||||
'progress': 25,
|
||||
},
|
||||
{
|
||||
'id': 125,
|
||||
'name': 'saving snapshot',
|
||||
'updated': NOW_API_FORMAT,
|
||||
'created': NOW_API_FORMAT,
|
||||
'status': 'SAVING',
|
||||
'progress': 50,
|
||||
},
|
||||
{
|
||||
'id': 126,
|
||||
'name': 'active snapshot',
|
||||
'updated': NOW_API_FORMAT,
|
||||
'created': NOW_API_FORMAT,
|
||||
'status': 'ACTIVE',
|
||||
'progress': 100,
|
||||
},
|
||||
{
|
||||
'id': 127,
|
||||
'name': 'killed snapshot',
|
||||
'updated': NOW_API_FORMAT,
|
||||
'created': NOW_API_FORMAT,
|
||||
'status': 'ERROR',
|
||||
'progress': 0,
|
||||
},
|
||||
{
|
||||
'id': 128,
|
||||
'name': 'deleted snapshot',
|
||||
'updated': NOW_API_FORMAT,
|
||||
'created': NOW_API_FORMAT,
|
||||
'status': 'DELETED',
|
||||
'progress': 0,
|
||||
},
|
||||
{
|
||||
'id': 129,
|
||||
'name': 'pending_delete snapshot',
|
||||
'updated': NOW_API_FORMAT,
|
||||
'created': NOW_API_FORMAT,
|
||||
'status': 'DELETED',
|
||||
'progress': 0,
|
||||
},
|
||||
{
|
||||
'id': 130,
|
||||
'name': None,
|
||||
'updated': NOW_API_FORMAT,
|
||||
'created': NOW_API_FORMAT,
|
||||
'status': 'ACTIVE',
|
||||
'progress': 100,
|
||||
}]
|
||||
|
||||
self.assertDictListMatch(expected, response_list)
|
||||
|
||||
def test_get_image_details_v1_1(self):
|
||||
request = webob.Request.blank('/v1.1/fake/images/detail')
|
||||
app = fakes.wsgi_app(fake_auth_context=self._get_fake_context())
|
||||
response = request.get_response(app)
|
||||
@@ -931,7 +740,7 @@ class ImagesTest(test.TestCase):
|
||||
|
||||
self.assertDictListMatch(expected, response_list)
|
||||
|
||||
def test_get_image_details_with_limit_v1_1(self):
|
||||
def test_get_image_details_with_limit(self):
|
||||
request = webob.Request.blank('/v1.1/fake/images/detail?limit=2')
|
||||
app = fakes.wsgi_app(fake_auth_context=self._get_fake_context())
|
||||
response = request.get_response(app)
|
||||
@@ -1022,7 +831,7 @@ class ImagesTest(test.TestCase):
|
||||
self.mox.ReplayAll()
|
||||
request = webob.Request.blank('/v1.1/images?name=testname')
|
||||
request.environ['nova.context'] = context
|
||||
controller = images.ControllerV11(image_service=image_service)
|
||||
controller = images.Controller(image_service=image_service)
|
||||
controller.index(request)
|
||||
self.mox.VerifyAll()
|
||||
|
||||
@@ -1034,7 +843,7 @@ class ImagesTest(test.TestCase):
|
||||
self.mox.ReplayAll()
|
||||
request = webob.Request.blank('/v1.1/images?minRam=0')
|
||||
request.environ['nova.context'] = context
|
||||
controller = images.ControllerV11(image_service=image_service)
|
||||
controller = images.Controller(image_service=image_service)
|
||||
controller.index(request)
|
||||
self.mox.VerifyAll()
|
||||
|
||||
@@ -1046,7 +855,7 @@ class ImagesTest(test.TestCase):
|
||||
self.mox.ReplayAll()
|
||||
request = webob.Request.blank('/v1.1/images?minDisk=7')
|
||||
request.environ['nova.context'] = context
|
||||
controller = images.ControllerV11(image_service=image_service)
|
||||
controller = images.Controller(image_service=image_service)
|
||||
controller.index(request)
|
||||
self.mox.VerifyAll()
|
||||
|
||||
@@ -1058,7 +867,7 @@ class ImagesTest(test.TestCase):
|
||||
self.mox.ReplayAll()
|
||||
request = webob.Request.blank('/v1.1/images?status=ACTIVE')
|
||||
request.environ['nova.context'] = context
|
||||
controller = images.ControllerV11(image_service=image_service)
|
||||
controller = images.Controller(image_service=image_service)
|
||||
controller.index(request)
|
||||
self.mox.VerifyAll()
|
||||
|
||||
@@ -1070,7 +879,7 @@ class ImagesTest(test.TestCase):
|
||||
self.mox.ReplayAll()
|
||||
request = webob.Request.blank('/v1.1/images?property-test=3')
|
||||
request.environ['nova.context'] = context
|
||||
controller = images.ControllerV11(image_service=image_service)
|
||||
controller = images.Controller(image_service=image_service)
|
||||
controller.index(request)
|
||||
self.mox.VerifyAll()
|
||||
|
||||
@@ -1084,7 +893,7 @@ class ImagesTest(test.TestCase):
|
||||
request = webob.Request.blank('/v1.1/images?server='
|
||||
'http://localhost:8774/servers/12')
|
||||
request.environ['nova.context'] = context
|
||||
controller = images.ControllerV11(image_service=image_service)
|
||||
controller = images.Controller(image_service=image_service)
|
||||
controller.index(request)
|
||||
self.mox.VerifyAll()
|
||||
|
||||
@@ -1097,7 +906,7 @@ class ImagesTest(test.TestCase):
|
||||
request = webob.Request.blank('/v1.1/images?changes-since='
|
||||
'2011-01-24T17:08Z')
|
||||
request.environ['nova.context'] = context
|
||||
controller = images.ControllerV11(image_service=image_service)
|
||||
controller = images.Controller(image_service=image_service)
|
||||
controller.index(request)
|
||||
self.mox.VerifyAll()
|
||||
|
||||
@@ -1109,7 +918,7 @@ class ImagesTest(test.TestCase):
|
||||
self.mox.ReplayAll()
|
||||
request = webob.Request.blank('/v1.1/images?type=BASE')
|
||||
request.environ['nova.context'] = context
|
||||
controller = images.ControllerV11(image_service=image_service)
|
||||
controller = images.Controller(image_service=image_service)
|
||||
controller.index(request)
|
||||
self.mox.VerifyAll()
|
||||
|
||||
@@ -1122,7 +931,7 @@ class ImagesTest(test.TestCase):
|
||||
request = webob.Request.blank('/v1.1/images?status=ACTIVE&'
|
||||
'UNSUPPORTEDFILTER=testname')
|
||||
request.environ['nova.context'] = context
|
||||
controller = images.ControllerV11(image_service=image_service)
|
||||
controller = images.Controller(image_service=image_service)
|
||||
controller.detail(request)
|
||||
self.mox.VerifyAll()
|
||||
|
||||
@@ -1136,7 +945,7 @@ class ImagesTest(test.TestCase):
|
||||
request = webob.Request.blank(
|
||||
'/v1.1/images')
|
||||
request.environ['nova.context'] = context
|
||||
controller = images.ControllerV11(image_service=image_service)
|
||||
controller = images.Controller(image_service=image_service)
|
||||
controller.index(request)
|
||||
self.mox.VerifyAll()
|
||||
|
||||
@@ -1148,7 +957,7 @@ class ImagesTest(test.TestCase):
|
||||
self.mox.ReplayAll()
|
||||
request = webob.Request.blank('/v1.1/fake/images/detail?name=testname')
|
||||
request.environ['nova.context'] = context
|
||||
controller = images.ControllerV11(image_service=image_service)
|
||||
controller = images.Controller(image_service=image_service)
|
||||
controller.detail(request)
|
||||
self.mox.VerifyAll()
|
||||
|
||||
@@ -1160,7 +969,7 @@ class ImagesTest(test.TestCase):
|
||||
self.mox.ReplayAll()
|
||||
request = webob.Request.blank('/v1.1/fake/images/detail?status=ACTIVE')
|
||||
request.environ['nova.context'] = context
|
||||
controller = images.ControllerV11(image_service=image_service)
|
||||
controller = images.Controller(image_service=image_service)
|
||||
controller.detail(request)
|
||||
self.mox.VerifyAll()
|
||||
|
||||
@@ -1173,7 +982,7 @@ class ImagesTest(test.TestCase):
|
||||
request = webob.Request.blank(
|
||||
'/v1.1/fake/images/detail?property-test=3')
|
||||
request.environ['nova.context'] = context
|
||||
controller = images.ControllerV11(image_service=image_service)
|
||||
controller = images.Controller(image_service=image_service)
|
||||
controller.detail(request)
|
||||
self.mox.VerifyAll()
|
||||
|
||||
@@ -1187,7 +996,7 @@ class ImagesTest(test.TestCase):
|
||||
request = webob.Request.blank('/v1.1/fake/images/detail?server='
|
||||
'http://localhost:8774/servers/12')
|
||||
request.environ['nova.context'] = context
|
||||
controller = images.ControllerV11(image_service=image_service)
|
||||
controller = images.Controller(image_service=image_service)
|
||||
controller.index(request)
|
||||
self.mox.VerifyAll()
|
||||
|
||||
@@ -1200,7 +1009,7 @@ class ImagesTest(test.TestCase):
|
||||
request = webob.Request.blank('/v1.1/fake/images/detail?changes-since='
|
||||
'2011-01-24T17:08Z')
|
||||
request.environ['nova.context'] = context
|
||||
controller = images.ControllerV11(image_service=image_service)
|
||||
controller = images.Controller(image_service=image_service)
|
||||
controller.index(request)
|
||||
self.mox.VerifyAll()
|
||||
|
||||
@@ -1212,7 +1021,7 @@ class ImagesTest(test.TestCase):
|
||||
self.mox.ReplayAll()
|
||||
request = webob.Request.blank('/v1.1/fake/images/detail?type=BASE')
|
||||
request.environ['nova.context'] = context
|
||||
controller = images.ControllerV11(image_service=image_service)
|
||||
controller = images.Controller(image_service=image_service)
|
||||
controller.index(request)
|
||||
self.mox.VerifyAll()
|
||||
|
||||
@@ -1225,7 +1034,7 @@ class ImagesTest(test.TestCase):
|
||||
request = webob.Request.blank('/v1.1/fake/images/detail?status=ACTIVE&'
|
||||
'UNSUPPORTEDFILTER=testname')
|
||||
request.environ['nova.context'] = context
|
||||
controller = images.ControllerV11(image_service=image_service)
|
||||
controller = images.Controller(image_service=image_service)
|
||||
controller.detail(request)
|
||||
self.mox.VerifyAll()
|
||||
|
||||
@@ -1237,82 +1046,24 @@ class ImagesTest(test.TestCase):
|
||||
self.mox.ReplayAll()
|
||||
request = webob.Request.blank('/v1.1/fake/images/detail')
|
||||
request.environ['nova.context'] = context
|
||||
controller = images.ControllerV11(image_service=image_service)
|
||||
controller = images.Controller(image_service=image_service)
|
||||
controller.detail(request)
|
||||
self.mox.VerifyAll()
|
||||
|
||||
def test_get_image_found(self):
|
||||
req = webob.Request.blank('/v1.0/images/123')
|
||||
app = fakes.wsgi_app(fake_auth_context=self._get_fake_context())
|
||||
res = req.get_response(app)
|
||||
image_meta = json.loads(res.body)['image']
|
||||
expected = {'id': 123, 'name': 'public image',
|
||||
'updated': NOW_API_FORMAT,
|
||||
'created': NOW_API_FORMAT, 'status': 'ACTIVE',
|
||||
'progress': 100}
|
||||
self.assertDictMatch(image_meta, expected)
|
||||
|
||||
def test_get_image_non_existent(self):
|
||||
req = webob.Request.blank('/v1.0/images/4242')
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 404)
|
||||
|
||||
def test_create_image(self):
|
||||
body = dict(image=dict(serverId='123', name='Snapshot 1'))
|
||||
req = webob.Request.blank('/v1.0/images')
|
||||
req.method = 'POST'
|
||||
req.body = json.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
response = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(200, response.status_int)
|
||||
image_meta = json.loads(response.body)['image']
|
||||
self.assertEqual(123, image_meta['serverId'])
|
||||
self.assertEqual('Snapshot 1', image_meta['name'])
|
||||
|
||||
def test_create_snapshot_no_name(self):
|
||||
"""Name is required for snapshots"""
|
||||
body = dict(image=dict(serverId='123'))
|
||||
req = webob.Request.blank('/v1.0/images')
|
||||
req.method = 'POST'
|
||||
req.body = json.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
response = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(400, response.status_int)
|
||||
|
||||
def test_create_image_no_server_id(self):
|
||||
|
||||
body = dict(image=dict(name='Snapshot 1'))
|
||||
req = webob.Request.blank('/v1.0/images')
|
||||
req.method = 'POST'
|
||||
req.body = json.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
response = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(400, response.status_int)
|
||||
|
||||
def test_create_image_snapshots_disabled(self):
|
||||
self.flags(allow_instance_snapshots=False)
|
||||
body = dict(image=dict(serverId='123', name='Snapshot 1'))
|
||||
req = webob.Request.blank('/v1.0/images')
|
||||
req.method = 'POST'
|
||||
req.body = json.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
response = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(400, response.status_int)
|
||||
|
||||
def test_generate_alternate(self):
|
||||
view = images_view.ViewBuilderV11(1)
|
||||
def test_generate_alternate_link(self):
|
||||
view = images_view.ViewBuilder(1)
|
||||
generated_url = view.generate_alternate(1)
|
||||
actual_url = "%s//images/1" % utils.generate_glance_url()
|
||||
self.assertEqual(generated_url, actual_url)
|
||||
|
||||
def test_delete_image_v1_1(self):
|
||||
def test_delete_image(self):
|
||||
request = webob.Request.blank('/v1.1/fake/images/124')
|
||||
request.method = 'DELETE'
|
||||
app = fakes.wsgi_app(fake_auth_context=self._get_fake_context())
|
||||
response = request.get_response(app)
|
||||
self.assertEqual(response.status_int, 204)
|
||||
|
||||
def test_delete_image_not_found_v1_1(self):
|
||||
def test_delete_image_not_found(self):
|
||||
request = webob.Request.blank('/v1.1/fake/images/300')
|
||||
request.method = 'DELETE'
|
||||
app = fakes.wsgi_app(fake_auth_context=self._get_fake_context())
|
||||
|
@@ -72,149 +72,15 @@ class BaseLimitTestSuite(unittest.TestCase):
|
||||
return self.time
|
||||
|
||||
|
||||
class LimitsControllerV10Test(BaseLimitTestSuite):
|
||||
class LimitsControllerTest(BaseLimitTestSuite):
|
||||
"""
|
||||
Tests for `limits.LimitsControllerV10` class.
|
||||
Tests for `limits.LimitsController` class.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
"""Run before each test."""
|
||||
BaseLimitTestSuite.setUp(self)
|
||||
self.controller = limits.create_resource('1.0')
|
||||
|
||||
def _get_index_request(self, accept_header="application/json"):
|
||||
"""Helper to set routing arguments."""
|
||||
request = webob.Request.blank("/")
|
||||
request.accept = accept_header
|
||||
request.environ["wsgiorg.routing_args"] = (None, {
|
||||
"action": "index",
|
||||
"controller": "",
|
||||
})
|
||||
context = nova.context.RequestContext('testuser', 'testproject')
|
||||
request.environ["nova.context"] = context
|
||||
return request
|
||||
|
||||
def _populate_limits(self, request):
|
||||
"""Put limit info into a request."""
|
||||
_limits = [
|
||||
limits.Limit("GET", "*", ".*", 10, 60).display(),
|
||||
limits.Limit("POST", "*", ".*", 5, 60 * 60).display(),
|
||||
]
|
||||
request.environ["nova.limits"] = _limits
|
||||
return request
|
||||
|
||||
def _setup_absolute_limits(self):
|
||||
self.absolute_limits = {
|
||||
'instances': 5,
|
||||
'cores': 8,
|
||||
'ram': 2 ** 13,
|
||||
'volumes': 21,
|
||||
'gigabytes': 34,
|
||||
'metadata_items': 55,
|
||||
'injected_files': 89,
|
||||
'injected_file_content_bytes': 144,
|
||||
}
|
||||
|
||||
def test_empty_index_json(self):
|
||||
"""Test getting empty limit details in JSON."""
|
||||
request = self._get_index_request()
|
||||
response = request.get_response(self.controller)
|
||||
expected = {
|
||||
"limits": {
|
||||
"rate": [],
|
||||
"absolute": {},
|
||||
},
|
||||
}
|
||||
body = json.loads(response.body)
|
||||
self.assertEqual(expected, body)
|
||||
|
||||
def test_index_json(self):
|
||||
"""Test getting limit details in JSON."""
|
||||
request = self._get_index_request()
|
||||
request = self._populate_limits(request)
|
||||
self._setup_absolute_limits()
|
||||
response = request.get_response(self.controller)
|
||||
expected = {
|
||||
"limits": {
|
||||
"rate": [{
|
||||
"regex": ".*",
|
||||
"resetTime": 0,
|
||||
"URI": "*",
|
||||
"value": 10,
|
||||
"verb": "GET",
|
||||
"remaining": 10,
|
||||
"unit": "MINUTE",
|
||||
},
|
||||
{
|
||||
"regex": ".*",
|
||||
"resetTime": 0,
|
||||
"URI": "*",
|
||||
"value": 5,
|
||||
"verb": "POST",
|
||||
"remaining": 5,
|
||||
"unit": "HOUR",
|
||||
}],
|
||||
"absolute": {
|
||||
"maxTotalInstances": 5,
|
||||
"maxTotalCores": 8,
|
||||
"maxTotalRAMSize": 2 ** 13,
|
||||
"maxServerMeta": 55,
|
||||
"maxImageMeta": 55,
|
||||
"maxPersonality": 89,
|
||||
"maxPersonalitySize": 144,
|
||||
},
|
||||
},
|
||||
}
|
||||
body = json.loads(response.body)
|
||||
self.assertEqual(expected, body)
|
||||
|
||||
def test_empty_index_xml(self):
|
||||
"""Test getting limit details in XML."""
|
||||
request = self._get_index_request("application/xml")
|
||||
response = request.get_response(self.controller)
|
||||
|
||||
expected = minidom.parseString("""
|
||||
<limits xmlns="http://docs.rackspacecloud.com/servers/api/v1.0">
|
||||
<rate/>
|
||||
<absolute/>
|
||||
</limits>
|
||||
""".replace(" ", "").replace("\n", ""))
|
||||
|
||||
body = minidom.parseString(response.body.replace(" ", ""))
|
||||
|
||||
self.assertEqual(expected.toxml(), body.toxml())
|
||||
|
||||
def test_index_xml(self):
|
||||
"""Test getting limit details in XML."""
|
||||
request = self._get_index_request("application/xml")
|
||||
request = self._populate_limits(request)
|
||||
response = request.get_response(self.controller)
|
||||
|
||||
expected = minidom.parseString("""
|
||||
<limits xmlns="http://docs.rackspacecloud.com/servers/api/v1.0">
|
||||
<rate>
|
||||
<limit URI="*" regex=".*" remaining="10" resetTime="0"
|
||||
unit="MINUTE" value="10" verb="GET"/>
|
||||
<limit URI="*" regex=".*" remaining="5" resetTime="0"
|
||||
unit="HOUR" value="5" verb="POST"/>
|
||||
</rate>
|
||||
<absolute/>
|
||||
</limits>
|
||||
""".replace(" ", "").replace("\n", ""))
|
||||
body = minidom.parseString(response.body.replace(" ", ""))
|
||||
|
||||
self.assertEqual(expected.toxml(), body.toxml())
|
||||
|
||||
|
||||
class LimitsControllerV11Test(BaseLimitTestSuite):
|
||||
"""
|
||||
Tests for `limits.LimitsControllerV11` class.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
"""Run before each test."""
|
||||
BaseLimitTestSuite.setUp(self)
|
||||
self.controller = limits.create_resource('1.1')
|
||||
self.controller = limits.create_resource()
|
||||
self.maxDiff = None
|
||||
|
||||
def _get_index_request(self, accept_header="application/json"):
|
||||
@@ -915,10 +781,10 @@ class WsgiLimiterProxyTest(BaseLimitTestSuite):
|
||||
self.assertEqual((delay, error), expected)
|
||||
|
||||
|
||||
class LimitsViewBuilderV11Test(test.TestCase):
|
||||
class LimitsViewBuilderTest(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.view_builder = views.limits.ViewBuilderV11()
|
||||
self.view_builder = views.limits.ViewBuilder()
|
||||
self.rate_limits = [{"URI": "*",
|
||||
"regex": ".*",
|
||||
"value": 10,
|
||||
|
@@ -117,368 +117,7 @@ class ServerActionsTest(test.TestCase):
|
||||
def setUp(self):
|
||||
self.maxDiff = None
|
||||
super(ServerActionsTest, self).setUp()
|
||||
self.flags(verbose=True)
|
||||
self.stubs = stubout.StubOutForTesting()
|
||||
fakes.stub_out_auth(self.stubs)
|
||||
self.stubs.Set(nova.db.api, 'instance_get', return_server_by_id)
|
||||
self.stubs.Set(nova.db.api, 'instance_update', instance_update)
|
||||
|
||||
self.webreq = common.webob_factory('/v1.0/servers')
|
||||
|
||||
def tearDown(self):
|
||||
self.stubs.UnsetAll()
|
||||
|
||||
def test_server_change_password(self):
|
||||
body = {'changePassword': {'adminPass': '1234pass'}}
|
||||
req = webob.Request.blank('/v1.0/servers/1/action')
|
||||
req.method = 'POST'
|
||||
req.content_type = 'application/json'
|
||||
req.body = json.dumps(body)
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 501)
|
||||
|
||||
def test_server_change_password_xml(self):
|
||||
req = webob.Request.blank('/v1.0/servers/1/action')
|
||||
req.method = 'POST'
|
||||
req.content_type = 'application/xml'
|
||||
req.body = '<changePassword adminPass="1234pass">'
|
||||
# res = req.get_response(fakes.wsgi_app())
|
||||
# self.assertEqual(res.status_int, 501)
|
||||
|
||||
def test_server_reboot(self):
|
||||
body = dict(server=dict(
|
||||
name='server_test', imageId=2, flavorId=2, metadata={},
|
||||
personality={}))
|
||||
req = webob.Request.blank('/v1.0/servers/1/action')
|
||||
req.method = 'POST'
|
||||
req.content_type = 'application/json'
|
||||
req.body = json.dumps(body)
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
|
||||
def test_server_rebuild_accepted(self):
|
||||
body = {
|
||||
"rebuild": {
|
||||
"imageId": 2,
|
||||
},
|
||||
}
|
||||
|
||||
req = webob.Request.blank('/v1.0/servers/1/action')
|
||||
req.method = 'POST'
|
||||
req.content_type = 'application/json'
|
||||
req.body = json.dumps(body)
|
||||
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 202)
|
||||
self.assertEqual(res.body, "")
|
||||
|
||||
def test_server_rebuild_rejected_when_building(self):
|
||||
body = {
|
||||
"rebuild": {
|
||||
"imageId": 2,
|
||||
},
|
||||
}
|
||||
|
||||
state = vm_states.BUILDING
|
||||
new_return_server = return_server_with_state(state)
|
||||
self.stubs.Set(nova.db.api, 'instance_get', new_return_server)
|
||||
self.stubs.Set(nova.db, 'instance_get_by_uuid',
|
||||
return_server_with_uuid_and_state(state))
|
||||
|
||||
req = webob.Request.blank('/v1.0/servers/1/action')
|
||||
req.method = 'POST'
|
||||
req.content_type = 'application/json'
|
||||
req.body = json.dumps(body)
|
||||
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 409)
|
||||
|
||||
def test_server_rebuild_bad_entity(self):
|
||||
body = {
|
||||
"rebuild": {
|
||||
},
|
||||
}
|
||||
|
||||
req = webob.Request.blank('/v1.0/servers/1/action')
|
||||
req.method = 'POST'
|
||||
req.content_type = 'application/json'
|
||||
req.body = json.dumps(body)
|
||||
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 400)
|
||||
|
||||
def test_resize_server(self):
|
||||
req = self.webreq('/1/action', 'POST', dict(resize=dict(flavorId=3)))
|
||||
|
||||
self.resize_called = False
|
||||
|
||||
def resize_mock(*args):
|
||||
self.resize_called = True
|
||||
|
||||
self.stubs.Set(nova.compute.api.API, 'resize', resize_mock)
|
||||
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 202)
|
||||
self.assertEqual(self.resize_called, True)
|
||||
|
||||
def test_resize_bad_flavor_fails(self):
|
||||
req = self.webreq('/1/action', 'POST', dict(resize=dict(derp=3)))
|
||||
|
||||
self.resize_called = False
|
||||
|
||||
def resize_mock(*args):
|
||||
self.resize_called = True
|
||||
|
||||
self.stubs.Set(nova.compute.api.API, 'resize', resize_mock)
|
||||
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 400)
|
||||
self.assertEqual(self.resize_called, False)
|
||||
|
||||
def test_resize_raises_fails(self):
|
||||
req = self.webreq('/1/action', 'POST', dict(resize=dict(flavorId=3)))
|
||||
|
||||
def resize_mock(*args):
|
||||
raise Exception('hurr durr')
|
||||
|
||||
self.stubs.Set(nova.compute.api.API, 'resize', resize_mock)
|
||||
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 500)
|
||||
|
||||
def test_confirm_resize_server(self):
|
||||
req = self.webreq('/1/action', 'POST', dict(confirmResize=None))
|
||||
|
||||
self.resize_called = False
|
||||
|
||||
def confirm_resize_mock(*args):
|
||||
self.resize_called = True
|
||||
|
||||
self.stubs.Set(nova.compute.api.API, 'confirm_resize',
|
||||
confirm_resize_mock)
|
||||
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 204)
|
||||
self.assertEqual(self.resize_called, True)
|
||||
|
||||
def test_confirm_resize_server_fails(self):
|
||||
req = self.webreq('/1/action', 'POST', dict(confirmResize=None))
|
||||
|
||||
def confirm_resize_mock(*args):
|
||||
raise Exception('hurr durr')
|
||||
|
||||
self.stubs.Set(nova.compute.api.API, 'confirm_resize',
|
||||
confirm_resize_mock)
|
||||
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 400)
|
||||
|
||||
def test_confirm_resize_migration_not_found(self):
|
||||
req = self.webreq('/1/action', 'POST', dict(confirmResize=None))
|
||||
|
||||
def confirm_resize_mock(*args):
|
||||
raise exception.MigrationNotFoundByStatus(instance_id=1,
|
||||
status='finished')
|
||||
|
||||
self.stubs.Set(nova.compute.api.API,
|
||||
'confirm_resize',
|
||||
confirm_resize_mock)
|
||||
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 400)
|
||||
|
||||
def test_revert_resize_server(self):
|
||||
req = self.webreq('/1/action', 'POST', dict(revertResize=None))
|
||||
|
||||
self.resize_called = False
|
||||
|
||||
def revert_resize_mock(*args):
|
||||
self.resize_called = True
|
||||
|
||||
self.stubs.Set(nova.compute.api.API, 'revert_resize',
|
||||
revert_resize_mock)
|
||||
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 202)
|
||||
self.assertEqual(self.resize_called, True)
|
||||
|
||||
def test_revert_resize_server_fails(self):
|
||||
req = self.webreq('/1/action', 'POST', dict(revertResize=None))
|
||||
|
||||
def revert_resize_mock(*args):
|
||||
raise Exception('hurr durr')
|
||||
|
||||
self.stubs.Set(nova.compute.api.API, 'revert_resize',
|
||||
revert_resize_mock)
|
||||
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 400)
|
||||
|
||||
def test_revert_resize_migration_not_found(self):
|
||||
req = self.webreq('/1/action', 'POST', dict(revertResize=None))
|
||||
|
||||
def revert_resize_mock(*args):
|
||||
raise exception.MigrationNotFoundByStatus(instance_id=1,
|
||||
status='finished')
|
||||
|
||||
self.stubs.Set(nova.compute.api.API,
|
||||
'revert_resize',
|
||||
revert_resize_mock)
|
||||
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 400)
|
||||
|
||||
def test_create_backup(self):
|
||||
"""The happy path for creating backups"""
|
||||
self.flags(allow_admin_api=True)
|
||||
|
||||
body = {
|
||||
'createBackup': {
|
||||
'name': 'Backup 1',
|
||||
'backup_type': 'daily',
|
||||
'rotation': 1,
|
||||
},
|
||||
}
|
||||
|
||||
req = webob.Request.blank('/v1.0/servers/1/action')
|
||||
req.method = 'POST'
|
||||
req.body = json.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
response = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(202, response.status_int)
|
||||
self.assertTrue(response.headers['Location'])
|
||||
|
||||
def test_create_backup_admin_api_off(self):
|
||||
"""The happy path for creating backups"""
|
||||
self.flags(allow_admin_api=False)
|
||||
|
||||
body = {
|
||||
'createBackup': {
|
||||
'name': 'Backup 1',
|
||||
'backup_type': 'daily',
|
||||
'rotation': 1,
|
||||
},
|
||||
}
|
||||
|
||||
req = webob.Request.blank('/v1.0/servers/1/action')
|
||||
req.method = 'POST'
|
||||
req.body = json.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
response = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(400, response.status_int)
|
||||
|
||||
def test_create_backup_with_metadata(self):
|
||||
self.flags(allow_admin_api=True)
|
||||
|
||||
body = {
|
||||
'createBackup': {
|
||||
'name': 'Backup 1',
|
||||
'backup_type': 'daily',
|
||||
'rotation': 1,
|
||||
'metadata': {'123': 'asdf'},
|
||||
},
|
||||
}
|
||||
|
||||
req = webob.Request.blank('/v1.0/servers/1/action')
|
||||
req.method = 'POST'
|
||||
req.body = json.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
response = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(202, response.status_int)
|
||||
self.assertTrue(response.headers['Location'])
|
||||
|
||||
def test_create_backup_with_too_much_metadata(self):
|
||||
self.flags(allow_admin_api=True)
|
||||
|
||||
body = {
|
||||
'createBackup': {
|
||||
'name': 'Backup 1',
|
||||
'backup_type': 'daily',
|
||||
'rotation': 1,
|
||||
'metadata': {'123': 'asdf'},
|
||||
},
|
||||
}
|
||||
for num in range(FLAGS.quota_metadata_items + 1):
|
||||
body['createBackup']['metadata']['foo%i' % num] = "bar"
|
||||
req = webob.Request.blank('/v1.0/servers/1/action')
|
||||
req.method = 'POST'
|
||||
req.body = json.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
response = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(413, response.status_int)
|
||||
|
||||
def test_create_backup_no_name(self):
|
||||
"""Name is required for backups"""
|
||||
self.flags(allow_admin_api=True)
|
||||
|
||||
body = {
|
||||
'createBackup': {
|
||||
'backup_type': 'daily',
|
||||
'rotation': 1,
|
||||
},
|
||||
}
|
||||
|
||||
req = webob.Request.blank('/v1.0/images')
|
||||
req.method = 'POST'
|
||||
req.body = json.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
response = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(400, response.status_int)
|
||||
|
||||
def test_create_backup_no_rotation(self):
|
||||
"""Rotation is required for backup requests"""
|
||||
self.flags(allow_admin_api=True)
|
||||
|
||||
body = {
|
||||
'createBackup': {
|
||||
'name': 'Backup 1',
|
||||
'backup_type': 'daily',
|
||||
},
|
||||
}
|
||||
|
||||
req = webob.Request.blank('/v1.0/images')
|
||||
req.method = 'POST'
|
||||
req.body = json.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
|
||||
response = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(400, response.status_int)
|
||||
|
||||
def test_create_backup_no_backup_type(self):
|
||||
"""Backup Type (daily or weekly) is required for backup requests"""
|
||||
self.flags(allow_admin_api=True)
|
||||
|
||||
body = {
|
||||
'createBackup': {
|
||||
'name': 'Backup 1',
|
||||
'rotation': 1,
|
||||
},
|
||||
}
|
||||
req = webob.Request.blank('/v1.0/images')
|
||||
req.method = 'POST'
|
||||
req.body = json.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
|
||||
response = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(400, response.status_int)
|
||||
|
||||
def test_create_backup_bad_entity(self):
|
||||
self.flags(allow_admin_api=True)
|
||||
|
||||
body = {'createBackup': 'go'}
|
||||
req = webob.Request.blank('/v1.0/images')
|
||||
req.method = 'POST'
|
||||
req.body = json.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
|
||||
response = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(400, response.status_int)
|
||||
|
||||
|
||||
class ServerActionsTestV11(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.maxDiff = None
|
||||
super(ServerActionsTestV11, self).setUp()
|
||||
self.stubs = stubout.StubOutForTesting()
|
||||
fakes.stub_out_auth(self.stubs)
|
||||
self.stubs.Set(nova.db.api, 'instance_get', return_server_by_id)
|
||||
@@ -851,6 +490,42 @@ class ServerActionsTestV11(test.TestCase):
|
||||
self.assertEqual(res.status_int, 204)
|
||||
self.assertEqual(self.confirm_resize_called, True)
|
||||
|
||||
def test_confirm_resize_migration_not_found(self):
|
||||
req = webob.Request.blank('/v1.1/fake/servers/1/action')
|
||||
req.content_type = 'application/json'
|
||||
req.method = 'POST'
|
||||
body_dict = dict(confirmResize=None)
|
||||
req.body = json.dumps(body_dict)
|
||||
|
||||
def confirm_resize_mock(*args):
|
||||
raise exception.MigrationNotFoundByStatus(instance_id=1,
|
||||
status='finished')
|
||||
|
||||
self.stubs.Set(nova.compute.api.API,
|
||||
'confirm_resize',
|
||||
confirm_resize_mock)
|
||||
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 400)
|
||||
|
||||
def test_revert_resize_migration_not_found(self):
|
||||
req = webob.Request.blank('/v1.1/fake/servers/1/action')
|
||||
req.content_type = 'application/json'
|
||||
req.method = 'POST'
|
||||
body_dict = dict(revertResize=None)
|
||||
req.body = json.dumps(body_dict)
|
||||
|
||||
def revert_resize_mock(*args):
|
||||
raise exception.MigrationNotFoundByStatus(instance_id=1,
|
||||
status='finished')
|
||||
|
||||
self.stubs.Set(nova.compute.api.API,
|
||||
'revert_resize',
|
||||
revert_resize_mock)
|
||||
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 400)
|
||||
|
||||
def test_revert_resize_server(self):
|
||||
req = webob.Request.blank('/v1.1/fake/servers/1/action')
|
||||
req.content_type = 'application/json'
|
||||
@@ -978,11 +653,137 @@ class ServerActionsTestV11(test.TestCase):
|
||||
self.assertEqual(202, response.status_int)
|
||||
self.assertTrue(response.headers['Location'])
|
||||
|
||||
def test_create_backup_admin_api_off(self):
|
||||
"""The happy path for creating backups"""
|
||||
self.flags(allow_admin_api=False)
|
||||
|
||||
class TestServerActionXMLDeserializerV11(test.TestCase):
|
||||
body = {
|
||||
'createBackup': {
|
||||
'name': 'Backup 1',
|
||||
'backup_type': 'daily',
|
||||
'rotation': 1,
|
||||
},
|
||||
}
|
||||
|
||||
req = webob.Request.blank('/v1.1/fake/servers/1/action')
|
||||
req.method = 'POST'
|
||||
req.body = json.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
response = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(400, response.status_int)
|
||||
|
||||
def test_create_backup_with_metadata(self):
|
||||
self.flags(allow_admin_api=True)
|
||||
|
||||
body = {
|
||||
'createBackup': {
|
||||
'name': 'Backup 1',
|
||||
'backup_type': 'daily',
|
||||
'rotation': 1,
|
||||
'metadata': {'123': 'asdf'},
|
||||
},
|
||||
}
|
||||
|
||||
req = webob.Request.blank('/v1.1/fake/servers/1/action')
|
||||
req.method = 'POST'
|
||||
req.body = json.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
response = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(202, response.status_int)
|
||||
self.assertTrue(response.headers['Location'])
|
||||
|
||||
def test_create_backup_with_too_much_metadata(self):
|
||||
self.flags(allow_admin_api=True)
|
||||
|
||||
body = {
|
||||
'createBackup': {
|
||||
'name': 'Backup 1',
|
||||
'backup_type': 'daily',
|
||||
'rotation': 1,
|
||||
'metadata': {'123': 'asdf'},
|
||||
},
|
||||
}
|
||||
for num in range(FLAGS.quota_metadata_items + 1):
|
||||
body['createBackup']['metadata']['foo%i' % num] = "bar"
|
||||
req = webob.Request.blank('/v1.1/fake/servers/1/action')
|
||||
req.method = 'POST'
|
||||
req.body = json.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
response = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(413, response.status_int)
|
||||
|
||||
def test_create_backup_no_name(self):
|
||||
"""Name is required for backups"""
|
||||
self.flags(allow_admin_api=True)
|
||||
|
||||
body = {
|
||||
'createBackup': {
|
||||
'backup_type': 'daily',
|
||||
'rotation': 1,
|
||||
},
|
||||
}
|
||||
|
||||
req = webob.Request.blank('/v1.1/fake/servers/1/action')
|
||||
req.method = 'POST'
|
||||
req.body = json.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
response = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(400, response.status_int)
|
||||
|
||||
def test_create_backup_no_rotation(self):
|
||||
"""Rotation is required for backup requests"""
|
||||
self.flags(allow_admin_api=True)
|
||||
|
||||
body = {
|
||||
'createBackup': {
|
||||
'name': 'Backup 1',
|
||||
'backup_type': 'daily',
|
||||
},
|
||||
}
|
||||
|
||||
req = webob.Request.blank('/v1.1/fake/servers/1/action')
|
||||
req.method = 'POST'
|
||||
req.body = json.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
|
||||
response = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(400, response.status_int)
|
||||
|
||||
def test_create_backup_no_backup_type(self):
|
||||
"""Backup Type (daily or weekly) is required for backup requests"""
|
||||
self.flags(allow_admin_api=True)
|
||||
|
||||
body = {
|
||||
'createBackup': {
|
||||
'name': 'Backup 1',
|
||||
'rotation': 1,
|
||||
},
|
||||
}
|
||||
req = webob.Request.blank('/v1.1/fake/servers/1/action')
|
||||
req.method = 'POST'
|
||||
req.body = json.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
|
||||
response = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(400, response.status_int)
|
||||
|
||||
def test_create_backup_bad_entity(self):
|
||||
self.flags(allow_admin_api=True)
|
||||
|
||||
body = {'createBackup': 'go'}
|
||||
req = webob.Request.blank('/v1.1/fake/servers/1/action')
|
||||
req.method = 'POST'
|
||||
req.body = json.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
|
||||
response = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(400, response.status_int)
|
||||
|
||||
|
||||
class TestServerActionXMLDeserializer(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.deserializer = servers.ServerXMLDeserializerV11()
|
||||
self.deserializer = servers.ServerXMLDeserializer()
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,51 +0,0 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2010 OpenStack LLC.
|
||||
# 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 webob
|
||||
|
||||
from nova import test
|
||||
from nova.tests.api.openstack import fakes
|
||||
|
||||
|
||||
class SharedIpGroupsTest(test.TestCase):
|
||||
def test_get_shared_ip_groups(self):
|
||||
req = webob.Request.blank('/v1.0/shared_ip_groups')
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 501)
|
||||
|
||||
def test_create_shared_ip_group(self):
|
||||
req = webob.Request.blank('/v1.0/shared_ip_groups')
|
||||
req.method = 'POST'
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 501)
|
||||
|
||||
def test_update_shared_ip_group(self):
|
||||
req = webob.Request.blank('/v1.0/shared_ip_groups/12')
|
||||
req.method = 'PUT'
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 501)
|
||||
|
||||
def test_delete_shared_ip_group(self):
|
||||
req = webob.Request.blank('/v1.0/shared_ip_groups/12')
|
||||
req.method = 'DELETE'
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 501)
|
||||
|
||||
def test_deprecated_v11(self):
|
||||
req = webob.Request.blank('/v1.1/shared_ip_groups')
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 404)
|
@@ -28,16 +28,6 @@ class UrlmapTest(test.TestCase):
|
||||
super(UrlmapTest, self).setUp()
|
||||
fakes.stub_out_rate_limiting(self.stubs)
|
||||
|
||||
def test_path_version_v1_0(self):
|
||||
"""Test URL path specifying v1.0 returns v1.0 content."""
|
||||
req = webob.Request.blank('/v1.0/')
|
||||
req.accept = "application/json"
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 200)
|
||||
self.assertEqual(res.content_type, "application/json")
|
||||
body = json.loads(res.body)
|
||||
self.assertEqual(body['version']['id'], 'v1.0')
|
||||
|
||||
def test_path_version_v1_1(self):
|
||||
"""Test URL path specifying v1.1 returns v1.1 content."""
|
||||
req = webob.Request.blank('/v1.1/')
|
||||
@@ -48,17 +38,6 @@ class UrlmapTest(test.TestCase):
|
||||
body = json.loads(res.body)
|
||||
self.assertEqual(body['version']['id'], 'v1.1')
|
||||
|
||||
def test_content_type_version_v1_0(self):
|
||||
"""Test Content-Type specifying v1.0 returns v1.0 content."""
|
||||
req = webob.Request.blank('/')
|
||||
req.content_type = "application/json;version=1.0"
|
||||
req.accept = "application/json"
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 200)
|
||||
self.assertEqual(res.content_type, "application/json")
|
||||
body = json.loads(res.body)
|
||||
self.assertEqual(body['version']['id'], 'v1.0')
|
||||
|
||||
def test_content_type_version_v1_1(self):
|
||||
"""Test Content-Type specifying v1.1 returns v1.1 content."""
|
||||
req = webob.Request.blank('/')
|
||||
@@ -70,16 +49,6 @@ class UrlmapTest(test.TestCase):
|
||||
body = json.loads(res.body)
|
||||
self.assertEqual(body['version']['id'], 'v1.1')
|
||||
|
||||
def test_accept_version_v1_0(self):
|
||||
"""Test Accept header specifying v1.0 returns v1.0 content."""
|
||||
req = webob.Request.blank('/')
|
||||
req.accept = "application/json;version=1.0"
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 200)
|
||||
self.assertEqual(res.content_type, "application/json")
|
||||
body = json.loads(res.body)
|
||||
self.assertEqual(body['version']['id'], 'v1.0')
|
||||
|
||||
def test_accept_version_v1_1(self):
|
||||
"""Test Accept header specifying v1.1 returns v1.1 content."""
|
||||
req = webob.Request.blank('/')
|
||||
|
@@ -56,7 +56,7 @@ class UsersTest(test.TestCase):
|
||||
fakemgr.add_user(User('id2', 'guy2', 'acc2', 'secret2', True))
|
||||
|
||||
def test_get_user_list(self):
|
||||
req = webob.Request.blank('/v1.0/users')
|
||||
req = webob.Request.blank('/v1.1/fake/users')
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
res_dict = json.loads(res.body)
|
||||
|
||||
@@ -64,7 +64,7 @@ class UsersTest(test.TestCase):
|
||||
self.assertEqual(len(res_dict['users']), 2)
|
||||
|
||||
def test_get_user_by_id(self):
|
||||
req = webob.Request.blank('/v1.0/users/id2')
|
||||
req = webob.Request.blank('/v1.1/fake/users/id2')
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
res_dict = json.loads(res.body)
|
||||
|
||||
@@ -76,7 +76,7 @@ class UsersTest(test.TestCase):
|
||||
|
||||
def test_user_delete(self):
|
||||
# Check the user exists
|
||||
req = webob.Request.blank('/v1.0/users/id1')
|
||||
req = webob.Request.blank('/v1.1/fake/users/id1')
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
res_dict = json.loads(res.body)
|
||||
|
||||
@@ -84,7 +84,7 @@ class UsersTest(test.TestCase):
|
||||
self.assertEqual(res.status_int, 200)
|
||||
|
||||
# Delete the user
|
||||
req = webob.Request.blank('/v1.0/users/id1')
|
||||
req = webob.Request.blank('/v1.1/fake/users/id1')
|
||||
req.method = 'DELETE'
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertTrue('id1' not in [u.id for u in
|
||||
@@ -92,7 +92,7 @@ class UsersTest(test.TestCase):
|
||||
self.assertEqual(res.status_int, 200)
|
||||
|
||||
# Check the user is not returned (and returns 404)
|
||||
req = webob.Request.blank('/v1.0/users/id1')
|
||||
req = webob.Request.blank('/v1.1/fake/users/id1')
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
res_dict = json.loads(res.body)
|
||||
self.assertEqual(res.status_int, 404)
|
||||
@@ -103,7 +103,7 @@ class UsersTest(test.TestCase):
|
||||
access='acc3',
|
||||
secret=secret,
|
||||
admin=True))
|
||||
req = webob.Request.blank('/v1.0/users')
|
||||
req = webob.Request.blank('/v1.1/fake/users')
|
||||
req.headers["Content-Type"] = "application/json"
|
||||
req.method = 'POST'
|
||||
req.body = json.dumps(body)
|
||||
@@ -130,7 +130,7 @@ class UsersTest(test.TestCase):
|
||||
body = dict(user=dict(name='guy2',
|
||||
access='acc2',
|
||||
secret=new_secret))
|
||||
req = webob.Request.blank('/v1.0/users/id2')
|
||||
req = webob.Request.blank('/v1.1/fake/users/id2')
|
||||
req.headers["Content-Type"] = "application/json"
|
||||
req.method = 'PUT'
|
||||
req.body = json.dumps(body)
|
||||
|
@@ -35,35 +35,6 @@ NS = {
|
||||
'ns': 'http://docs.openstack.org/compute/api/v1.1'
|
||||
}
|
||||
VERSIONS = {
|
||||
"v1.0": {
|
||||
"id": "v1.0",
|
||||
"status": "DEPRECATED",
|
||||
"updated": "2011-01-21T11:33:21Z",
|
||||
"links": [
|
||||
{
|
||||
"rel": "describedby",
|
||||
"type": "application/pdf",
|
||||
"href": "http://docs.rackspacecloud.com/"
|
||||
"servers/api/v1.0/cs-devguide-20110125.pdf",
|
||||
},
|
||||
{
|
||||
"rel": "describedby",
|
||||
"type": "application/vnd.sun.wadl+xml",
|
||||
"href": "http://docs.rackspacecloud.com/"
|
||||
"servers/api/v1.0/application.wadl",
|
||||
},
|
||||
],
|
||||
"media-types": [
|
||||
{
|
||||
"base": "application/xml",
|
||||
"type": "application/vnd.openstack.compute+xml;version=1.0",
|
||||
},
|
||||
{
|
||||
"base": "application/json",
|
||||
"type": "application/vnd.openstack.compute+json;version=1.0",
|
||||
},
|
||||
],
|
||||
},
|
||||
"v1.1": {
|
||||
"id": "v1.1",
|
||||
"status": "CURRENT",
|
||||
@@ -118,16 +89,6 @@ class VersionsTest(test.TestCase):
|
||||
self.assertEqual(res.content_type, "application/json")
|
||||
versions = json.loads(res.body)["versions"]
|
||||
expected = [
|
||||
{
|
||||
"id": "v1.0",
|
||||
"status": "DEPRECATED",
|
||||
"updated": "2011-01-21T11:33:21Z",
|
||||
"links": [
|
||||
{
|
||||
"rel": "self",
|
||||
"href": "http://localhost/v1.0/",
|
||||
}],
|
||||
},
|
||||
{
|
||||
"id": "v1.1",
|
||||
"status": "CURRENT",
|
||||
@@ -141,52 +102,6 @@ class VersionsTest(test.TestCase):
|
||||
]
|
||||
self.assertEqual(versions, expected)
|
||||
|
||||
def test_get_version_1_0_detail(self):
|
||||
req = webob.Request.blank('/v1.0/')
|
||||
req.accept = "application/json"
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 200)
|
||||
self.assertEqual(res.content_type, "application/json")
|
||||
version = json.loads(res.body)
|
||||
expected = {
|
||||
"version": {
|
||||
"id": "v1.0",
|
||||
"status": "DEPRECATED",
|
||||
"updated": "2011-01-21T11:33:21Z",
|
||||
"links": [
|
||||
{
|
||||
"rel": "self",
|
||||
"href": "http://localhost/v1.0/",
|
||||
},
|
||||
{
|
||||
"rel": "describedby",
|
||||
"type": "application/pdf",
|
||||
"href": "http://docs.rackspacecloud.com/"
|
||||
"servers/api/v1.0/cs-devguide-20110125.pdf",
|
||||
},
|
||||
{
|
||||
"rel": "describedby",
|
||||
"type": "application/vnd.sun.wadl+xml",
|
||||
"href": "http://docs.rackspacecloud.com/"
|
||||
"servers/api/v1.0/application.wadl",
|
||||
},
|
||||
],
|
||||
"media-types": [
|
||||
{
|
||||
"base": "application/xml",
|
||||
"type": "application/"
|
||||
"vnd.openstack.compute+xml;version=1.0",
|
||||
},
|
||||
{
|
||||
"base": "application/json",
|
||||
"type": "application/"
|
||||
"vnd.openstack.compute+json;version=1.0",
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
self.assertEqual(expected, version)
|
||||
|
||||
def test_get_version_1_1_detail(self):
|
||||
req = webob.Request.blank('/v1.1/')
|
||||
req.accept = "application/json"
|
||||
@@ -279,29 +194,6 @@ class VersionsTest(test.TestCase):
|
||||
}
|
||||
self.assertEqual(expected, version)
|
||||
|
||||
def test_get_version_1_0_detail_xml(self):
|
||||
req = webob.Request.blank('/v1.0/')
|
||||
req.accept = "application/xml"
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 200)
|
||||
self.assertEqual(res.content_type, "application/xml")
|
||||
|
||||
version = etree.XML(res.body)
|
||||
xmlutil.validate_schema(version, 'version')
|
||||
|
||||
expected = VERSIONS['v1.0']
|
||||
self.assertTrue(version.xpath('/ns:version', namespaces=NS))
|
||||
media_types = version.xpath('ns:media-types/ns:media-type',
|
||||
namespaces=NS)
|
||||
self.assertTrue(common.compare_media_types(media_types,
|
||||
expected['media-types']))
|
||||
for key in ['id', 'status', 'updated']:
|
||||
self.assertEqual(version.get(key), expected[key])
|
||||
links = version.xpath('atom:link', namespaces=NS)
|
||||
self.assertTrue(common.compare_links(links,
|
||||
[{'rel': 'self', 'href': 'http://localhost/v1.0/'}]
|
||||
+ expected['links']))
|
||||
|
||||
def test_get_version_1_1_detail_xml(self):
|
||||
req = webob.Request.blank('/v1.1/')
|
||||
req.accept = "application/xml"
|
||||
@@ -338,9 +230,9 @@ class VersionsTest(test.TestCase):
|
||||
|
||||
self.assertTrue(root.xpath('/ns:versions', namespaces=NS))
|
||||
versions = root.xpath('ns:version', namespaces=NS)
|
||||
self.assertEqual(len(versions), 2)
|
||||
self.assertEqual(len(versions), 1)
|
||||
|
||||
for i, v in enumerate(['v1.0', 'v1.1']):
|
||||
for i, v in enumerate(['v1.1']):
|
||||
version = versions[i]
|
||||
expected = VERSIONS[v]
|
||||
for key in ['id', 'status', 'updated']:
|
||||
@@ -349,47 +241,6 @@ class VersionsTest(test.TestCase):
|
||||
self.assertTrue(common.compare_links(link,
|
||||
[{'rel': 'self', 'href': 'http://localhost/%s/' % v}]))
|
||||
|
||||
def test_get_version_1_0_detail_atom(self):
|
||||
req = webob.Request.blank('/v1.0/')
|
||||
req.accept = "application/atom+xml"
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 200)
|
||||
self.assertEqual("application/atom+xml", res.content_type)
|
||||
|
||||
xmlutil.validate_schema(etree.XML(res.body), 'atom')
|
||||
|
||||
f = feedparser.parse(res.body)
|
||||
self.assertEqual(f.feed.title, 'About This Version')
|
||||
self.assertEqual(f.feed.updated, '2011-01-21T11:33:21Z')
|
||||
self.assertEqual(f.feed.id, 'http://localhost/v1.0/')
|
||||
self.assertEqual(f.feed.author, 'Rackspace')
|
||||
self.assertEqual(f.feed.author_detail.href,
|
||||
'http://www.rackspace.com/')
|
||||
self.assertEqual(f.feed.links[0]['href'], 'http://localhost/v1.0/')
|
||||
self.assertEqual(f.feed.links[0]['rel'], 'self')
|
||||
|
||||
self.assertEqual(len(f.entries), 1)
|
||||
entry = f.entries[0]
|
||||
self.assertEqual(entry.id, 'http://localhost/v1.0/')
|
||||
self.assertEqual(entry.title, 'Version v1.0')
|
||||
self.assertEqual(entry.updated, '2011-01-21T11:33:21Z')
|
||||
self.assertEqual(len(entry.content), 1)
|
||||
self.assertEqual(entry.content[0].value,
|
||||
'Version v1.0 DEPRECATED (2011-01-21T11:33:21Z)')
|
||||
self.assertEqual(len(entry.links), 3)
|
||||
self.assertEqual(entry.links[0]['href'], 'http://localhost/v1.0/')
|
||||
self.assertEqual(entry.links[0]['rel'], 'self')
|
||||
self.assertEqual(entry.links[1], {
|
||||
'href': 'http://docs.rackspacecloud.com/servers/api/v1.0/'\
|
||||
'cs-devguide-20110125.pdf',
|
||||
'type': 'application/pdf',
|
||||
'rel': 'describedby'})
|
||||
self.assertEqual(entry.links[2], {
|
||||
'href': 'http://docs.rackspacecloud.com/servers/api/v1.0/'\
|
||||
'application.wadl',
|
||||
'type': 'application/vnd.sun.wadl+xml',
|
||||
'rel': 'describedby'})
|
||||
|
||||
def test_get_version_1_1_detail_atom(self):
|
||||
req = webob.Request.blank('/v1.1/')
|
||||
req.accept = "application/atom+xml"
|
||||
@@ -448,18 +299,8 @@ class VersionsTest(test.TestCase):
|
||||
self.assertEqual(f.feed.links[0]['href'], 'http://localhost/')
|
||||
self.assertEqual(f.feed.links[0]['rel'], 'self')
|
||||
|
||||
self.assertEqual(len(f.entries), 2)
|
||||
self.assertEqual(len(f.entries), 1)
|
||||
entry = f.entries[0]
|
||||
self.assertEqual(entry.id, 'http://localhost/v1.0/')
|
||||
self.assertEqual(entry.title, 'Version v1.0')
|
||||
self.assertEqual(entry.updated, '2011-01-21T11:33:21Z')
|
||||
self.assertEqual(len(entry.content), 1)
|
||||
self.assertEqual(entry.content[0].value,
|
||||
'Version v1.0 DEPRECATED (2011-01-21T11:33:21Z)')
|
||||
self.assertEqual(len(entry.links), 1)
|
||||
self.assertEqual(entry.links[0]['href'], 'http://localhost/v1.0/')
|
||||
self.assertEqual(entry.links[0]['rel'], 'self')
|
||||
entry = f.entries[1]
|
||||
self.assertEqual(entry.id, 'http://localhost/v1.1/')
|
||||
self.assertEqual(entry.title, 'Version v1.1')
|
||||
self.assertEqual(entry.updated, '2011-01-21T11:33:21Z')
|
||||
@@ -501,28 +342,6 @@ class VersionsTest(test.TestCase):
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"id": "v1.0",
|
||||
"status": "DEPRECATED",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://localhost/v1.0/images/1",
|
||||
"rel": "self",
|
||||
},
|
||||
],
|
||||
"media-types": [
|
||||
{
|
||||
"base": "application/xml",
|
||||
"type": "application/vnd.openstack.compute+xml"
|
||||
";version=1.0"
|
||||
},
|
||||
{
|
||||
"base": "application/json",
|
||||
"type": "application/vnd.openstack.compute+json"
|
||||
";version=1.0"
|
||||
},
|
||||
],
|
||||
},
|
||||
], }
|
||||
|
||||
self.assertDictMatch(expected, json.loads(res.body))
|
||||
@@ -537,7 +356,7 @@ class VersionsTest(test.TestCase):
|
||||
root = etree.XML(res.body)
|
||||
self.assertTrue(root.xpath('/ns:choices', namespaces=NS))
|
||||
versions = root.xpath('ns:version', namespaces=NS)
|
||||
self.assertEqual(len(versions), 2)
|
||||
self.assertEqual(len(versions), 1)
|
||||
|
||||
version = versions[0]
|
||||
self.assertEqual(version.get('id'), 'v1.1')
|
||||
@@ -550,17 +369,6 @@ class VersionsTest(test.TestCase):
|
||||
self.assertTrue(common.compare_links(links,
|
||||
[{'rel': 'self', 'href': 'http://localhost/v1.1/images/1'}]))
|
||||
|
||||
version = versions[1]
|
||||
self.assertEqual(version.get('id'), 'v1.0')
|
||||
self.assertEqual(version.get('status'), 'DEPRECATED')
|
||||
media_types = version.xpath('ns:media-types/ns:media-type',
|
||||
namespaces=NS)
|
||||
self.assertTrue(common.compare_media_types(media_types,
|
||||
VERSIONS['v1.0']['media-types']))
|
||||
links = version.xpath('atom:link', namespaces=NS)
|
||||
self.assertTrue(common.compare_links(links,
|
||||
[{'rel': 'self', 'href': 'http://localhost/v1.0/images/1'}]))
|
||||
|
||||
def test_multi_choice_server_atom(self):
|
||||
"""
|
||||
Make sure multi choice responses do not have content-type
|
||||
@@ -603,28 +411,6 @@ class VersionsTest(test.TestCase):
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"id": "v1.0",
|
||||
"status": "DEPRECATED",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://localhost/v1.0/servers/2",
|
||||
"rel": "self",
|
||||
},
|
||||
],
|
||||
"media-types": [
|
||||
{
|
||||
"base": "application/xml",
|
||||
"type": "application/vnd.openstack.compute+xml"
|
||||
";version=1.0"
|
||||
},
|
||||
{
|
||||
"base": "application/json",
|
||||
"type": "application/vnd.openstack.compute+json"
|
||||
";version=1.0"
|
||||
},
|
||||
],
|
||||
},
|
||||
], }
|
||||
|
||||
self.assertDictMatch(expected, json.loads(res.body))
|
||||
@@ -754,70 +540,6 @@ class VersionsSerializerTests(test.TestCase):
|
||||
self.assertTrue(common.compare_links(link,
|
||||
versions_data['choices'][0]['links']))
|
||||
|
||||
def test_version_detail_xml_serializer(self):
|
||||
version_data = {
|
||||
"version": {
|
||||
"id": "v1.0",
|
||||
"status": "CURRENT",
|
||||
"updated": "2011-01-21T11:33:21Z",
|
||||
"links": [
|
||||
{
|
||||
"rel": "self",
|
||||
"href": "http://localhost/v1.0/",
|
||||
},
|
||||
{
|
||||
"rel": "describedby",
|
||||
"type": "application/pdf",
|
||||
"href": "http://docs.rackspacecloud.com/"
|
||||
"servers/api/v1.0/cs-devguide-20110125.pdf",
|
||||
},
|
||||
{
|
||||
"rel": "describedby",
|
||||
"type": "application/vnd.sun.wadl+xml",
|
||||
"href": "http://docs.rackspacecloud.com/"
|
||||
"servers/api/v1.0/application.wadl",
|
||||
},
|
||||
],
|
||||
"media-types": [
|
||||
{
|
||||
"base": "application/xml",
|
||||
"type": "application/vnd.openstack.compute+xml"
|
||||
";version=1.0",
|
||||
},
|
||||
{
|
||||
"base": "application/json",
|
||||
"type": "application/vnd.openstack.compute+json"
|
||||
";version=1.0",
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
serializer = versions.VersionsXMLSerializer()
|
||||
response = serializer.show(version_data)
|
||||
|
||||
root = etree.XML(response)
|
||||
self.assertEqual(root.tag.split('}')[1], "version")
|
||||
self.assertEqual(root.tag.split('}')[0].strip('{'), wsgi.XMLNS_V11)
|
||||
|
||||
children = list(root)
|
||||
media_types = children[0]
|
||||
media_type_nodes = list(media_types)
|
||||
links = (children[1], children[2], children[3])
|
||||
|
||||
self.assertEqual(media_types.tag.split('}')[1], 'media-types')
|
||||
for i, media_node in enumerate(media_type_nodes):
|
||||
self.assertEqual(media_node.tag.split('}')[1], 'media-type')
|
||||
for key, val in version_data['version']['media-types'][i].items():
|
||||
self.assertEqual(val, media_node.get(key))
|
||||
|
||||
for i, link in enumerate(links):
|
||||
self.assertEqual(link.tag.split('}')[0].strip('{'),
|
||||
'http://www.w3.org/2005/Atom')
|
||||
self.assertEqual(link.tag.split('}')[1], 'link')
|
||||
for key, val in version_data['version']['links'][i].items():
|
||||
self.assertEqual(val, link.get(key))
|
||||
|
||||
def test_versions_list_atom_serializer(self):
|
||||
versions_data = {
|
||||
'versions': [
|
||||
|
@@ -105,7 +105,7 @@ class ZonesTest(test.TestCase):
|
||||
|
||||
def test_get_zone_list_scheduler(self):
|
||||
self.stubs.Set(api, '_call_scheduler', zone_get_all_scheduler)
|
||||
req = webob.Request.blank('/v1.0/zones')
|
||||
req = webob.Request.blank('/v1.1/fake/zones')
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
res_dict = json.loads(res.body)
|
||||
|
||||
@@ -115,7 +115,7 @@ class ZonesTest(test.TestCase):
|
||||
def test_get_zone_list_db(self):
|
||||
self.stubs.Set(api, '_call_scheduler', zone_get_all_scheduler_empty)
|
||||
self.stubs.Set(nova.db, 'zone_get_all', zone_get_all_db)
|
||||
req = webob.Request.blank('/v1.0/zones')
|
||||
req = webob.Request.blank('/v1.1/fake/zones')
|
||||
req.headers["Content-Type"] = "application/json"
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
|
||||
@@ -124,7 +124,7 @@ class ZonesTest(test.TestCase):
|
||||
self.assertEqual(len(res_dict['zones']), 2)
|
||||
|
||||
def test_get_zone_by_id(self):
|
||||
req = webob.Request.blank('/v1.0/zones/1')
|
||||
req = webob.Request.blank('/v1.1/fake/zones/1')
|
||||
req.headers["Content-Type"] = "application/json"
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
|
||||
@@ -135,7 +135,7 @@ class ZonesTest(test.TestCase):
|
||||
self.assertFalse('password' in res_dict['zone'])
|
||||
|
||||
def test_zone_delete(self):
|
||||
req = webob.Request.blank('/v1.0/zones/1')
|
||||
req = webob.Request.blank('/v1.1/fake/zones/1')
|
||||
req.headers["Content-Type"] = "application/json"
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
|
||||
@@ -144,7 +144,7 @@ class ZonesTest(test.TestCase):
|
||||
def test_zone_create(self):
|
||||
body = dict(zone=dict(api_url='http://example.com', username='fred',
|
||||
password='fubar'))
|
||||
req = webob.Request.blank('/v1.0/zones')
|
||||
req = webob.Request.blank('/v1.1/fake/zones')
|
||||
req.headers["Content-Type"] = "application/json"
|
||||
req.method = 'POST'
|
||||
req.body = json.dumps(body)
|
||||
@@ -159,7 +159,7 @@ class ZonesTest(test.TestCase):
|
||||
|
||||
def test_zone_update(self):
|
||||
body = dict(zone=dict(username='zeb', password='sneaky'))
|
||||
req = webob.Request.blank('/v1.0/zones/1')
|
||||
req = webob.Request.blank('/v1.1/fake/zones/1')
|
||||
req.headers["Content-Type"] = "application/json"
|
||||
req.method = 'PUT'
|
||||
req.body = json.dumps(body)
|
||||
@@ -178,7 +178,7 @@ class ZonesTest(test.TestCase):
|
||||
self.stubs.Set(api, '_call_scheduler', zone_capabilities)
|
||||
|
||||
body = dict(zone=dict(username='zeb', password='sneaky'))
|
||||
req = webob.Request.blank('/v1.0/zones/info')
|
||||
req = webob.Request.blank('/v1.1/fake/zones/info')
|
||||
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
res_dict = json.loads(res.body)
|
||||
@@ -192,7 +192,7 @@ class ZonesTest(test.TestCase):
|
||||
self.flags(build_plan_encryption_key=key)
|
||||
self.stubs.Set(api, 'select', zone_select)
|
||||
|
||||
req = webob.Request.blank('/v1.0/zones/select')
|
||||
req = webob.Request.blank('/v1.1/fake/zones/select')
|
||||
req.method = 'POST'
|
||||
req.headers["Content-Type"] = "application/json"
|
||||
# Select queries end up being JSON encoded twice.
|
||||
|
@@ -96,18 +96,15 @@ class ServersTest(integrated_helpers._IntegratedTestBase):
|
||||
self.assertRaises(client.OpenStackApiException,
|
||||
self.api.post_server, post)
|
||||
|
||||
# Add a valid imageId/imageRef
|
||||
server['imageId'] = good_server.get('imageId')
|
||||
# Add a valid imageRef
|
||||
server['imageRef'] = good_server.get('imageRef')
|
||||
|
||||
# Without flavorId, this throws 500
|
||||
# Without flavorRef, this throws 500
|
||||
# TODO(justinsb): Check whatever the spec says should be thrown here
|
||||
self.assertRaises(client.OpenStackApiException,
|
||||
self.api.post_server, post)
|
||||
|
||||
# Set a valid flavorId/flavorRef
|
||||
server['flavorRef'] = good_server.get('flavorRef')
|
||||
server['flavorId'] = good_server.get('flavorId')
|
||||
|
||||
# Without a name, this throws 500
|
||||
# TODO(justinsb): Check whatever the spec says should be thrown here
|
||||
|
Reference in New Issue
Block a user