From 97a4a7e89fbfca53018e096236ea6ed7ab4c0cf2 Mon Sep 17 00:00:00 2001 From: Hiroaki Kobayashi Date: Fri, 2 Dec 2016 17:56:48 +0900 Subject: [PATCH] Update legacy code depending on Nova V2 API plugin Blazar-Nova uses Nova API plugin frameworks. The V2 API was removed in Nova commit a31d917af0cc5ecb55424598e7b812e02afbf28c. However, some lines of V2 dependent code were still included in Blazar-Nova. This patch updates the V2 dependent code to V2.1. NOTE: This commit fixes unit tests in order to unblock the gate, but doesn't restore instance reservation functionality due to major changes in support for Nova API extensions. Change-Id: Ie8252a350bd739845ee92e17c85f32385a7ddeb4 Closes-Bug: #1644680 --- .../api/extensions/default_reservation.py | 39 ++++++++++--------- blazarnova/api/extensions/reservation.py | 19 +++++---- blazarnova/tests/api/extensions/__init__.py | 24 ++---------- .../extensions/test_default_reservation.py | 28 ++++++++----- .../tests/api/extensions/test_reservation.py | 22 +++++------ requirements.txt | 1 + 6 files changed, 64 insertions(+), 69 deletions(-) diff --git a/blazarnova/api/extensions/default_reservation.py b/blazarnova/api/extensions/default_reservation.py index 82099b3..c9d349d 100644 --- a/blazarnova/api/extensions/default_reservation.py +++ b/blazarnova/api/extensions/default_reservation.py @@ -25,11 +25,13 @@ import json from nova.api.openstack import extensions from nova.api.openstack import wsgi +from nova import compute from nova import utils from oslo_config import cfg from oslo_log import log as logging from webob import exc + reservation_opts = [ cfg.StrOpt('reservation_start_date', default='now', @@ -49,12 +51,15 @@ CONF = cfg.CONF CONF.register_opts(reservation_opts) LOG = logging.getLogger(__name__) -authorize = extensions.extension_authorizer('compute', 'default_reservation') class DefaultReservationController(wsgi.Controller): """Add default reservation flags to every VM started.""" + def __init__(self, *args, **kwargs): + super(DefaultReservationController, self).__init__(*args, **kwargs) + self.compute_api = compute.API() + @wsgi.extends def create(self, req, body): """Add additional hints to the create server request. @@ -65,9 +70,7 @@ class DefaultReservationController(wsgi.Controller): if not self.is_valid_body(body, 'server'): raise exc.HTTPUnprocessableEntity() - if 'server' in body: - scheduler_hints = body['server'].get('scheduler_hints', {}) - elif 'os:scheduler_hints' in body: + if 'os:scheduler_hints' in body: scheduler_hints = body['os:scheduler_hints'] else: scheduler_hints = body.get('OS-SCH-HNT:scheduler_hints', {}) @@ -94,29 +97,27 @@ class DefaultReservationController(wsgi.Controller): default_hints = {'lease_params': json.dumps(lease_params)} - if 'server' in body: - if 'scheduler_hints' in body['server']: - body['server']['scheduler_hints'].update(default_hints) - else: - body['server']['scheduler_hints'] = default_hints + if 'os:scheduler_hints' in body: + body['os:scheduler_hints'].update(default_hints) + elif 'OS-SCH-HNT:scheduler_hints' in body: + body['OS-SCH-HNT:scheduler_hints'].update(default_hints) else: - attr = 'OS-SCH-HNT:scheduler_hints' - if 'os:scheduler_hints' in body: - body['os:scheduler_hints'].update(default_hints) - elif attr in body and 'lease_params' not in body[attr]: - body[attr].update(default_hints) - yield + body['os:scheduler_hints'] = default_hints -class Default_reservation(extensions.ExtensionDescriptor): +class Default_reservation(extensions.V21APIExtensionBase): """Instance reservation system.""" name = "DefaultReservation" alias = "os-default-instance-reservation" - updated = "2015-09-29T00:00:00Z" - namespace = "blazarnova" + updated = "2016-11-30T00:00:00Z" + version = 1 def get_controller_extensions(self): + return [] + + def get_resources(self): controller = DefaultReservationController() - extension = extensions.ControllerExtension(self, 'servers', controller) + extension = extensions.ResourceExtension( + self.alias, controller, member_actions={"action": "POST"}) return [extension] diff --git a/blazarnova/api/extensions/reservation.py b/blazarnova/api/extensions/reservation.py index 2b1aa06..e903f10 100644 --- a/blazarnova/api/extensions/reservation.py +++ b/blazarnova/api/extensions/reservation.py @@ -29,7 +29,6 @@ except ImportError: blazar_client = None from blazarnova.i18n import _ # noqa - from nova.api.openstack import extensions from nova.api.openstack import wsgi from nova import compute @@ -38,7 +37,6 @@ from oslo_log import log as logging LOG = logging.getLogger(__name__) -authorize = extensions.extension_authorizer('compute', 'reservation') class ReservationController(wsgi.Controller): @@ -51,8 +49,12 @@ class ReservationController(wsgi.Controller): def create(self, req, resp_obj, body): """Support Blazar usage for Nova VMs.""" - scheduler_hints = body.get('server', {}).get('scheduler_hints', {}) - lease_params = scheduler_hints.get('lease_params') + if 'os:scheduler_hints' in body: + scheduler_hints = body['os:scheduler_hints'] + else: + scheduler_hints = body.get('OS-SCH-HNT:scheduler_hints', {}) + + lease_params = scheduler_hints.get('lease_params', {}) if lease_params: try: @@ -172,15 +174,18 @@ class LeaseTransaction(object): self.nova_ctx = nova_ctx -class Reservation(extensions.ExtensionDescriptor): +class Reservation(extensions.V21APIExtensionBase): """Instance reservation system.""" name = "Reservation" alias = "os-instance-reservation" - updated = "2015-09-29T00:00:00Z" - namespace = "blazarnova" + updated = "2016-11-30T00:00:00Z" + version = 1 def get_controller_extensions(self): controller = ReservationController() extension = extensions.ControllerExtension(self, 'servers', controller) return [extension] + + def get_resources(self): + return [] diff --git a/blazarnova/tests/api/extensions/__init__.py b/blazarnova/tests/api/extensions/__init__.py index f430f07..9a9856e 100644 --- a/blazarnova/tests/api/extensions/__init__.py +++ b/blazarnova/tests/api/extensions/__init__.py @@ -15,21 +15,19 @@ import datetime -from nova.tests.unit.api.openstack import fakes - import mock + from nova.api.openstack import compute from nova.compute import api as compute_api from nova import context from nova import test +from nova.tests.unit.api.openstack import fakes from nova import utils from oslo_config import cfg UUID = fakes.FAKE_UUID CONF = cfg.CONF -CONF.import_opt('osapi_compute_ext_list', - 'nova.api.openstack.compute.legacy_v2.contrib') CONF.import_opt('reservation_start_date', 'blazarnova.api.extensions.default_reservation') CONF.import_opt('reservation_length_hours', @@ -59,22 +57,12 @@ class BaseExtensionTestCase(test.TestCase): """Set up testing environment.""" super(BaseExtensionTestCase, self).setUp() self.fake_instance = fakes.stub_instance(1, uuid=UUID) - self.flags( - osapi_compute_extension=[ - 'nova.api.openstack.compute.legacy_v2.contrib.' - 'select_extensions', - 'blazarnova.api.extensions.default_reservation.' - 'Default_reservation', - 'blazarnova.api.extensions.reservation.Reservation' - ], - osapi_compute_ext_list=['Scheduler_hints']) self.lease_controller = mock.MagicMock() - self.lease_controller.create = mock.MagicMock() self.mock_client = mock.MagicMock() self.mock_client.lease = self.lease_controller - self.req = fakes.HTTPRequest.blank('/fake/servers') + self.req = fakes.HTTPRequestV21.blank('/fake/servers') self.req.method = 'POST' self.req.content_type = 'application/json' self.req.environ.update({ @@ -86,9 +74,8 @@ class BaseExtensionTestCase(test.TestCase): }) self.l_name = 'lease_123' - self.app = compute.APIRouter(init_only=('servers',)) + self.app = compute.APIRouterV21() self.stubs.Set(utils, 'generate_uid', lambda name, size: self.l_name) - self.stubs.Set(compute_api.API, 'create', self._fake_create) self.stubs.Set(compute_api.API, 'get', self._fake_get) self.stubs.Set(compute_api.API, 'shelve', self._fake_shelve) @@ -101,9 +88,6 @@ class BaseExtensionTestCase(test.TestCase): self.default_lease_end = lease_end.strftime('%Y-%m-%d %H:%M') self.default_lease_start = 'now' - def _fake_create(self, *args, **kwargs): - return [self.fake_instance], '' - def _fake_get(self, *args, **kwargs): self.fake_instance['vm_state'] = 'active' return InstanceWrapper(self.fake_instance) diff --git a/blazarnova/tests/api/extensions/test_default_reservation.py b/blazarnova/tests/api/extensions/test_default_reservation.py index 605a8c4..1fd40f6 100644 --- a/blazarnova/tests/api/extensions/test_default_reservation.py +++ b/blazarnova/tests/api/extensions/test_default_reservation.py @@ -14,9 +14,12 @@ # limitations under the License. import mock -from oslo_serialization import jsonutils +from blazarnova.api.extensions import default_reservation +from blazarnova.api.extensions import reservation from blazarnova.tests.api import extensions +from nova.api.openstack import wsgi +from oslo_serialization import jsonutils class BlazarDefaultReservationTestCase(extensions.BaseExtensionTestCase): @@ -30,6 +33,9 @@ class BlazarDefaultReservationTestCase(extensions.BaseExtensionTestCase): def setUp(self): """Set up testing environment.""" super(BlazarDefaultReservationTestCase, self).setUp() + self.rsrv_controller = reservation.ReservationController() + self.default_rsrv_controller = default_reservation\ + .DefaultReservationController() @mock.patch('blazarnova.api.extensions.reservation.blazar_client') def test_create_with_default(self, mock_module): @@ -48,20 +54,21 @@ class BlazarDefaultReservationTestCase(extensions.BaseExtensionTestCase): } self.req.body = jsonutils.dumps(body) - res = self.req.get_response(self.app) + self.default_rsrv_controller.create(self.req, body) + resp_obj = wsgi.ResponseObject({'server': {'id': 'fakeId'}}) + self.rsrv_controller.create(self.req, resp_obj, body) mock_module.Client.assert_called_once_with(climate_url='fake', auth_token='fake_token') + self.lease_controller.create.assert_called_once_with( reservations=[ {'resource_type': 'virtual:instance', - 'resource_id': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'}], + 'resource_id': 'fakeId'}], end=self.default_lease_end, events=[], start='now', - name='lease_123') - - self.assertEqual(202, res.status_int) + name=self.l_name) @mock.patch('blazarnova.api.extensions.reservation.blazar_client') def test_create_with_passed_args(self, mock_module): @@ -82,17 +89,18 @@ class BlazarDefaultReservationTestCase(extensions.BaseExtensionTestCase): } self.req.body = jsonutils.dumps(body) - res = self.req.get_response(self.app) + self.default_rsrv_controller.create(self.req, body) + resp_obj = wsgi.ResponseObject({'server': {'id': 'fakeId'}}) + self.rsrv_controller.create(self.req, resp_obj, body) mock_module.Client.assert_called_once_with(climate_url='fake', auth_token='fake_token') + self.lease_controller.create.assert_called_once_with( reservations=[ {'resource_type': 'virtual:instance', - 'resource_id': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'}], + 'resource_id': 'fakeId'}], end=self.default_lease_end, events=[], start='now', name='other_name') - - self.assertEqual(202, res.status_int) diff --git a/blazarnova/tests/api/extensions/test_reservation.py b/blazarnova/tests/api/extensions/test_reservation.py index bfce5f8..4806e78 100644 --- a/blazarnova/tests/api/extensions/test_reservation.py +++ b/blazarnova/tests/api/extensions/test_reservation.py @@ -14,15 +14,17 @@ # limitations under the License. import mock -from oslo_serialization import jsonutils +from blazarnova.api.extensions import reservation from blazarnova.tests.api import extensions +from nova.api.openstack import wsgi +from oslo_serialization import jsonutils class BlazarReservationTestCase(extensions.BaseExtensionTestCase): """Blazar API extensions test case. - This test case provides tests for Default_reservation extension working + This test case provides tests for Reservation extension working together with Reservation extension passing hints to Nova and sending lease creation request to Blazar. """ @@ -30,13 +32,7 @@ class BlazarReservationTestCase(extensions.BaseExtensionTestCase): def setUp(self): """Set up testing environment.""" super(BlazarReservationTestCase, self).setUp() - self.flags( - osapi_compute_extension=[ - 'nova.api.openstack.compute.legacy_v2.contrib.' - 'select_extensions', - 'blazarnova.api.extensions.reservation.Reservation' - ], - osapi_compute_ext_list=['Scheduler_hints']) + self.controller = reservation.ReservationController() @mock.patch('blazarnova.api.extensions.reservation.blazar_client') def test_create(self, mock_module): @@ -57,17 +53,17 @@ class BlazarReservationTestCase(extensions.BaseExtensionTestCase): } self.req.body = jsonutils.dumps(body) - res = self.req.get_response(self.app) + resp_obj = wsgi.ResponseObject({'server': {'id': 'fakeId'}}) + self.controller.create(self.req, resp_obj, body) mock_module.Client.assert_called_once_with(climate_url='fake', auth_token='fake_token') + self.lease_controller.create.assert_called_once_with( reservations=[ {'resource_type': 'virtual:instance', - 'resource_id': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'}], + 'resource_id': 'fakeId'}], end='2014-02-10 12:00', events=[], start='2014-02-09 12:00', name='some_name') - - self.assertEqual(202, res.status_int) diff --git a/requirements.txt b/requirements.txt index 9dbc011..b7eed5c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ # The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. +kombu>=3.0.25,<4.0.0 # BSD