Add API schema for v2.1/v3 config_drive extension
By defining the API schema, it is possible to separate the validation code from the API method. The API method can be more simple. In addition, a response of API validation error can be consistent for the whole Nova API. Partially implements blueprint v3-api-schema Change-Id: Ia0681941c5449051c90425348466bd7dc44c2e45
This commit is contained in:
@@ -15,6 +15,8 @@
|
||||
|
||||
"""Config Drive extension."""
|
||||
|
||||
from nova.api.openstack.compute.schemas.v3 import config_drive as \
|
||||
schema_config_drive
|
||||
from nova.api.openstack import extensions
|
||||
from nova.api.openstack import wsgi
|
||||
|
||||
@@ -68,3 +70,6 @@ class ConfigDrive(extensions.V3APIExtensionBase):
|
||||
|
||||
def server_create(self, server_dict, create_kwargs):
|
||||
create_kwargs['config_drive'] = server_dict.get(ATTRIBUTE_NAME)
|
||||
|
||||
def get_server_create_schema(self):
|
||||
return schema_config_drive.server_create
|
||||
|
||||
19
nova/api/openstack/compute/schemas/v3/config_drive.py
Normal file
19
nova/api/openstack/compute/schemas/v3/config_drive.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# Copyright 2014 NEC Corporation. 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 nova.api.validation import parameter_types
|
||||
|
||||
server_create = {
|
||||
'os-config-drive:config_drive': parameter_types.boolean,
|
||||
}
|
||||
@@ -25,6 +25,7 @@ from nova.api.openstack.compute.plugins.v3 import servers
|
||||
from nova.compute import api as compute_api
|
||||
from nova.compute import flavors
|
||||
from nova import db
|
||||
from nova import exception
|
||||
from nova.network import manager
|
||||
from nova.openstack.common import jsonutils
|
||||
from nova import test
|
||||
@@ -202,7 +203,7 @@ class ServersControllerCreateTest(test.TestCase):
|
||||
self._test_create_extra(params,
|
||||
override_controller=self.no_config_drive_controller)
|
||||
|
||||
def test_create_instance_with_config_drive(self):
|
||||
def _create_instance_body_of_config_drive(self, param):
|
||||
def create(*args, **kwargs):
|
||||
self.assertIn('config_drive', kwargs)
|
||||
return old_create(*args, **kwargs)
|
||||
@@ -220,7 +221,7 @@ class ServersControllerCreateTest(test.TestCase):
|
||||
'hello': 'world',
|
||||
'open': 'stack',
|
||||
},
|
||||
config_drive.ATTRIBUTE_NAME: "true",
|
||||
config_drive.ATTRIBUTE_NAME: param,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -228,55 +229,39 @@ class ServersControllerCreateTest(test.TestCase):
|
||||
req.method = 'POST'
|
||||
req.body = jsonutils.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
res = self.controller.create(req, body=body).obj
|
||||
|
||||
return req, body
|
||||
|
||||
def test_create_instance_with_config_drive(self):
|
||||
param = True
|
||||
req, body = self._create_instance_body_of_config_drive(param)
|
||||
res = self.controller.create(req, body=body).obj
|
||||
server = res['server']
|
||||
self.assertEqual(FAKE_UUID, server['id'])
|
||||
|
||||
def test_create_instance_with_config_drive_as_boolean_string(self):
|
||||
param = 'false'
|
||||
req, body = self._create_instance_body_of_config_drive(param)
|
||||
res = self.controller.create(req, body=body).obj
|
||||
server = res['server']
|
||||
self.assertEqual(FAKE_UUID, server['id'])
|
||||
|
||||
def test_create_instance_with_bad_config_drive(self):
|
||||
image_href = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
|
||||
flavor_ref = 'http://localhost/v3/flavors/3'
|
||||
body = {
|
||||
'server': {
|
||||
'name': 'config_drive_test',
|
||||
'image_ref': image_href,
|
||||
'flavor_ref': flavor_ref,
|
||||
'metadata': {
|
||||
'hello': 'world',
|
||||
'open': 'stack',
|
||||
},
|
||||
config_drive.ATTRIBUTE_NAME: image_href,
|
||||
},
|
||||
}
|
||||
|
||||
req = fakes.HTTPRequestV3.blank('/servers')
|
||||
req.method = 'POST'
|
||||
req.body = jsonutils.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
|
||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
param = 12345
|
||||
req, body = self._create_instance_body_of_config_drive(param)
|
||||
self.assertRaises(exception.ValidationError,
|
||||
self.controller.create, req, body=body)
|
||||
|
||||
def test_create_instance_without_config_drive(self):
|
||||
image_href = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
|
||||
flavor_ref = 'http://localhost/v3/flavors/3'
|
||||
body = {
|
||||
'server': {
|
||||
'name': 'config_drive_test',
|
||||
'image_ref': image_href,
|
||||
'flavor_ref': flavor_ref,
|
||||
'metadata': {
|
||||
'hello': 'world',
|
||||
'open': 'stack',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
req = fakes.HTTPRequestV3.blank('/servers')
|
||||
req.method = 'POST'
|
||||
req.body = jsonutils.dumps(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
param = True
|
||||
req, body = self._create_instance_body_of_config_drive(param)
|
||||
del body['server'][config_drive.ATTRIBUTE_NAME]
|
||||
res = self.controller.create(req, body=body).obj
|
||||
|
||||
server = res['server']
|
||||
self.assertEqual(FAKE_UUID, server['id'])
|
||||
|
||||
def test_create_instance_with_empty_config_drive(self):
|
||||
param = ''
|
||||
req, body = self._create_instance_body_of_config_drive(param)
|
||||
self.assertRaises(exception.ValidationError,
|
||||
self.controller.create, req, body=body)
|
||||
|
||||
Reference in New Issue
Block a user