diff options
author | Zuul <zuul@review.opendev.org> | 2021-07-23 20:27:26 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2021-07-23 20:27:26 +0000 |
commit | 82d87230491eda4bbef63b0b1acce1ebaf5a6e72 (patch) | |
tree | 2b79b3b560b2f5927ac3f356c594677e3e67a58b /glance_store/tests | |
parent | 32f9a1509bc94baa6acaf508c922f3b7edf5b65f (diff) | |
parent | 1178f113c4fc3f5f0938f3dcc608cea4a73adb7f (diff) | |
download | glance_store-82d87230491eda4bbef63b0b1acce1ebaf5a6e72.tar.gz |
Merge "Add cinder's new attachment support"
Diffstat (limited to 'glance_store/tests')
-rw-r--r-- | glance_store/tests/unit/common/test_cinder_utils.py | 157 | ||||
-rw-r--r-- | glance_store/tests/unit/test_cinder_store.py | 44 | ||||
-rw-r--r-- | glance_store/tests/unit/test_multistore_cinder.py | 46 |
3 files changed, 221 insertions, 26 deletions
diff --git a/glance_store/tests/unit/common/test_cinder_utils.py b/glance_store/tests/unit/common/test_cinder_utils.py new file mode 100644 index 0000000..2acfaac --- /dev/null +++ b/glance_store/tests/unit/common/test_cinder_utils.py @@ -0,0 +1,157 @@ +# Copyright 2021 RedHat Inc. +# 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 unittest import mock +import uuid + +from cinderclient.apiclient import exceptions as apiclient_exception +from cinderclient import exceptions as cinder_exception +from oslo_config import cfg +from oslotest import base + +from glance_store.common import cinder_utils + +CONF = cfg.CONF + + +class FakeObject(object): + def __init__(self, **kwargs): + for name, value in kwargs.items(): + setattr(self, name, value) + + +class CinderUtilsTestCase(base.BaseTestCase): + + def setUp(self): + super(CinderUtilsTestCase, self).setUp() + CONF.register_opt(cfg.DictOpt('enabled_backends')) + CONF.set_override('enabled_backends', 'fake:cinder') + self.volume_api = cinder_utils.API() + self.fake_client = FakeObject(attachments=FakeObject( + create=mock.MagicMock(), delete=mock.MagicMock(), + complete=mock.MagicMock(), update=mock.MagicMock(), + show=mock.MagicMock())) + self.fake_vol_id = uuid.uuid4() + self.fake_attach_id = uuid.uuid4() + self.fake_connector = { + 'platform': 'x86_64', 'os_type': 'linux', 'ip': 'fake_ip', + 'host': 'fake_host', 'multipath': False, + 'initiator': 'fake_initiator', 'do_local_attach': False, + 'uuid': '3e1a7217-104e-41c1-b177-a37c491129a0', + 'system uuid': '98755544-c749-40ed-b30a-a1cb27b2a46d', + 'nqn': 'fake_nqn'} + + def test_attachment_create(self): + self.volume_api.attachment_create(self.fake_client, self.fake_vol_id) + self.fake_client.attachments.create.assert_called_once_with( + self.fake_vol_id, None, mode=None) + + def test_attachment_create_with_connector_and_mountpoint(self): + self.volume_api.attachment_create( + self.fake_client, self.fake_vol_id, + connector=self.fake_connector, mountpoint='fake_mountpoint') + self.fake_connector['mountpoint'] = 'fake_mountpoint' + self.fake_client.attachments.create.assert_called_once_with( + self.fake_vol_id, self.fake_connector, mode=None) + + def test_attachment_create_client_exception(self): + self.fake_client.attachments.create.side_effect = ( + cinder_exception.ClientException(code=1)) + self.assertRaises( + cinder_exception.ClientException, + self.volume_api.attachment_create, + self.fake_client, self.fake_vol_id) + + def test_attachment_get(self): + self.volume_api.attachment_get(self.fake_client, self.fake_attach_id) + self.fake_client.attachments.show.assert_called_once_with( + self.fake_attach_id) + + def test_attachment_get_client_exception(self): + self.fake_client.attachments.show.side_effect = ( + cinder_exception.ClientException(code=1)) + self.assertRaises( + cinder_exception.ClientException, + self.volume_api.attachment_get, + self.fake_client, self.fake_attach_id) + + def test_attachment_update(self): + self.volume_api.attachment_update(self.fake_client, + self.fake_attach_id, + self.fake_connector) + self.fake_client.attachments.update.assert_called_once_with( + self.fake_attach_id, self.fake_connector) + + def test_attachment_update_with_connector_and_mountpoint(self): + self.volume_api.attachment_update( + self.fake_client, self.fake_attach_id, self.fake_connector, + mountpoint='fake_mountpoint') + self.fake_connector['mountpoint'] = 'fake_mountpoint' + self.fake_client.attachments.update.assert_called_once_with( + self.fake_attach_id, self.fake_connector) + + def test_attachment_update_client_exception(self): + self.fake_client.attachments.update.side_effect = ( + cinder_exception.ClientException(code=1)) + self.assertRaises( + cinder_exception.ClientException, + self.volume_api.attachment_update, + self.fake_client, self.fake_attach_id, self.fake_connector) + + def test_attachment_complete(self): + self.volume_api.attachment_complete(self.fake_client, + self.fake_attach_id) + self.fake_client.attachments.complete.assert_called_once_with( + self.fake_attach_id) + + def test_attachment_complete_client_exception(self): + self.fake_client.attachments.complete.side_effect = ( + cinder_exception.ClientException(code=1)) + self.assertRaises( + cinder_exception.ClientException, + self.volume_api.attachment_complete, + self.fake_client, self.fake_attach_id) + + def test_attachment_delete(self): + self.volume_api.attachment_delete(self.fake_client, + self.fake_attach_id) + self.fake_client.attachments.delete.assert_called_once_with( + self.fake_attach_id) + + def test_attachment_delete_client_exception(self): + self.fake_client.attachments.delete.side_effect = ( + cinder_exception.ClientException(code=1)) + self.assertRaises( + cinder_exception.ClientException, + self.volume_api.attachment_delete, + self.fake_client, self.fake_attach_id) + + def test_attachment_delete_retries(self): + # Make delete fail two times and succeed on the third attempt. + self.fake_client.attachments.delete.side_effect = [ + apiclient_exception.InternalServerError(), + apiclient_exception.InternalServerError(), + lambda aid: 'foo'] + + # Make sure we get a clean result. + self.assertIsNone(self.volume_api.attachment_delete( + self.fake_client, self.fake_attach_id)) + + # Assert that we called delete three times due to the retry + # decorator. + self.fake_client.attachments.delete.assert_has_calls([ + mock.call(self.fake_attach_id), + mock.call(self.fake_attach_id), + mock.call(self.fake_attach_id)]) diff --git a/glance_store/tests/unit/test_cinder_store.py b/glance_store/tests/unit/test_cinder_store.py index 7abe0c3..e87f129 100644 --- a/glance_store/tests/unit/test_cinder_store.py +++ b/glance_store/tests/unit/test_cinder_store.py @@ -31,6 +31,7 @@ from oslo_concurrency import processutils from oslo_utils.secretutils import md5 from oslo_utils import units +from glance_store.common import cinder_utils from glance_store import exceptions from glance_store import location from glance_store.tests import base @@ -154,8 +155,11 @@ class TestCinderStore(base.StoreBaseTest, encrypted_nfs=False): self.config(cinder_mount_point_base=None) fake_volume = mock.MagicMock(id=str(uuid.uuid4()), status='available') - fake_volumes = FakeObject(get=lambda id: fake_volume, - detach=mock.Mock()) + fake_volumes = FakeObject(get=lambda id: fake_volume) + fake_attachment_id = str(uuid.uuid4()) + fake_attachment_create = {'id': fake_attachment_id} + fake_attachment_update = mock.MagicMock(id=fake_attachment_id) + fake_conn_info = mock.MagicMock(connector={}) fake_client = FakeObject(volumes=fake_volumes) _, fake_dev_path = tempfile.mkstemp(dir=self.test_dir) fake_devinfo = {'path': fake_dev_path} @@ -174,8 +178,6 @@ class TestCinderStore(base.StoreBaseTest, raise error def fake_factory(protocol, root_helper, **kwargs): - self.assertEqual(fake_volume.initialize_connection.return_value, - kwargs['conn']) return fake_connector root_helper = "sudo glance-rootwrap /etc/glance/rootwrap.conf" @@ -187,10 +189,22 @@ class TestCinderStore(base.StoreBaseTest, mock.patch.object(cinder.Store, 'get_root_helper', return_value=root_helper), \ mock.patch.object(connector.InitiatorConnector, 'factory', - side_effect=fake_factory) as fake_conn_obj: + side_effect=fake_factory + ) as fake_conn_obj, \ + mock.patch.object(cinder_utils.API, 'attachment_create', + return_value=fake_attachment_create + ) as attach_create, \ + mock.patch.object(cinder_utils.API, 'attachment_update', + return_value=fake_attachment_update + ) as attach_update, \ + mock.patch.object(cinder_utils.API, + 'attachment_delete') as attach_delete, \ + mock.patch.object(cinder_utils.API, + 'attachment_complete') as attach_complete: with mock.patch.object(connector, - 'get_connector_properties') as mock_conn: + 'get_connector_properties', + return_value=fake_conn_info) as mock_conn: if error: self.assertRaises(error, do_open) elif encrypted_nfs: @@ -218,13 +232,18 @@ class TestCinderStore(base.StoreBaseTest, mock.ANY) fake_connector.disconnect_volume.assert_called_once_with( mock.ANY, fake_devinfo) - fake_volume.attach.assert_called_once_with( - None, 'glance_store', attach_mode, - host_name=socket.gethostname()) - fake_volumes.detach.assert_called_once_with(fake_volume) fake_conn_obj.assert_called_once_with( mock.ANY, root_helper, conn=mock.ANY, use_multipath=multipath_supported) + attach_create.assert_called_once_with( + fake_client, fake_volume.id, mode=attach_mode) + attach_update.assert_called_once_with( + fake_client, fake_attachment_id, + fake_conn_info, mountpoint='glance_store') + attach_complete.assert_called_once_with( + fake_client, fake_attachment_id) + attach_delete.assert_called_once_with( + fake_client, fake_attachment_id) def test_open_cinder_volume_rw(self): self._test_open_cinder_volume('wb', 'rw', None) @@ -400,8 +419,7 @@ class TestCinderStore(base.StoreBaseTest, def test_cinder_delete(self): fake_client = FakeObject(auth_token=None, management_url=None) fake_volume_uuid = str(uuid.uuid4()) - fake_volume = FakeObject(delete=mock.Mock()) - fake_volumes = {fake_volume_uuid: fake_volume} + fake_volumes = FakeObject(delete=mock.Mock()) with mock.patch.object(cinder.Store, 'get_cinderclient') as mocked_cc: mocked_cc.return_value = FakeObject(client=fake_client, @@ -410,7 +428,7 @@ class TestCinderStore(base.StoreBaseTest, uri = 'cinder://%s' % fake_volume_uuid loc = location.get_location_from_uri(uri, conf=self.conf) self.store.delete(loc, context=self.context) - fake_volume.delete.assert_called_once_with() + fake_volumes.delete.assert_called_once_with(fake_volume_uuid) def test_set_url_prefix(self): self.assertEqual('cinder://', self.store._url_prefix) diff --git a/glance_store/tests/unit/test_multistore_cinder.py b/glance_store/tests/unit/test_multistore_cinder.py index d87bdfc..2cc1e58 100644 --- a/glance_store/tests/unit/test_multistore_cinder.py +++ b/glance_store/tests/unit/test_multistore_cinder.py @@ -33,6 +33,7 @@ from oslo_utils.secretutils import md5 from oslo_utils import units import glance_store as store +from glance_store.common import cinder_utils from glance_store import exceptions from glance_store import location from glance_store.tests import base @@ -185,8 +186,11 @@ class TestMultiCinderStore(base.MultiStoreBaseTest, enforce_multipath=False): self.config(cinder_mount_point_base=None, group='cinder1') fake_volume = mock.MagicMock(id=str(uuid.uuid4()), status='available') - fake_volumes = FakeObject(get=lambda id: fake_volume, - detach=mock.Mock()) + fake_attachment_id = str(uuid.uuid4()) + fake_attachment_create = {'id': fake_attachment_id} + fake_attachment_update = mock.MagicMock(id=fake_attachment_id) + fake_conn_info = mock.MagicMock(connector={}) + fake_volumes = FakeObject(get=lambda id: fake_volume) fake_client = FakeObject(volumes=fake_volumes) _, fake_dev_path = tempfile.mkstemp(dir=self.test_dir) fake_devinfo = {'path': fake_dev_path} @@ -205,8 +209,6 @@ class TestMultiCinderStore(base.MultiStoreBaseTest, raise error def fake_factory(protocol, root_helper, **kwargs): - self.assertEqual(fake_volume.initialize_connection.return_value, - kwargs['conn']) return fake_connector root_helper = "sudo glance-rootwrap /etc/glance/rootwrap.conf" @@ -218,10 +220,24 @@ class TestMultiCinderStore(base.MultiStoreBaseTest, mock.patch.object(cinder.Store, 'get_root_helper', return_value=root_helper), \ mock.patch.object(connector.InitiatorConnector, 'factory', - side_effect=fake_factory) as fake_conn_obj: + side_effect=fake_factory + ) as fake_conn_obj, \ + mock.patch.object(cinder_utils.API, + 'attachment_create', + return_value=fake_attachment_create + ) as attach_create, \ + mock.patch.object(cinder_utils.API, + 'attachment_update', + return_value=fake_attachment_update + ) as attach_update, \ + mock.patch.object(cinder_utils.API, + 'attachment_delete') as attach_delete, \ + mock.patch.object(cinder_utils.API, + 'attachment_complete') as attach_complete: with mock.patch.object(connector, - 'get_connector_properties') as mock_conn: + 'get_connector_properties', + return_value=fake_conn_info) as mock_conn: if error: self.assertRaises(error, do_open) else: @@ -233,13 +249,18 @@ class TestMultiCinderStore(base.MultiStoreBaseTest, fake_connector.connect_volume.assert_called_once_with(mock.ANY) fake_connector.disconnect_volume.assert_called_once_with( mock.ANY, fake_devinfo) - fake_volume.attach.assert_called_once_with( - None, 'glance_store', attach_mode, - host_name=socket.gethostname()) - fake_volumes.detach.assert_called_once_with(fake_volume) fake_conn_obj.assert_called_once_with( mock.ANY, root_helper, conn=mock.ANY, use_multipath=multipath_supported) + attach_create.assert_called_once_with( + fake_client, fake_volume.id, mode=attach_mode) + attach_update.assert_called_once_with( + fake_client, fake_attachment_id, + fake_conn_info, mountpoint='glance_store') + attach_complete.assert_called_once_with(fake_client, + fake_attachment_id) + attach_delete.assert_called_once_with(fake_client, + fake_attachment_id) def test_open_cinder_volume_rw(self): self._test_open_cinder_volume('wb', 'rw', None) @@ -499,8 +520,7 @@ class TestMultiCinderStore(base.MultiStoreBaseTest, def test_cinder_delete(self): fake_client = FakeObject(auth_token=None, management_url=None) fake_volume_uuid = str(uuid.uuid4()) - fake_volume = FakeObject(delete=mock.Mock()) - fake_volumes = {fake_volume_uuid: fake_volume} + fake_volumes = FakeObject(delete=mock.Mock()) with mock.patch.object(cinder.Store, 'get_cinderclient') as mocked_cc: mocked_cc.return_value = FakeObject(client=fake_client, @@ -511,7 +531,7 @@ class TestMultiCinderStore(base.MultiStoreBaseTest, "cinder1", conf=self.conf) self.store.delete(loc, context=self.context) - fake_volume.delete.assert_called_once_with() + fake_volumes.delete.assert_called_once_with(fake_volume_uuid) def test_cinder_add_different_backend(self): self.store = cinder.Store(self.conf, backend="cinder2") |