Added a mechanism for versioned controllers for openstack api versions 1.0/1.1.
Create servers in the 1.1 api now supports imageRef/flavorRef instead of imageId/flavorId.
This commit is contained in:
commit
86b3cc94bc
@ -67,11 +67,14 @@ paste.app_factory = nova.api.ec2.metadatarequesthandler:MetadataRequestHandler.f
|
||||
[composite:osapi]
|
||||
use = egg:Paste#urlmap
|
||||
/: osversions
|
||||
/v1.0: openstackapi
|
||||
/v1.1: openstackapi
|
||||
/v1.0: openstackapi10
|
||||
/v1.1: openstackapi11
|
||||
|
||||
[pipeline:openstackapi]
|
||||
pipeline = faultwrap auth ratelimit osapiapp
|
||||
[pipeline:openstackapi10]
|
||||
pipeline = faultwrap auth ratelimit osapiapp10
|
||||
|
||||
[pipeline:openstackapi11]
|
||||
pipeline = faultwrap auth ratelimit osapiapp11
|
||||
|
||||
[filter:faultwrap]
|
||||
paste.filter_factory = nova.api.openstack:FaultWrapper.factory
|
||||
@ -82,8 +85,11 @@ paste.filter_factory = nova.api.openstack.auth:AuthMiddleware.factory
|
||||
[filter:ratelimit]
|
||||
paste.filter_factory = nova.api.openstack.limits:RateLimitingMiddleware.factory
|
||||
|
||||
[app:osapiapp]
|
||||
paste.app_factory = nova.api.openstack:APIRouter.factory
|
||||
[app:osapiapp10]
|
||||
paste.app_factory = nova.api.openstack:APIRouterV10.factory
|
||||
|
||||
[app:osapiapp11]
|
||||
paste.app_factory = nova.api.openstack:APIRouterV11.factory
|
||||
|
||||
[pipeline:osversions]
|
||||
pipeline = faultwrap osversionapp
|
||||
|
@ -72,9 +72,14 @@ class APIRouter(wsgi.Router):
|
||||
return cls()
|
||||
|
||||
def __init__(self):
|
||||
self.server_members = {}
|
||||
mapper = routes.Mapper()
|
||||
self._setup_routes(mapper)
|
||||
super(APIRouter, self).__init__(mapper)
|
||||
|
||||
server_members = {'action': 'POST'}
|
||||
def _setup_routes(self, mapper):
|
||||
server_members = self.server_members
|
||||
server_members['action'] = 'POST'
|
||||
if FLAGS.allow_admin_api:
|
||||
LOG.debug(_("Including admin operations in API."))
|
||||
|
||||
@ -99,10 +104,6 @@ class APIRouter(wsgi.Router):
|
||||
controller=accounts.Controller(),
|
||||
collection={'detail': 'GET'})
|
||||
|
||||
mapper.resource("server", "servers", controller=servers.Controller(),
|
||||
collection={'detail': 'GET'},
|
||||
member=server_members)
|
||||
|
||||
mapper.resource("backup_schedule", "backup_schedule",
|
||||
controller=backup_schedules.Controller(),
|
||||
parent_resource=dict(member_name='server',
|
||||
@ -126,7 +127,27 @@ class APIRouter(wsgi.Router):
|
||||
_limits = limits.LimitsController()
|
||||
mapper.resource("limit", "limits", controller=_limits)
|
||||
|
||||
super(APIRouter, self).__init__(mapper)
|
||||
|
||||
class APIRouterV10(APIRouter):
|
||||
"""Define routes specific to OpenStack API V1.0."""
|
||||
|
||||
def _setup_routes(self, mapper):
|
||||
super(APIRouterV10, self)._setup_routes(mapper)
|
||||
mapper.resource("server", "servers",
|
||||
controller=servers.ControllerV10(),
|
||||
collection={'detail': 'GET'},
|
||||
member=self.server_members)
|
||||
|
||||
|
||||
class APIRouterV11(APIRouter):
|
||||
"""Define routes specific to OpenStack API V1.1."""
|
||||
|
||||
def _setup_routes(self, mapper):
|
||||
super(APIRouterV11, self)._setup_routes(mapper)
|
||||
mapper.resource("server", "servers",
|
||||
controller=servers.ControllerV11(),
|
||||
collection={'detail': 'GET'},
|
||||
member=self.server_members)
|
||||
|
||||
|
||||
class Versions(wsgi.Application):
|
||||
|
@ -69,8 +69,6 @@ class AuthMiddleware(wsgi.Middleware):
|
||||
return faults.Fault(webob.exc.HTTPUnauthorized())
|
||||
|
||||
req.environ['nova.context'] = context.RequestContext(user, account)
|
||||
version = req.path.split('/')[1].replace('v', '')
|
||||
req.environ['api.version'] = version
|
||||
return self.application
|
||||
|
||||
def has_authentication(self, req):
|
||||
|
@ -15,7 +15,9 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import webob.exc
|
||||
from urlparse import urlparse
|
||||
|
||||
import webob
|
||||
|
||||
from nova import exception
|
||||
|
||||
@ -76,5 +78,14 @@ def get_image_id_from_image_hash(image_service, context, image_hash):
|
||||
raise exception.NotFound(image_hash)
|
||||
|
||||
|
||||
def get_api_version(req):
|
||||
return req.environ.get('api.version')
|
||||
def get_id_from_href(href):
|
||||
"""Return the id portion of a url as an int.
|
||||
|
||||
Given: http://www.foo.com/bar/123?q=4
|
||||
Returns: 123
|
||||
|
||||
"""
|
||||
try:
|
||||
return int(urlparse(href).path.split('/')[-1])
|
||||
except:
|
||||
raise webob.exc.HTTPBadRequest(_('could not parse id from href'))
|
||||
|
@ -30,8 +30,9 @@ from nova import wsgi
|
||||
from nova import utils
|
||||
from nova.api.openstack import common
|
||||
from nova.api.openstack import faults
|
||||
from nova.api.openstack.views import servers as servers_views
|
||||
from nova.api.openstack.views import addresses as addresses_views
|
||||
import nova.api.openstack.views.addresses
|
||||
import nova.api.openstack.views.flavors
|
||||
import nova.api.openstack.views.servers
|
||||
from nova.auth import manager as auth_manager
|
||||
from nova.compute import instance_types
|
||||
from nova.compute import power_state
|
||||
@ -64,7 +65,7 @@ class Controller(wsgi.Controller):
|
||||
except exception.NotFound:
|
||||
return faults.Fault(exc.HTTPNotFound())
|
||||
|
||||
builder = addresses_views.get_view_builder(req)
|
||||
builder = self._get_addresses_view_builder(req)
|
||||
return builder.build(instance)
|
||||
|
||||
def index(self, req):
|
||||
@ -82,7 +83,7 @@ class Controller(wsgi.Controller):
|
||||
"""
|
||||
instance_list = self.compute_api.get_all(req.environ['nova.context'])
|
||||
limited_list = common.limited(instance_list, req)
|
||||
builder = servers_views.get_view_builder(req)
|
||||
builder = self._get_view_builder(req)
|
||||
servers = [builder.build(inst, is_detail)['server']
|
||||
for inst in limited_list]
|
||||
return dict(servers=servers)
|
||||
@ -91,7 +92,7 @@ class Controller(wsgi.Controller):
|
||||
""" Returns server details by server id """
|
||||
try:
|
||||
instance = self.compute_api.get(req.environ['nova.context'], id)
|
||||
builder = servers_views.get_view_builder(req)
|
||||
builder = self._get_view_builder(req)
|
||||
return builder.build(instance, is_detail=True)
|
||||
except exception.NotFound:
|
||||
return faults.Fault(exc.HTTPNotFound())
|
||||
@ -120,8 +121,9 @@ class Controller(wsgi.Controller):
|
||||
key_name = key_pair['name']
|
||||
key_data = key_pair['public_key']
|
||||
|
||||
requested_image_id = self._image_id_from_req_data(env)
|
||||
image_id = common.get_image_id_from_image_hash(self._image_service,
|
||||
context, env['server']['imageId'])
|
||||
context, requested_image_id)
|
||||
kernel_id, ramdisk_id = self._get_kernel_ramdisk_from_image(
|
||||
req, image_id)
|
||||
|
||||
@ -140,10 +142,11 @@ class Controller(wsgi.Controller):
|
||||
if personality:
|
||||
injected_files = self._get_injected_files(personality)
|
||||
|
||||
flavor_id = self._flavor_id_from_req_data(env)
|
||||
try:
|
||||
instances = self.compute_api.create(
|
||||
(inst,) = self.compute_api.create(
|
||||
context,
|
||||
instance_types.get_by_flavor_id(env['server']['flavorId']),
|
||||
instance_types.get_by_flavor_id(flavor_id),
|
||||
image_id,
|
||||
kernel_id=kernel_id,
|
||||
ramdisk_id=ramdisk_id,
|
||||
@ -156,8 +159,11 @@ class Controller(wsgi.Controller):
|
||||
except QuotaError as error:
|
||||
self._handle_quota_errors(error)
|
||||
|
||||
builder = servers_views.get_view_builder(req)
|
||||
server = builder.build(instances[0], is_detail=False)
|
||||
inst['instance_type'] = flavor_id
|
||||
inst['image_id'] = requested_image_id
|
||||
|
||||
builder = self._get_view_builder(req)
|
||||
server = builder.build(inst, is_detail=True)
|
||||
password = "%s%s" % (server['server']['name'][:4],
|
||||
utils.generate_password(12))
|
||||
server['server']['adminPass'] = password
|
||||
@ -512,6 +518,45 @@ class Controller(wsgi.Controller):
|
||||
return kernel_id, ramdisk_id
|
||||
|
||||
|
||||
class ControllerV10(Controller):
|
||||
def _image_id_from_req_data(self, data):
|
||||
return data['server']['imageId']
|
||||
|
||||
def _flavor_id_from_req_data(self, data):
|
||||
return data['server']['flavorId']
|
||||
|
||||
def _get_view_builder(self, req):
|
||||
addresses_builder = nova.api.openstack.views.addresses.ViewBuilderV10()
|
||||
return nova.api.openstack.views.servers.ViewBuilderV10(
|
||||
addresses_builder)
|
||||
|
||||
def _get_addresses_view_builder(self, req):
|
||||
return nova.api.openstack.views.addresses.ViewBuilderV10(req)
|
||||
|
||||
|
||||
class ControllerV11(Controller):
|
||||
def _image_id_from_req_data(self, data):
|
||||
href = data['server']['imageRef']
|
||||
return common.get_id_from_href(href)
|
||||
|
||||
def _flavor_id_from_req_data(self, data):
|
||||
href = data['server']['flavorRef']
|
||||
return common.get_id_from_href(href)
|
||||
|
||||
def _get_view_builder(self, req):
|
||||
base_url = req.application_url
|
||||
flavor_builder = nova.api.openstack.views.flavors.ViewBuilderV11(
|
||||
base_url)
|
||||
image_builder = nova.api.openstack.views.images.ViewBuilderV11(
|
||||
base_url)
|
||||
addresses_builder = nova.api.openstack.views.addresses.ViewBuilderV11()
|
||||
return nova.api.openstack.views.servers.ViewBuilderV11(
|
||||
addresses_builder, flavor_builder, image_builder)
|
||||
|
||||
def _get_addresses_view_builder(self, req):
|
||||
return nova.api.openstack.views.addresses.ViewBuilderV11(req)
|
||||
|
||||
|
||||
class ServerCreateRequestXMLDeserializer(object):
|
||||
"""
|
||||
Deserializer to handle xml-formatted server create requests.
|
||||
|
@ -19,18 +19,6 @@ from nova import utils
|
||||
from nova.api.openstack import common
|
||||
|
||||
|
||||
def get_view_builder(req):
|
||||
'''
|
||||
A factory method that returns the correct builder based on the version of
|
||||
the api requested.
|
||||
'''
|
||||
version = common.get_api_version(req)
|
||||
if version == '1.1':
|
||||
return ViewBuilder_1_1()
|
||||
else:
|
||||
return ViewBuilder_1_0()
|
||||
|
||||
|
||||
class ViewBuilder(object):
|
||||
''' Models a server addresses response as a python dictionary.'''
|
||||
|
||||
@ -38,14 +26,14 @@ class ViewBuilder(object):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class ViewBuilder_1_0(ViewBuilder):
|
||||
class ViewBuilderV10(ViewBuilder):
|
||||
def build(self, inst):
|
||||
private_ips = utils.get_from_path(inst, 'fixed_ip/address')
|
||||
public_ips = utils.get_from_path(inst, 'fixed_ip/floating_ips/address')
|
||||
return dict(public=public_ips, private=private_ips)
|
||||
|
||||
|
||||
class ViewBuilder_1_1(ViewBuilder):
|
||||
class ViewBuilderV11(ViewBuilder):
|
||||
def build(self, inst):
|
||||
private_ips = utils.get_from_path(inst, 'fixed_ip/address')
|
||||
private_ips = [dict(version=4, addr=a) for a in private_ips]
|
||||
|
@ -18,19 +18,6 @@
|
||||
from nova.api.openstack import common
|
||||
|
||||
|
||||
def get_view_builder(req):
|
||||
'''
|
||||
A factory method that returns the correct builder based on the version of
|
||||
the api requested.
|
||||
'''
|
||||
version = common.get_api_version(req)
|
||||
base_url = req.application_url
|
||||
if version == '1.1':
|
||||
return ViewBuilder_1_1(base_url)
|
||||
else:
|
||||
return ViewBuilder_1_0()
|
||||
|
||||
|
||||
class ViewBuilder(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
@ -39,13 +26,9 @@ class ViewBuilder(object):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class ViewBuilder_1_1(ViewBuilder):
|
||||
class ViewBuilderV11(ViewBuilder):
|
||||
def __init__(self, base_url):
|
||||
self.base_url = base_url
|
||||
|
||||
def generate_href(self, flavor_id):
|
||||
return "%s/flavors/%s" % (self.base_url, flavor_id)
|
||||
|
||||
|
||||
class ViewBuilder_1_0(ViewBuilder):
|
||||
pass
|
||||
|
@ -18,19 +18,6 @@
|
||||
from nova.api.openstack import common
|
||||
|
||||
|
||||
def get_view_builder(req):
|
||||
'''
|
||||
A factory method that returns the correct builder based on the version of
|
||||
the api requested.
|
||||
'''
|
||||
version = common.get_api_version(req)
|
||||
base_url = req.application_url
|
||||
if version == '1.1':
|
||||
return ViewBuilder_1_1(base_url)
|
||||
else:
|
||||
return ViewBuilder_1_0()
|
||||
|
||||
|
||||
class ViewBuilder(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
@ -39,13 +26,9 @@ class ViewBuilder(object):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class ViewBuilder_1_1(ViewBuilder):
|
||||
class ViewBuilderV11(ViewBuilder):
|
||||
def __init__(self, base_url):
|
||||
self.base_url = base_url
|
||||
|
||||
def generate_href(self, image_id):
|
||||
return "%s/images/%s" % (self.base_url, image_id)
|
||||
|
||||
|
||||
class ViewBuilder_1_0(ViewBuilder):
|
||||
pass
|
||||
|
@ -27,45 +27,30 @@ from nova.api.openstack.views import images as images_view
|
||||
from nova import utils
|
||||
|
||||
|
||||
def get_view_builder(req):
|
||||
'''
|
||||
A factory method that returns the correct builder based on the version of
|
||||
the api requested.
|
||||
'''
|
||||
version = common.get_api_version(req)
|
||||
addresses_builder = addresses_view.get_view_builder(req)
|
||||
if version == '1.1':
|
||||
flavor_builder = flavors_view.get_view_builder(req)
|
||||
image_builder = images_view.get_view_builder(req)
|
||||
return ViewBuilder_1_1(addresses_builder, flavor_builder,
|
||||
image_builder)
|
||||
else:
|
||||
return ViewBuilder_1_0(addresses_builder)
|
||||
|
||||
|
||||
class ViewBuilder(object):
|
||||
'''
|
||||
Models 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, addresses_builder):
|
||||
self.addresses_builder = addresses_builder
|
||||
|
||||
def build(self, inst, is_detail):
|
||||
"""
|
||||
Coerces into dictionary format, mapping everything to
|
||||
Rackspace-like attributes for return
|
||||
"""
|
||||
"""Return a dict that represenst a server."""
|
||||
if is_detail:
|
||||
return self._build_detail(inst)
|
||||
else:
|
||||
return self._build_simple(inst)
|
||||
|
||||
def _build_simple(self, inst):
|
||||
return dict(server=dict(id=inst['id'], name=inst['display_name']))
|
||||
"""Return a simple model of a server."""
|
||||
return dict(server=dict(id=inst['id'], name=inst['display_name']))
|
||||
|
||||
def _build_detail(self, inst):
|
||||
"""Returns a detailed model of a server."""
|
||||
power_mapping = {
|
||||
None: 'build',
|
||||
power_state.NOSTATE: 'build',
|
||||
@ -77,32 +62,26 @@ class ViewBuilder(object):
|
||||
power_state.SHUTOFF: 'active',
|
||||
power_state.CRASHED: 'error',
|
||||
power_state.FAILED: 'error'}
|
||||
inst_dict = {}
|
||||
|
||||
#mapped_keys = dict(status='state', imageId='image_id',
|
||||
# flavorId='instance_type', name='display_name', id='id')
|
||||
|
||||
mapped_keys = dict(status='state', name='display_name', id='id')
|
||||
|
||||
for k, v in mapped_keys.iteritems():
|
||||
inst_dict[k] = inst[v]
|
||||
inst_dict = {
|
||||
'id': int(inst['id']),
|
||||
'name': inst['display_name'],
|
||||
'addresses': self.addresses_builder.build(inst),
|
||||
'status': power_mapping[inst.get('state')]}
|
||||
|
||||
ctxt = nova.context.get_admin_context()
|
||||
inst_dict['status'] = power_mapping[inst_dict['status']]
|
||||
compute_api = nova.compute.API()
|
||||
if compute_api.has_finished_migration(ctxt, inst['id']):
|
||||
inst_dict['status'] = 'resize-confirm'
|
||||
|
||||
inst_dict['addresses'] = self.addresses_builder.build(inst)
|
||||
|
||||
# Return the metadata as a dictionary
|
||||
metadata = {}
|
||||
for item in inst['metadata']:
|
||||
for item in inst.get('metadata', []):
|
||||
metadata[item['key']] = item['value']
|
||||
inst_dict['metadata'] = metadata
|
||||
|
||||
inst_dict['hostId'] = ''
|
||||
if inst['host']:
|
||||
if inst.get('host'):
|
||||
inst_dict['hostId'] = hashlib.sha224(inst['host']).hexdigest()
|
||||
|
||||
self._build_image(inst_dict, inst)
|
||||
@ -111,21 +90,27 @@ class ViewBuilder(object):
|
||||
return dict(server=inst_dict)
|
||||
|
||||
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()
|
||||
|
||||
|
||||
class ViewBuilder_1_0(ViewBuilder):
|
||||
class ViewBuilderV10(ViewBuilder):
|
||||
"""Model an Openstack API V1.0 server response."""
|
||||
|
||||
def _build_image(self, response, inst):
|
||||
response["imageId"] = inst["image_id"]
|
||||
response['imageId'] = inst['image_id']
|
||||
|
||||
def _build_flavor(self, response, inst):
|
||||
response["flavorId"] = inst["instance_type"]
|
||||
response['flavorId'] = inst['instance_type']
|
||||
|
||||
|
||||
class ViewBuilder_1_1(ViewBuilder):
|
||||
class ViewBuilderV11(ViewBuilder):
|
||||
"""Model an Openstack API V1.0 server response."""
|
||||
|
||||
def __init__(self, addresses_builder, flavor_builder, image_builder):
|
||||
ViewBuilder.__init__(self, addresses_builder)
|
||||
self.flavor_builder = flavor_builder
|
||||
|
@ -73,14 +73,18 @@ def fake_wsgi(self, req):
|
||||
return self.application
|
||||
|
||||
|
||||
def wsgi_app(inner_application=None):
|
||||
if not inner_application:
|
||||
inner_application = openstack.APIRouter()
|
||||
def wsgi_app(inner_app10=None, inner_app11=None):
|
||||
if not inner_app10:
|
||||
inner_app10 = openstack.APIRouterV10()
|
||||
if not inner_app11:
|
||||
inner_app11 = openstack.APIRouterV11()
|
||||
mapper = urlmap.URLMap()
|
||||
api = openstack.FaultWrapper(auth.AuthMiddleware(
|
||||
limits.RateLimitingMiddleware(inner_application)))
|
||||
mapper['/v1.0'] = api
|
||||
mapper['/v1.1'] = api
|
||||
api10 = openstack.FaultWrapper(auth.AuthMiddleware(
|
||||
limits.RateLimitingMiddleware(inner_app10)))
|
||||
api11 = openstack.FaultWrapper(auth.AuthMiddleware(
|
||||
limits.RateLimitingMiddleware(inner_app11)))
|
||||
mapper['/v1.0'] = api10
|
||||
mapper['/v1.1'] = api11
|
||||
mapper['/'] = openstack.FaultWrapper(openstack.Versions())
|
||||
return mapper
|
||||
|
||||
|
@ -83,8 +83,7 @@ class Test(test.TestCase):
|
||||
self.assertEqual(result.headers['X-Storage-Url'], "")
|
||||
|
||||
token = result.headers['X-Auth-Token']
|
||||
self.stubs.Set(nova.api.openstack, 'APIRouter',
|
||||
fakes.FakeRouter)
|
||||
self.stubs.Set(nova.api.openstack, 'APIRouterV10', fakes.FakeRouter)
|
||||
req = webob.Request.blank('/v1.0/fake')
|
||||
req.headers['X-Auth-Token'] = token
|
||||
result = req.get_response(fakes.wsgi_app())
|
||||
@ -201,8 +200,7 @@ class TestLimiter(test.TestCase):
|
||||
self.assertEqual(len(result.headers['X-Auth-Token']), 40)
|
||||
|
||||
token = result.headers['X-Auth-Token']
|
||||
self.stubs.Set(nova.api.openstack, 'APIRouter',
|
||||
fakes.FakeRouter)
|
||||
self.stubs.Set(nova.api.openstack, 'APIRouterV10', fakes.FakeRouter)
|
||||
req = webob.Request.blank('/v1.0/fake')
|
||||
req.method = 'POST'
|
||||
req.headers['X-Auth-Token'] = token
|
||||
|
@ -161,7 +161,7 @@ class ServersTest(test.TestCase):
|
||||
req = webob.Request.blank('/v1.0/servers/1')
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
res_dict = json.loads(res.body)
|
||||
self.assertEqual(res_dict['server']['id'], '1')
|
||||
self.assertEqual(res_dict['server']['id'], 1)
|
||||
self.assertEqual(res_dict['server']['name'], 'server1')
|
||||
|
||||
def test_get_server_by_id_with_addresses(self):
|
||||
@ -172,7 +172,7 @@ class ServersTest(test.TestCase):
|
||||
req = webob.Request.blank('/v1.0/servers/1')
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
res_dict = json.loads(res.body)
|
||||
self.assertEqual(res_dict['server']['id'], '1')
|
||||
self.assertEqual(res_dict['server']['id'], 1)
|
||||
self.assertEqual(res_dict['server']['name'], 'server1')
|
||||
addresses = res_dict['server']['addresses']
|
||||
self.assertEqual(len(addresses["public"]), len(public))
|
||||
@ -180,7 +180,7 @@ class ServersTest(test.TestCase):
|
||||
self.assertEqual(len(addresses["private"]), 1)
|
||||
self.assertEqual(addresses["private"][0], private)
|
||||
|
||||
def test_get_server_by_id_with_addresses_v1_1(self):
|
||||
def test_get_server_by_id_with_addresses_v11(self):
|
||||
private = "192.168.0.3"
|
||||
public = ["1.2.3.4"]
|
||||
new_return_server = return_server_with_addresses(private, public)
|
||||
@ -189,7 +189,7 @@ class ServersTest(test.TestCase):
|
||||
req.environ['api.version'] = '1.1'
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
res_dict = json.loads(res.body)
|
||||
self.assertEqual(res_dict['server']['id'], '1')
|
||||
self.assertEqual(res_dict['server']['id'], 1)
|
||||
self.assertEqual(res_dict['server']['name'], 'server1')
|
||||
addresses = res_dict['server']['addresses']
|
||||
self.assertEqual(len(addresses["public"]), len(public))
|
||||
@ -239,7 +239,7 @@ class ServersTest(test.TestCase):
|
||||
servers = json.loads(res.body)['servers']
|
||||
self.assertEqual([s['id'] for s in servers], [1, 2])
|
||||
|
||||
def _test_create_instance_helper(self):
|
||||
def _setup_for_create_instance(self):
|
||||
"""Shared implementation for tests below that create instance"""
|
||||
def instance_create(context, inst):
|
||||
return {'id': '1', 'display_name': 'server_test'}
|
||||
@ -276,14 +276,17 @@ class ServersTest(test.TestCase):
|
||||
self.stubs.Set(nova.api.openstack.common,
|
||||
"get_image_id_from_image_hash", image_id_from_hash)
|
||||
|
||||
def _test_create_instance_helper(self):
|
||||
self._setup_for_create_instance()
|
||||
|
||||
body = dict(server=dict(
|
||||
name='server_test', imageId=2, flavorId=2,
|
||||
name='server_test', imageId=3, flavorId=2,
|
||||
metadata={'hello': 'world', 'open': 'stack'},
|
||||
personality={}))
|
||||
req = webob.Request.blank('/v1.0/servers')
|
||||
req.method = 'POST'
|
||||
req.body = json.dumps(body)
|
||||
req.headers["Content-Type"] = "application/json"
|
||||
req.headers["content-type"] = "application/json"
|
||||
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
|
||||
@ -291,8 +294,9 @@ class ServersTest(test.TestCase):
|
||||
self.assertEqual('serv', server['adminPass'][:4])
|
||||
self.assertEqual(16, len(server['adminPass']))
|
||||
self.assertEqual('server_test', server['name'])
|
||||
self.assertEqual('1', server['id'])
|
||||
|
||||
self.assertEqual(1, server['id'])
|
||||
self.assertEqual(2, server['flavorId'])
|
||||
self.assertEqual(3, server['imageId'])
|
||||
self.assertEqual(res.status_int, 200)
|
||||
|
||||
def test_create_instance(self):
|
||||
@ -302,6 +306,56 @@ class ServersTest(test.TestCase):
|
||||
fakes.stub_out_key_pair_funcs(self.stubs, have_key_pair=False)
|
||||
self._test_create_instance_helper()
|
||||
|
||||
def test_create_instance_v11(self):
|
||||
self._setup_for_create_instance()
|
||||
|
||||
imageRef = 'http://localhost/v1.1/images/2'
|
||||
flavorRef = 'http://localhost/v1.1/flavors/3'
|
||||
body = {
|
||||
'server': {
|
||||
'name': 'server_test',
|
||||
'imageRef': imageRef,
|
||||
'flavorRef': flavorRef,
|
||||
'metadata': {
|
||||
'hello': 'world',
|
||||
'open': 'stack',
|
||||
},
|
||||
'personality': {},
|
||||
},
|
||||
}
|
||||
|
||||
req = webob.Request.blank('/v1.1/servers')
|
||||
req.method = 'POST'
|
||||
req.body = json.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
|
||||
server = json.loads(res.body)['server']
|
||||
self.assertEqual('serv', server['adminPass'][:4])
|
||||
self.assertEqual(16, len(server['adminPass']))
|
||||
self.assertEqual('server_test', server['name'])
|
||||
self.assertEqual(1, server['id'])
|
||||
self.assertEqual(flavorRef, server['flavorRef'])
|
||||
self.assertEqual(imageRef, server['imageRef'])
|
||||
self.assertEqual(res.status_int, 200)
|
||||
|
||||
def test_create_instance_v11_bad_href(self):
|
||||
self._setup_for_create_instance()
|
||||
|
||||
imageRef = 'http://localhost/v1.1/images/asdf'
|
||||
flavorRef = 'http://localhost/v1.1/flavors/3'
|
||||
body = dict(server=dict(
|
||||
name='server_test', imageRef=imageRef, flavorRef=flavorRef,
|
||||
metadata={'hello': 'world', 'open': 'stack'},
|
||||
personality={}))
|
||||
req = webob.Request.blank('/v1.1/servers')
|
||||
req.method = 'POST'
|
||||
req.body = json.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 400)
|
||||
|
||||
def test_update_no_body(self):
|
||||
req = webob.Request.blank('/v1.0/servers/1')
|
||||
req.method = 'PUT'
|
||||
@ -945,7 +999,7 @@ class TestServerInstanceCreation(test.TestCase):
|
||||
|
||||
def _setup_mock_compute_api_for_personality(self):
|
||||
|
||||
class MockComputeAPI(object):
|
||||
class MockComputeAPI(nova.compute.API):
|
||||
|
||||
def __init__(self):
|
||||
self.injected_files = None
|
||||
|
Loading…
Reference in New Issue
Block a user