From 72adb4fa5c65eaf97c29feac4bd8c4f50f244eb5 Mon Sep 17 00:00:00 2001 From: Dmitry Tantsur Date: Wed, 18 Jan 2017 15:51:27 +0100 Subject: [PATCH] Use only Glance V2 by default (with a compatibility option) Glance V1 is deprecated we should start switching off it. Even more, some features in Ironic already require V2 anyway. This change switches everything to V2 by default, while leaving an option to get previous behavior back. Features that already required V2 are not affected by this option. Change-Id: I6947a150fefb7fe3028a0a7c5208c6c343be8e0d Closes-Bug: #1657475 --- etc/ironic/ironic.conf.sample | 5 ++++ ironic/common/image_service.py | 7 +++-- ironic/conf/glance.py | 3 ++ ironic/drivers/modules/pxe.py | 3 +- .../tests/unit/common/test_image_service.py | 28 ++++++++++++++----- .../notes/glance-v2-83b04fec247cd22f.yaml | 8 ++++++ 6 files changed, 44 insertions(+), 10 deletions(-) create mode 100644 releasenotes/notes/glance-v2-83b04fec247cd22f.yaml diff --git a/etc/ironic/ironic.conf.sample b/etc/ironic/ironic.conf.sample index 2e88f02739..07ad8e21f2 100644 --- a/etc/ironic/ironic.conf.sample +++ b/etc/ironic/ironic.conf.sample @@ -1420,6 +1420,11 @@ # [hostname|IP]:port. (list value) #glance_api_servers = +# Glance API version (1 or 2) to use. (integer value) +# Minimum value: 1 +# Maximum value: 2 +#glance_api_version = 2 + # Optional path to a CA certificate bundle to be used to # validate the SSL certificate served by glance. It is used # when glance_api_insecure is set to False. (string value) diff --git a/ironic/common/image_service.py b/ironic/common/image_service.py index 891ed5698a..2987cf5625 100644 --- a/ironic/common/image_service.py +++ b/ironic/common/image_service.py @@ -45,8 +45,11 @@ def _get_glance_session(): return _GLANCE_SESSION -def GlanceImageService(client=None, version=1, context=None): +def GlanceImageService(client=None, version=None, context=None): module_str = 'ironic.common.glance_service' + if version is None: + version = CONF.glance.glance_api_version + module = importutils.import_versioned_module(module_str, version, 'image_service') service_class = getattr(module, 'GlanceImageService') @@ -258,7 +261,7 @@ protocol_mapping = { } -def get_image_service(image_href, client=None, version=1, context=None): +def get_image_service(image_href, client=None, version=None, context=None): """Get image service instance to download the image. :param image_href: String containing href to get image service for. diff --git a/ironic/conf/glance.py b/ironic/conf/glance.py index 9c46a81811..d8642cf40e 100644 --- a/ironic/conf/glance.py +++ b/ironic/conf/glance.py @@ -141,6 +141,9 @@ opts = [ help=_('Optional path to a CA certificate bundle to be used to ' 'validate the SSL certificate served by glance. It is ' 'used when glance_api_insecure is set to False.')), + cfg.IntOpt('glance_api_version', + help=_('Glance API version (1 or 2) to use.'), + min=1, max=2, default=2), ] diff --git a/ironic/drivers/modules/pxe.py b/ironic/drivers/modules/pxe.py index ee912c057b..5a3af41b53 100644 --- a/ironic/drivers/modules/pxe.py +++ b/ironic/drivers/modules/pxe.py @@ -96,7 +96,8 @@ def _get_instance_image_info(node, ctx): labels = ('kernel', 'ramdisk') d_info = deploy_utils.get_image_instance_info(node) if not (i_info.get('kernel') and i_info.get('ramdisk')): - glance_service = service.GlanceImageService(version=1, context=ctx) + glance_service = service.GlanceImageService( + version=CONF.glance.glance_api_version, context=ctx) iproperties = glance_service.show(d_info['image_source'])['properties'] for label in labels: i_info[label] = str(iproperties[label + '_id']) diff --git a/ironic/tests/unit/common/test_image_service.py b/ironic/tests/unit/common/test_image_service.py index 57ac3be832..e2319d4f10 100644 --- a/ironic/tests/unit/common/test_image_service.py +++ b/ironic/tests/unit/common/test_image_service.py @@ -24,6 +24,7 @@ from six.moves import http_client from ironic.common import exception from ironic.common.glance_service.v1 import image_service as glance_v1_service +from ironic.common.glance_service.v2 import image_service as glance_v2_service from ironic.common import image_service from ironic.tests import base @@ -254,31 +255,44 @@ class FileImageServiceTestCase(base.TestCase): class ServiceGetterTestCase(base.TestCase): @mock.patch.object(image_service, '_get_glance_session') - @mock.patch.object(glance_v1_service.GlanceImageService, '__init__', + @mock.patch.object(glance_v2_service.GlanceImageService, '__init__', return_value=None, autospec=True) def test_get_glance_image_service(self, glance_service_mock, session_mock): image_href = 'image-uuid' self.context.auth_token = 'fake' image_service.get_image_service(image_href, context=self.context) + glance_service_mock.assert_called_once_with(mock.ANY, None, 2, + self.context) + self.assertFalse(session_mock.called) + + @mock.patch.object(image_service, '_get_glance_session') + @mock.patch.object(glance_v1_service.GlanceImageService, '__init__', + return_value=None, autospec=True) + def test_get_glance_image_service_default_v1(self, glance_service_mock, + session_mock): + self.config(glance_api_version=1, group='glance') + image_href = 'image-uuid' + self.context.auth_token = 'fake' + image_service.get_image_service(image_href, context=self.context) glance_service_mock.assert_called_once_with(mock.ANY, None, 1, self.context) self.assertFalse(session_mock.called) @mock.patch.object(image_service, '_get_glance_session') - @mock.patch.object(glance_v1_service.GlanceImageService, '__init__', + @mock.patch.object(glance_v2_service.GlanceImageService, '__init__', return_value=None, autospec=True) def test_get_glance_image_service_url(self, glance_service_mock, session_mock): image_href = 'glance://image-uuid' self.context.auth_token = 'fake' image_service.get_image_service(image_href, context=self.context) - glance_service_mock.assert_called_once_with(mock.ANY, None, 1, + glance_service_mock.assert_called_once_with(mock.ANY, None, 2, self.context) self.assertFalse(session_mock.called) @mock.patch.object(image_service, '_get_glance_session') - @mock.patch.object(glance_v1_service.GlanceImageService, '__init__', + @mock.patch.object(glance_v2_service.GlanceImageService, '__init__', return_value=None, autospec=True) def test_get_glance_image_service_no_token(self, glance_service_mock, session_mock): @@ -288,13 +302,13 @@ class ServiceGetterTestCase(base.TestCase): sess.get_token.return_value = 'admin-token' session_mock.return_value = sess image_service.get_image_service(image_href, context=self.context) - glance_service_mock.assert_called_once_with(mock.ANY, None, 1, + glance_service_mock.assert_called_once_with(mock.ANY, None, 2, self.context) sess.get_token.assert_called_once_with() self.assertEqual('admin-token', self.context.auth_token) @mock.patch.object(image_service, '_get_glance_session') - @mock.patch.object(glance_v1_service.GlanceImageService, '__init__', + @mock.patch.object(glance_v2_service.GlanceImageService, '__init__', return_value=None, autospec=True) def test_get_glance_image_service_token_not_needed(self, glance_service_mock, @@ -303,7 +317,7 @@ class ServiceGetterTestCase(base.TestCase): self.context.auth_token = None self.config(auth_strategy='noauth', group='glance') image_service.get_image_service(image_href, context=self.context) - glance_service_mock.assert_called_once_with(mock.ANY, None, 1, + glance_service_mock.assert_called_once_with(mock.ANY, None, 2, self.context) self.assertFalse(session_mock.called) self.assertIsNone(self.context.auth_token) diff --git a/releasenotes/notes/glance-v2-83b04fec247cd22f.yaml b/releasenotes/notes/glance-v2-83b04fec247cd22f.yaml new file mode 100644 index 0000000000..53c8384d39 --- /dev/null +++ b/releasenotes/notes/glance-v2-83b04fec247cd22f.yaml @@ -0,0 +1,8 @@ +--- +upgrade: + - | + Ironic now uses only Image (glance) V2 API by default. Usage of deprecated + V1 API for certain basic tasks can still be enabled by setting + "[glance]glance_api_version" to "1". This option, however, does not affect + temporary URL generation, as it always required V2 API and cannot work + with V1.