From 71f1fbc8a7d86ca4e7ccdad8cce251ceb4dc243a Mon Sep 17 00:00:00 2001 From: ghanshyam Date: Fri, 29 Jun 2018 09:25:08 +0300 Subject: [PATCH] Merge server create for scheduler hint extension As nova extensions has been deprecated already and goal is to merge all scattered code into main controller side. Currently schema and request/response extended code are there among all extensions. This commit merge the server_create for scheduler hint extensions. Partially implements: blueprint api-extensions-merge-rocky Change-Id: I0c5ceb4ed69c356aedc85cff74ef0a5d93c8f93e --- nova/api/openstack/compute/scheduler_hints.py | 27 ---- nova/api/openstack/compute/servers.py | 9 +- .../openstack/compute/test_scheduler_hints.py | 127 ------------------ .../api/openstack/compute/test_serversV21.py | 56 ++++++++ 4 files changed, 63 insertions(+), 156 deletions(-) delete mode 100644 nova/api/openstack/compute/scheduler_hints.py delete mode 100644 nova/tests/unit/api/openstack/compute/test_scheduler_hints.py diff --git a/nova/api/openstack/compute/scheduler_hints.py b/nova/api/openstack/compute/scheduler_hints.py deleted file mode 100644 index c9e507a8ca..0000000000 --- a/nova/api/openstack/compute/scheduler_hints.py +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# -# 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. - - -# NOTE(gmann): Accepting request body in this function to fetch "scheduler -# hint". This is a workaround to allow OS_SCH-HNT at the top level -# of the body request, but that it will be changed in the future to be a -# subset of the servers dict. -def server_create(server_dict, create_kwargs, req_body): - scheduler_hints = {} - if 'os:scheduler_hints' in req_body: - scheduler_hints = req_body['os:scheduler_hints'] - elif 'OS-SCH-HNT:scheduler_hints' in req_body: - scheduler_hints = req_body['OS-SCH-HNT:scheduler_hints'] - - create_kwargs['scheduler_hints'] = scheduler_hints diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py index f24d9450cb..714db029d7 100644 --- a/nova/api/openstack/compute/servers.py +++ b/nova/api/openstack/compute/servers.py @@ -33,7 +33,6 @@ from nova.api.openstack.compute import config_drive from nova.api.openstack.compute import helpers from nova.api.openstack.compute import keypairs from nova.api.openstack.compute import multiple_create -from nova.api.openstack.compute import scheduler_hints from nova.api.openstack.compute.schemas import servers as schema_servers from nova.api.openstack.compute.views import servers as views_servers from nova.api.openstack import wsgi @@ -72,7 +71,6 @@ class ServersController(wsgi.Controller): config_drive.server_create, keypairs.server_create, multiple_create.server_create, - scheduler_hints.server_create, ] @staticmethod @@ -440,6 +438,13 @@ class ServersController(wsgi.Controller): create_kwargs['security_groups'] = list( set(create_kwargs['security_groups'])) + scheduler_hints = {} + if 'os:scheduler_hints' in body: + scheduler_hints = body['os:scheduler_hints'] + elif 'OS-SCH-HNT:scheduler_hints' in body: + scheduler_hints = body['OS-SCH-HNT:scheduler_hints'] + create_kwargs['scheduler_hints'] = scheduler_hints + availability_zone = server_dict.pop("availability_zone", None) if api_version_request.is_supported(req, min_version='2.52'): diff --git a/nova/tests/unit/api/openstack/compute/test_scheduler_hints.py b/nova/tests/unit/api/openstack/compute/test_scheduler_hints.py deleted file mode 100644 index c22cfd479d..0000000000 --- a/nova/tests/unit/api/openstack/compute/test_scheduler_hints.py +++ /dev/null @@ -1,127 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# 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 oslo_serialization import jsonutils - -from nova.api.openstack import compute -from nova import test -from nova.tests.unit.api.openstack import fakes - - -UUID = fakes.FAKE_UUID - - -class SchedulerHintsTestCaseV21(test.TestCase): - - def setUp(self): - super(SchedulerHintsTestCaseV21, self).setUp() - self.fake_instance = fakes.stub_instance_obj(None, id=1, uuid=UUID) - self._set_up_router() - - def _set_up_router(self): - self.app = compute.APIRouterV21() - - def _get_request(self): - return fakes.HTTPRequest.blank('/fake/servers') - - def test_create_server_without_hints(self): - - def fake_create(*args, **kwargs): - self.assertEqual(kwargs['scheduler_hints'], {}) - return ([self.fake_instance], '') - - self.stub_out('nova.compute.api.API.create', fake_create) - - req = self._get_request() - req.method = 'POST' - req.content_type = 'application/json' - body = {'server': { - 'name': 'server_test', - 'imageRef': 'cedef40a-ed67-4d10-800e-17455edce175', - 'flavorRef': '1', - }} - - req.body = jsonutils.dump_as_bytes(body) - res = req.get_response(self.app) - self.assertEqual(202, res.status_int) - - def _test_create_server_with_hint(self, hint): - - def fake_create(*args, **kwargs): - self.assertEqual(kwargs['scheduler_hints'], hint) - return ([self.fake_instance], '') - - self.stub_out('nova.compute.api.API.create', fake_create) - - req = self._get_request() - req.method = 'POST' - req.content_type = 'application/json' - body = { - 'server': { - 'name': 'server_test', - 'imageRef': 'cedef40a-ed67-4d10-800e-17455edce175', - 'flavorRef': '1', - }, - 'os:scheduler_hints': hint, - } - - req.body = jsonutils.dump_as_bytes(body) - res = req.get_response(self.app) - self.assertEqual(202, res.status_int) - - def test_create_server_with_group_hint(self): - self._test_create_server_with_hint({'group': UUID}) - - def test_create_server_with_non_uuid_group_hint(self): - self._create_server_with_scheduler_hints_bad_request( - {'group': 'non-uuid'}) - - def test_create_server_with_different_host_hint(self): - self._test_create_server_with_hint( - {'different_host': '9c47bf55-e9d8-42da-94ab-7f9e80cd1857'}) - - self._test_create_server_with_hint( - {'different_host': ['9c47bf55-e9d8-42da-94ab-7f9e80cd1857', - '82412fa6-0365-43a9-95e4-d8b20e00c0de']}) - - def _create_server_with_scheduler_hints_bad_request(self, param): - req = self._get_request() - req.method = 'POST' - req.content_type = 'application/json' - body = { - 'server': { - 'name': 'server_test', - 'imageRef': 'cedef40a-ed67-4d10-800e-17455edce175', - 'flavorRef': '1', - }, - 'os:scheduler_hints': param, - } - req.body = jsonutils.dump_as_bytes(body) - res = req.get_response(self.app) - self.assertEqual(400, res.status_int) - - def test_create_server_bad_hints_non_dict(self): - self._create_server_with_scheduler_hints_bad_request('non-dict') - - def test_create_server_bad_hints_long_group(self): - param = {'group': 'a' * 256} - self._create_server_with_scheduler_hints_bad_request(param) - - def test_create_server_with_bad_different_host_hint(self): - param = {'different_host': 'non-server-id'} - self._create_server_with_scheduler_hints_bad_request(param) - - param = {'different_host': ['non-server-id01', 'non-server-id02']} - self._create_server_with_scheduler_hints_bad_request(param) diff --git a/nova/tests/unit/api/openstack/compute/test_serversV21.py b/nova/tests/unit/api/openstack/compute/test_serversV21.py index 8aeb6e63be..c46a01ba78 100644 --- a/nova/tests/unit/api/openstack/compute/test_serversV21.py +++ b/nova/tests/unit/api/openstack/compute/test_serversV21.py @@ -3714,6 +3714,34 @@ class ServersControllerCreateTest(test.TestCase): test_group = objects.InstanceGroup.get_by_uuid(ctxt, test_group.uuid) self.assertIn(server['id'], test_group.members) + def _test_create_instance_with_group_hint(self, hint, + hint_name='os:scheduler_hints'): + def fake_instance_destroy(context, uuid, constraint): + return fakes.stub_instance(1) + + def fake_create(*args, **kwargs): + self.assertEqual(kwargs['scheduler_hints'], hint) + return ([fakes.stub_instance(1)], '') + + self.stub_out('nova.compute.api.API.create', fake_create) + self.stub_out('nova.db.instance_destroy', fake_instance_destroy) + self.body[hint_name] = hint + self.req.body = jsonutils.dump_as_bytes(self.body) + return self.controller.create(self.req, body=self.body).obj['server'] + + def test_create_instance_with_group_hint_legacy(self): + self._test_create_instance_with_group_hint( + {'different_host': '9c47bf55-e9d8-42da-94ab-7f9e80cd1857'}, + hint_name='OS-SCH-HNT:scheduler_hints') + + def test_create_server_with_different_host_hint(self): + self._test_create_instance_with_group_hint( + {'different_host': '9c47bf55-e9d8-42da-94ab-7f9e80cd1857'}) + + self._test_create_instance_with_group_hint( + {'different_host': ['9c47bf55-e9d8-42da-94ab-7f9e80cd1857', + '82412fa6-0365-43a9-95e4-d8b20e00c0de']}) + def test_create_instance_with_group_hint_group_not_found(self): def fake_instance_destroy(context, uuid, constraint): return fakes.stub_instance(1) @@ -3732,6 +3760,34 @@ class ServersControllerCreateTest(test.TestCase): self.assertRaises(exception.ValidationError, self.controller.create, self.req, body=self.body) + def test_create_server_bad_hints_non_dict(self): + sch_hints = ['os:scheduler_hints', 'OS-SCH-HNT:scheduler_hints'] + for hint in sch_hints: + self.body[hint] = 'non-dict' + self.req.body = jsonutils.dump_as_bytes(self.body) + self.assertRaises(exception.ValidationError, + self.controller.create, self.req, body=self.body) + + def test_create_server_bad_hints_long_group(self): + self.body['os:scheduler_hints'] = { + 'group': 'a' * 256} + self.req.body = jsonutils.dump_as_bytes(self.body) + self.assertRaises(exception.ValidationError, + self.controller.create, self.req, body=self.body) + + def test_create_server_with_bad_different_host_hint(self): + self.body['os:scheduler_hints'] = { + 'different_host': 'non-server-id'} + self.req.body = jsonutils.dump_as_bytes(self.body) + self.assertRaises(exception.ValidationError, + self.controller.create, self.req, body=self.body) + + self.body['os:scheduler_hints'] = { + 'different_host': ['non-server-id01', 'non-server-id02']} + self.req.body = jsonutils.dump_as_bytes(self.body) + self.assertRaises(exception.ValidationError, + self.controller.create, self.req, body=self.body) + @mock.patch.object(compute_api.API, 'create', side_effect=exception.PortInUse(port_id=uuids.port)) def test_create_instance_with_neutronv2_port_in_use(self, mock_create):