diff --git a/doc/v3/api_samples/os-cloudpipe/cloud-pipe-create-req.json b/doc/v3/api_samples/os-cloudpipe/cloud-pipe-create-req.json index dd1cf348c6..74e69e27da 100644 --- a/doc/v3/api_samples/os-cloudpipe/cloud-pipe-create-req.json +++ b/doc/v3/api_samples/os-cloudpipe/cloud-pipe-create-req.json @@ -1,5 +1,5 @@ { "cloudpipe": { - "project_id": "cloudpipe-059f21e3-c20e-4efc-9e7a-eba2ab3c6f9a" + "project_id": "059f21e3-c20e-4efc-9e7a-eba2ab3c6f9a" } -} \ No newline at end of file +} diff --git a/doc/v3/api_samples/os-cloudpipe/cloud-pipe-get-resp.json b/doc/v3/api_samples/os-cloudpipe/cloud-pipe-get-resp.json index d6773dfa5a..caaa22774a 100644 --- a/doc/v3/api_samples/os-cloudpipe/cloud-pipe-get-resp.json +++ b/doc/v3/api_samples/os-cloudpipe/cloud-pipe-get-resp.json @@ -4,10 +4,10 @@ "created_at": "2012-11-27T17:18:01Z", "instance_id": "27deecdb-baa3-4a26-9c82-32994b815b01", "internal_ip": "192.168.0.3", - "project_id": "cloudpipe-fa1765bd-a352-49c7-a6b7-8ee108a3cb0c", + "project_id": "fa1765bd-a352-49c7-a6b7-8ee108a3cb0c", "public_ip": "127.0.0.1", "public_port": 22, "state": "down" } ] -} \ No newline at end of file +} diff --git a/nova/api/openstack/compute/plugins/v3/cloudpipe.py b/nova/api/openstack/compute/plugins/v3/cloudpipe.py index 6d57d15c72..9865ca4598 100644 --- a/nova/api/openstack/compute/plugins/v3/cloudpipe.py +++ b/nova/api/openstack/compute/plugins/v3/cloudpipe.py @@ -110,6 +110,7 @@ class CloudpipeController(wsgi.Controller): return rv @extensions.expected_errors((400, 403)) + @validation.schema(cloudpipe.create) def create(self, req, body): """Create a new cloudpipe instance, if none exists. diff --git a/nova/api/openstack/compute/schemas/v3/cloudpipe.py b/nova/api/openstack/compute/schemas/v3/cloudpipe.py index d4e0183772..635b384e97 100644 --- a/nova/api/openstack/compute/schemas/v3/cloudpipe.py +++ b/nova/api/openstack/compute/schemas/v3/cloudpipe.py @@ -15,6 +15,21 @@ from nova.api.validation import parameter_types +create = { + 'type': 'object', + 'properties': { + 'cloudpipe': { + 'type': 'object', + 'properties': { + 'project_id': parameter_types.project_id, + }, + 'additionalProperties': False, + }, + }, + 'required': ['cloudpipe'], + 'additionalProperties': False, +} + update = { 'type': 'object', 'properties': { diff --git a/nova/tests/api/openstack/compute/contrib/test_cloudpipe.py b/nova/tests/api/openstack/compute/contrib/test_cloudpipe.py index 129453ba37..d2358f3bf3 100644 --- a/nova/tests/api/openstack/compute/contrib/test_cloudpipe.py +++ b/nova/tests/api/openstack/compute/contrib/test_cloudpipe.py @@ -13,13 +13,15 @@ # License for the specific language governing permissions and limitations # under the License. +import uuid as uuid_lib + from lxml import etree from oslo.config import cfg from oslo.utils import timeutils from webob import exc from nova.api.openstack.compute.contrib import cloudpipe as cloudpipe_v2 -from nova.api.openstack.compute.contrib import cloudpipe as cloudpipe_v21 +from nova.api.openstack.compute.plugins.v3 import cloudpipe as cloudpipe_v21 from nova.api.openstack import wsgi from nova.compute import utils as compute_utils from nova import exception @@ -33,11 +35,15 @@ CONF = cfg.CONF CONF.import_opt('vpn_image_id', 'nova.cloudpipe.pipelib') +project_id = str(uuid_lib.uuid4().hex) +uuid = str(uuid_lib.uuid4()) + + def fake_vpn_instance(): return { 'id': 7, 'image_ref': CONF.vpn_image_id, 'vm_state': 'active', 'created_at': timeutils.parse_strtime('1981-10-20T00:00:00.000000'), - 'uuid': 7777, 'project_id': 'other', + 'uuid': uuid, 'project_id': project_id, } @@ -75,15 +81,15 @@ class CloudpipeTestV21(test.NoDBTestCase): compute_api_get_all) req = fakes.HTTPRequest.blank(self.url) res_dict = self.controller.index(req) - response = {'cloudpipes': [{'project_id': 'other', - 'instance_id': 7777, + response = {'cloudpipes': [{'project_id': project_id, + 'instance_id': uuid, 'created_at': '1981-10-20T00:00:00Z'}]} self.assertEqual(res_dict, response) def test_cloudpipe_list(self): def network_api_get(context, network_id): - self.assertEqual(context.project_id, 'other') + self.assertEqual(context.project_id, project_id) return {'vpn_public_address': '127.0.0.1', 'vpn_public_port': 22} @@ -98,12 +104,12 @@ class CloudpipeTestV21(test.NoDBTestCase): compute_api_get_all) req = fakes.HTTPRequest.blank(self.url) res_dict = self.controller.index(req) - response = {'cloudpipes': [{'project_id': 'other', + response = {'cloudpipes': [{'project_id': project_id, 'internal_ip': '192.168.1.100', 'public_ip': '127.0.0.1', 'public_port': 22, 'state': 'running', - 'instance_id': 7777, + 'instance_id': uuid, 'created_at': '1981-10-20T00:00:00Z'}]} self.assertThat(res_dict, matchers.DictMatches(response)) @@ -113,11 +119,11 @@ class CloudpipeTestV21(test.NoDBTestCase): self.stubs.Set(self.controller.cloudpipe, 'launch_vpn_instance', launch_vpn_instance) - body = {'cloudpipe': {'project_id': 1}} + body = {'cloudpipe': {'project_id': project_id}} req = fakes.HTTPRequest.blank(self.url) - res_dict = self.controller.create(req, body) + res_dict = self.controller.create(req, body=body) - response = {'instance_id': 7777} + response = {'instance_id': uuid} self.assertEqual(res_dict, response) def test_cloudpipe_create_no_networks(self): @@ -126,10 +132,10 @@ class CloudpipeTestV21(test.NoDBTestCase): self.stubs.Set(self.controller.cloudpipe, 'launch_vpn_instance', launch_vpn_instance) - body = {'cloudpipe': {'project_id': 1}} + body = {'cloudpipe': {'project_id': project_id}} req = fakes.HTTPRequest.blank(self.url) self.assertRaises(exc.HTTPBadRequest, - self.controller.create, req, body) + self.controller.create, req, body=body) def test_cloudpipe_create_already_running(self): def launch_vpn_instance(*args, **kwargs): @@ -139,16 +145,25 @@ class CloudpipeTestV21(test.NoDBTestCase): launch_vpn_instance) self.stubs.Set(self.controller.compute_api, "get_all", compute_api_get_all) - body = {'cloudpipe': {'project_id': 1}} + body = {'cloudpipe': {'project_id': project_id}} req = fakes.HTTPRequest.blank(self.url) - res_dict = self.controller.create(req, body) - response = {'instance_id': 7777} + res_dict = self.controller.create(req, body=body) + response = {'instance_id': uuid} self.assertEqual(res_dict, response) + def test_cloudpipe_create_with_bad_project_id_failed(self): + body = {'cloudpipe': {'project_id': 'bad.project.id'}} + req = fakes.HTTPRequest.blank(self.url) + self.assertRaises(exception.ValidationError, + self.controller.create, req, body=body) + class CloudpipeTestV2(CloudpipeTestV21): cloudpipe = cloudpipe_v2 + def test_cloudpipe_create_with_bad_project_id_failed(self): + pass + class CloudpipesXMLSerializerTestV2(test.NoDBTestCase): def test_default_serializer(self): diff --git a/nova/tests/integrated/v3/test_cloudpipe.py b/nova/tests/integrated/v3/test_cloudpipe.py index a3042eb736..54c510feab 100644 --- a/nova/tests/integrated/v3/test_cloudpipe.py +++ b/nova/tests/integrated/v3/test_cloudpipe.py @@ -46,13 +46,13 @@ class CloudPipeSampleTest(api_sample_base.ApiSampleTestBaseV3): network_api_get) def generalize_subs(self, subs, vanilla_regexes): - subs['project_id'] = 'cloudpipe-[0-9a-f-]+' + subs['project_id'] = '[0-9a-f-]+' return subs def test_cloud_pipe_create(self): # Get api samples of cloud pipe extension creation. self.flags(vpn_image_id=fake.get_valid_image_id()) - project = {'project_id': 'cloudpipe-' + str(uuid_lib.uuid4())} + project = {'project_id': str(uuid_lib.uuid4().hex)} response = self._do_post('os-cloudpipe', 'cloud-pipe-create-req', project) subs = self._get_regexes()