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."""
|
"""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 extensions
|
||||||
from nova.api.openstack import wsgi
|
from nova.api.openstack import wsgi
|
||||||
|
|
||||||
@@ -68,3 +70,6 @@ class ConfigDrive(extensions.V3APIExtensionBase):
|
|||||||
|
|
||||||
def server_create(self, server_dict, create_kwargs):
|
def server_create(self, server_dict, create_kwargs):
|
||||||
create_kwargs['config_drive'] = server_dict.get(ATTRIBUTE_NAME)
|
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 api as compute_api
|
||||||
from nova.compute import flavors
|
from nova.compute import flavors
|
||||||
from nova import db
|
from nova import db
|
||||||
|
from nova import exception
|
||||||
from nova.network import manager
|
from nova.network import manager
|
||||||
from nova.openstack.common import jsonutils
|
from nova.openstack.common import jsonutils
|
||||||
from nova import test
|
from nova import test
|
||||||
@@ -202,7 +203,7 @@ class ServersControllerCreateTest(test.TestCase):
|
|||||||
self._test_create_extra(params,
|
self._test_create_extra(params,
|
||||||
override_controller=self.no_config_drive_controller)
|
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):
|
def create(*args, **kwargs):
|
||||||
self.assertIn('config_drive', kwargs)
|
self.assertIn('config_drive', kwargs)
|
||||||
return old_create(*args, **kwargs)
|
return old_create(*args, **kwargs)
|
||||||
@@ -220,7 +221,7 @@ class ServersControllerCreateTest(test.TestCase):
|
|||||||
'hello': 'world',
|
'hello': 'world',
|
||||||
'open': 'stack',
|
'open': 'stack',
|
||||||
},
|
},
|
||||||
config_drive.ATTRIBUTE_NAME: "true",
|
config_drive.ATTRIBUTE_NAME: param,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,55 +229,39 @@ class ServersControllerCreateTest(test.TestCase):
|
|||||||
req.method = 'POST'
|
req.method = 'POST'
|
||||||
req.body = jsonutils.dumps(body)
|
req.body = jsonutils.dumps(body)
|
||||||
req.headers["content-type"] = "application/json"
|
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']
|
server = res['server']
|
||||||
self.assertEqual(FAKE_UUID, server['id'])
|
self.assertEqual(FAKE_UUID, server['id'])
|
||||||
|
|
||||||
def test_create_instance_with_bad_config_drive(self):
|
def test_create_instance_with_bad_config_drive(self):
|
||||||
image_href = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
|
param = 12345
|
||||||
flavor_ref = 'http://localhost/v3/flavors/3'
|
req, body = self._create_instance_body_of_config_drive(param)
|
||||||
body = {
|
self.assertRaises(exception.ValidationError,
|
||||||
'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,
|
|
||||||
self.controller.create, req, body=body)
|
self.controller.create, req, body=body)
|
||||||
|
|
||||||
def test_create_instance_without_config_drive(self):
|
def test_create_instance_without_config_drive(self):
|
||||||
image_href = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
|
param = True
|
||||||
flavor_ref = 'http://localhost/v3/flavors/3'
|
req, body = self._create_instance_body_of_config_drive(param)
|
||||||
body = {
|
del body['server'][config_drive.ATTRIBUTE_NAME]
|
||||||
'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"
|
|
||||||
res = self.controller.create(req, body=body).obj
|
res = self.controller.create(req, body=body).obj
|
||||||
|
|
||||||
server = res['server']
|
server = res['server']
|
||||||
self.assertEqual(FAKE_UUID, server['id'])
|
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