From 7580fac777d3facb269033f7416a654bce16451c Mon Sep 17 00:00:00 2001 From: Sean McGinnis Date: Mon, 21 Aug 2017 16:29:05 -0500 Subject: [PATCH] Allow v3.0 volume metadata API calls Commit I575635258c10f299181b8e4cdb51a7ad1f1be764 added some optimization to a few of the volume metadata API calls. It added a check incorrectly for the microversion for those changes such that if you were not using microversion 3.15 or above, it would fail the API call. This changes the microversion check to correctly either perform the new requested functionality or fail back to the base 3.0/2.0 API behavior. Change-Id: I09ad8200f73273dae8e5d926939620b71d9210e8 Closes-bug: #1712192 (cherry picked from commit c9c668437efb9e7f05a399472875b29c70f79d76) (cherry picked from commit 3bd4dc802108532cb0ae39739d652db152b5ac38) --- cinder/api/v3/volume_metadata.py | 38 +++++++++---------- .../tests/unit/api/v2/test_volume_metadata.py | 4 +- .../tests/unit/api/v3/test_volume_metadata.py | 21 +++++++--- 3 files changed, 35 insertions(+), 28 deletions(-) diff --git a/cinder/api/v3/volume_metadata.py b/cinder/api/v3/volume_metadata.py index d248618b41c..266c150b493 100644 --- a/cinder/api/v3/volume_metadata.py +++ b/cinder/api/v3/volume_metadata.py @@ -23,7 +23,6 @@ import webob from cinder.api.openstack import wsgi from cinder.api.v2 import volume_metadata as volume_meta_v2 -from cinder import exception METADATA_MICRO_VERSION = '3.15' @@ -42,36 +41,35 @@ class Controller(volume_meta_v2.Controller): checksum = hashlib.md5(data).hexdigest() return checksum in req.if_match.etags - def _ensure_min_version(self, req, allowed_version): - version = req.api_version_request - if not version.matches(allowed_version, None): - raise exception.VersionNotFoundForAPIMethod(version=version) - @wsgi.extends def index(self, req, volume_id): - self._ensure_min_version(req, METADATA_MICRO_VERSION) + req_version = req.api_version_request metadata = super(Controller, self).index(req, volume_id) - resp = webob.Response() - data = jsonutils.dumps(metadata) - if six.PY3: - data = data.encode('utf-8') - resp.headers['Etag'] = hashlib.md5(data).hexdigest() - resp.body = data - return resp + if req_version.matches(METADATA_MICRO_VERSION): + data = jsonutils.dumps(metadata) + if six.PY3: + data = data.encode('utf-8') + resp = webob.Response() + resp.headers['Etag'] = hashlib.md5(data).hexdigest() + resp.body = data + return resp + return metadata @wsgi.extends def update(self, req, volume_id, id, body): - self._ensure_min_version(req, METADATA_MICRO_VERSION) - if not self._validate_etag(req, volume_id): - return webob.Response(status_int=412) + req_version = req.api_version_request + if req_version.matches(METADATA_MICRO_VERSION): + if not self._validate_etag(req, volume_id): + return webob.Response(status_int=412) return super(Controller, self).update(req, volume_id, id, body) @wsgi.extends def update_all(self, req, volume_id, body): - self._ensure_min_version(req, METADATA_MICRO_VERSION) - if not self._validate_etag(req, volume_id): - return webob.Response(status_int=412) + req_version = req.api_version_request + if req_version.matches(METADATA_MICRO_VERSION): + if not self._validate_etag(req, volume_id): + return webob.Response(status_int=412) return super(Controller, self).update_all(req, volume_id, body) diff --git a/cinder/tests/unit/api/v2/test_volume_metadata.py b/cinder/tests/unit/api/v2/test_volume_metadata.py index 11c3799d1d7..a9bf6a741c4 100644 --- a/cinder/tests/unit/api/v2/test_volume_metadata.py +++ b/cinder/tests/unit/api/v2/test_volume_metadata.py @@ -107,10 +107,10 @@ def return_volume_nonexistent(*args, **kwargs): raise exception.VolumeNotFound('bogus test message') -class volumeMetaDataTest(test.TestCase): +class VolumeMetaDataTest(test.TestCase): def setUp(self): - super(volumeMetaDataTest, self).setUp() + super(VolumeMetaDataTest, self).setUp() self.volume_api = volume_api.API() self.mock_object(volume.api.API, 'get', get_volume) self.mock_object(db, 'volume_metadata_get', diff --git a/cinder/tests/unit/api/v3/test_volume_metadata.py b/cinder/tests/unit/api/v3/test_volume_metadata.py index 94fd217a445..0723cf53a4c 100644 --- a/cinder/tests/unit/api/v3/test_volume_metadata.py +++ b/cinder/tests/unit/api/v3/test_volume_metadata.py @@ -1,6 +1,3 @@ -# Copyright 2016 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 @@ -27,6 +24,7 @@ from cinder import exception from cinder import test from cinder.tests.unit.api import fakes from cinder.tests.unit.api.v2 import fakes as v2_fakes +from cinder.tests.unit.api.v2 import test_volume_metadata as v2_test from cinder.tests.unit import fake_constants as fake from cinder.tests.unit import fake_volume from cinder import volume @@ -118,10 +116,10 @@ def fake_update_volume_metadata(self, context, volume, diff): pass -class volumeMetaDataTest(test.TestCase): +class VolumeMetaDataTest(test.TestCase): def setUp(self): - super(volumeMetaDataTest, self).setUp() + super(VolumeMetaDataTest, self).setUp() self.volume_api = volume_api.API() self.mock_object(volume.api.API, 'get', get_volume) self.mock_object(db, 'volume_metadata_get', @@ -138,7 +136,7 @@ class volumeMetaDataTest(test.TestCase): self.volume_controller = volumes.VolumeController(self.ext_mgr) self.controller = volume_metadata.Controller() self.req_id = str(uuid.uuid4()) - self.url = '/v2/%s/volumes/%s/metadata' % ( + self.url = '/v3/%s/volumes/%s/metadata' % ( fake.PROJECT_ID, self.req_id) vol = {"size": 100, @@ -232,3 +230,14 @@ class volumeMetaDataTest(test.TestCase): expected = {'meta': {'key1': 'value1'}} self.assertEqual(expected, res_dict) get_volume.assert_called_once_with(fake_context, self.req_id) + + +class VolumeMetaDataTestNoMicroversion(v2_test.VolumeMetaDataTest): + """Volume metadata tests with no microversion provided.""" + + def setUp(self): + super(VolumeMetaDataTestNoMicroversion, self).setUp() + self.volume_controller = volumes.VolumeController(self.ext_mgr) + self.controller = volume_metadata.Controller() + self.url = '/v3/%s/volumes/%s/metadata' % ( + fake.PROJECT_ID, self.req_id)