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
This commit is contained in:
Hiroaki Kobayashi 2016-12-02 17:56:48 +09:00 committed by Pierre Riteau
parent 7a525b6d78
commit 97a4a7e89f
6 changed files with 64 additions and 69 deletions

View File

@ -25,11 +25,13 @@ import json
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova import compute
from nova import utils from nova import utils
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
from webob import exc from webob import exc
reservation_opts = [ reservation_opts = [
cfg.StrOpt('reservation_start_date', cfg.StrOpt('reservation_start_date',
default='now', default='now',
@ -49,12 +51,15 @@ CONF = cfg.CONF
CONF.register_opts(reservation_opts) CONF.register_opts(reservation_opts)
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
authorize = extensions.extension_authorizer('compute', 'default_reservation')
class DefaultReservationController(wsgi.Controller): class DefaultReservationController(wsgi.Controller):
"""Add default reservation flags to every VM started.""" """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 @wsgi.extends
def create(self, req, body): def create(self, req, body):
"""Add additional hints to the create server request. """Add additional hints to the create server request.
@ -65,9 +70,7 @@ class DefaultReservationController(wsgi.Controller):
if not self.is_valid_body(body, 'server'): if not self.is_valid_body(body, 'server'):
raise exc.HTTPUnprocessableEntity() raise exc.HTTPUnprocessableEntity()
if 'server' in body: if 'os:scheduler_hints' in body:
scheduler_hints = body['server'].get('scheduler_hints', {})
elif 'os:scheduler_hints' in body:
scheduler_hints = body['os:scheduler_hints'] scheduler_hints = body['os:scheduler_hints']
else: else:
scheduler_hints = body.get('OS-SCH-HNT:scheduler_hints', {}) 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)} default_hints = {'lease_params': json.dumps(lease_params)}
if 'server' in body: if 'os:scheduler_hints' in body:
if 'scheduler_hints' in body['server']: body['os:scheduler_hints'].update(default_hints)
body['server']['scheduler_hints'].update(default_hints) elif 'OS-SCH-HNT:scheduler_hints' in body:
else: body['OS-SCH-HNT:scheduler_hints'].update(default_hints)
body['server']['scheduler_hints'] = default_hints
else: else:
attr = 'OS-SCH-HNT:scheduler_hints' body['os:scheduler_hints'] = default_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
class Default_reservation(extensions.ExtensionDescriptor): class Default_reservation(extensions.V21APIExtensionBase):
"""Instance reservation system.""" """Instance reservation system."""
name = "DefaultReservation" name = "DefaultReservation"
alias = "os-default-instance-reservation" alias = "os-default-instance-reservation"
updated = "2015-09-29T00:00:00Z" updated = "2016-11-30T00:00:00Z"
namespace = "blazarnova" version = 1
def get_controller_extensions(self): def get_controller_extensions(self):
return []
def get_resources(self):
controller = DefaultReservationController() controller = DefaultReservationController()
extension = extensions.ControllerExtension(self, 'servers', controller) extension = extensions.ResourceExtension(
self.alias, controller, member_actions={"action": "POST"})
return [extension] return [extension]

View File

@ -29,7 +29,6 @@ except ImportError:
blazar_client = None blazar_client = None
from blazarnova.i18n import _ # noqa from blazarnova.i18n import _ # noqa
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova import compute from nova import compute
@ -38,7 +37,6 @@ from oslo_log import log as logging
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
authorize = extensions.extension_authorizer('compute', 'reservation')
class ReservationController(wsgi.Controller): class ReservationController(wsgi.Controller):
@ -51,8 +49,12 @@ class ReservationController(wsgi.Controller):
def create(self, req, resp_obj, body): def create(self, req, resp_obj, body):
"""Support Blazar usage for Nova VMs.""" """Support Blazar usage for Nova VMs."""
scheduler_hints = body.get('server', {}).get('scheduler_hints', {}) if 'os:scheduler_hints' in body:
lease_params = scheduler_hints.get('lease_params') 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: if lease_params:
try: try:
@ -172,15 +174,18 @@ class LeaseTransaction(object):
self.nova_ctx = nova_ctx self.nova_ctx = nova_ctx
class Reservation(extensions.ExtensionDescriptor): class Reservation(extensions.V21APIExtensionBase):
"""Instance reservation system.""" """Instance reservation system."""
name = "Reservation" name = "Reservation"
alias = "os-instance-reservation" alias = "os-instance-reservation"
updated = "2015-09-29T00:00:00Z" updated = "2016-11-30T00:00:00Z"
namespace = "blazarnova" version = 1
def get_controller_extensions(self): def get_controller_extensions(self):
controller = ReservationController() controller = ReservationController()
extension = extensions.ControllerExtension(self, 'servers', controller) extension = extensions.ControllerExtension(self, 'servers', controller)
return [extension] return [extension]
def get_resources(self):
return []

View File

@ -15,21 +15,19 @@
import datetime import datetime
from nova.tests.unit.api.openstack import fakes
import mock import mock
from nova.api.openstack import compute from nova.api.openstack import compute
from nova.compute import api as compute_api from nova.compute import api as compute_api
from nova import context from nova import context
from nova import test from nova import test
from nova.tests.unit.api.openstack import fakes
from nova import utils from nova import utils
from oslo_config import cfg from oslo_config import cfg
UUID = fakes.FAKE_UUID UUID = fakes.FAKE_UUID
CONF = cfg.CONF CONF = cfg.CONF
CONF.import_opt('osapi_compute_ext_list',
'nova.api.openstack.compute.legacy_v2.contrib')
CONF.import_opt('reservation_start_date', CONF.import_opt('reservation_start_date',
'blazarnova.api.extensions.default_reservation') 'blazarnova.api.extensions.default_reservation')
CONF.import_opt('reservation_length_hours', CONF.import_opt('reservation_length_hours',
@ -59,22 +57,12 @@ class BaseExtensionTestCase(test.TestCase):
"""Set up testing environment.""" """Set up testing environment."""
super(BaseExtensionTestCase, self).setUp() super(BaseExtensionTestCase, self).setUp()
self.fake_instance = fakes.stub_instance(1, uuid=UUID) 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 = mock.MagicMock()
self.lease_controller.create = mock.MagicMock()
self.mock_client = mock.MagicMock() self.mock_client = mock.MagicMock()
self.mock_client.lease = self.lease_controller 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.method = 'POST'
self.req.content_type = 'application/json' self.req.content_type = 'application/json'
self.req.environ.update({ self.req.environ.update({
@ -86,9 +74,8 @@ class BaseExtensionTestCase(test.TestCase):
}) })
self.l_name = 'lease_123' 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(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, 'get', self._fake_get)
self.stubs.Set(compute_api.API, 'shelve', self._fake_shelve) 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_end = lease_end.strftime('%Y-%m-%d %H:%M')
self.default_lease_start = 'now' self.default_lease_start = 'now'
def _fake_create(self, *args, **kwargs):
return [self.fake_instance], ''
def _fake_get(self, *args, **kwargs): def _fake_get(self, *args, **kwargs):
self.fake_instance['vm_state'] = 'active' self.fake_instance['vm_state'] = 'active'
return InstanceWrapper(self.fake_instance) return InstanceWrapper(self.fake_instance)

View File

@ -14,9 +14,12 @@
# limitations under the License. # limitations under the License.
import mock 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 blazarnova.tests.api import extensions
from nova.api.openstack import wsgi
from oslo_serialization import jsonutils
class BlazarDefaultReservationTestCase(extensions.BaseExtensionTestCase): class BlazarDefaultReservationTestCase(extensions.BaseExtensionTestCase):
@ -30,6 +33,9 @@ class BlazarDefaultReservationTestCase(extensions.BaseExtensionTestCase):
def setUp(self): def setUp(self):
"""Set up testing environment.""" """Set up testing environment."""
super(BlazarDefaultReservationTestCase, self).setUp() super(BlazarDefaultReservationTestCase, self).setUp()
self.rsrv_controller = reservation.ReservationController()
self.default_rsrv_controller = default_reservation\
.DefaultReservationController()
@mock.patch('blazarnova.api.extensions.reservation.blazar_client') @mock.patch('blazarnova.api.extensions.reservation.blazar_client')
def test_create_with_default(self, mock_module): def test_create_with_default(self, mock_module):
@ -48,20 +54,21 @@ class BlazarDefaultReservationTestCase(extensions.BaseExtensionTestCase):
} }
self.req.body = jsonutils.dumps(body) 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', mock_module.Client.assert_called_once_with(climate_url='fake',
auth_token='fake_token') auth_token='fake_token')
self.lease_controller.create.assert_called_once_with( self.lease_controller.create.assert_called_once_with(
reservations=[ reservations=[
{'resource_type': 'virtual:instance', {'resource_type': 'virtual:instance',
'resource_id': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'}], 'resource_id': 'fakeId'}],
end=self.default_lease_end, end=self.default_lease_end,
events=[], events=[],
start='now', start='now',
name='lease_123') name=self.l_name)
self.assertEqual(202, res.status_int)
@mock.patch('blazarnova.api.extensions.reservation.blazar_client') @mock.patch('blazarnova.api.extensions.reservation.blazar_client')
def test_create_with_passed_args(self, mock_module): def test_create_with_passed_args(self, mock_module):
@ -82,17 +89,18 @@ class BlazarDefaultReservationTestCase(extensions.BaseExtensionTestCase):
} }
self.req.body = jsonutils.dumps(body) 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', mock_module.Client.assert_called_once_with(climate_url='fake',
auth_token='fake_token') auth_token='fake_token')
self.lease_controller.create.assert_called_once_with( self.lease_controller.create.assert_called_once_with(
reservations=[ reservations=[
{'resource_type': 'virtual:instance', {'resource_type': 'virtual:instance',
'resource_id': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'}], 'resource_id': 'fakeId'}],
end=self.default_lease_end, end=self.default_lease_end,
events=[], events=[],
start='now', start='now',
name='other_name') name='other_name')
self.assertEqual(202, res.status_int)

View File

@ -14,15 +14,17 @@
# limitations under the License. # limitations under the License.
import mock import mock
from oslo_serialization import jsonutils
from blazarnova.api.extensions import reservation
from blazarnova.tests.api import extensions from blazarnova.tests.api import extensions
from nova.api.openstack import wsgi
from oslo_serialization import jsonutils
class BlazarReservationTestCase(extensions.BaseExtensionTestCase): class BlazarReservationTestCase(extensions.BaseExtensionTestCase):
"""Blazar API extensions test case. """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 together with Reservation extension passing hints to Nova and
sending lease creation request to Blazar. sending lease creation request to Blazar.
""" """
@ -30,13 +32,7 @@ class BlazarReservationTestCase(extensions.BaseExtensionTestCase):
def setUp(self): def setUp(self):
"""Set up testing environment.""" """Set up testing environment."""
super(BlazarReservationTestCase, self).setUp() super(BlazarReservationTestCase, self).setUp()
self.flags( self.controller = reservation.ReservationController()
osapi_compute_extension=[
'nova.api.openstack.compute.legacy_v2.contrib.'
'select_extensions',
'blazarnova.api.extensions.reservation.Reservation'
],
osapi_compute_ext_list=['Scheduler_hints'])
@mock.patch('blazarnova.api.extensions.reservation.blazar_client') @mock.patch('blazarnova.api.extensions.reservation.blazar_client')
def test_create(self, mock_module): def test_create(self, mock_module):
@ -57,17 +53,17 @@ class BlazarReservationTestCase(extensions.BaseExtensionTestCase):
} }
self.req.body = jsonutils.dumps(body) 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', mock_module.Client.assert_called_once_with(climate_url='fake',
auth_token='fake_token') auth_token='fake_token')
self.lease_controller.create.assert_called_once_with( self.lease_controller.create.assert_called_once_with(
reservations=[ reservations=[
{'resource_type': 'virtual:instance', {'resource_type': 'virtual:instance',
'resource_id': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'}], 'resource_id': 'fakeId'}],
end='2014-02-10 12:00', end='2014-02-10 12:00',
events=[], events=[],
start='2014-02-09 12:00', start='2014-02-09 12:00',
name='some_name') name='some_name')
self.assertEqual(202, res.status_int)

View File

@ -1,3 +1,4 @@
# The order of packages is significant, because pip processes them in the order # 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 # of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later. # process, which may cause wedges in the gate later.
kombu>=3.0.25,<4.0.0 # BSD