summaryrefslogtreecommitdiff
path: root/glance_store/tests
diff options
context:
space:
mode:
authorZuul <zuul@review.opendev.org>2021-07-23 20:27:26 +0000
committerGerrit Code Review <review@openstack.org>2021-07-23 20:27:26 +0000
commit82d87230491eda4bbef63b0b1acce1ebaf5a6e72 (patch)
tree2b79b3b560b2f5927ac3f356c594677e3e67a58b /glance_store/tests
parent32f9a1509bc94baa6acaf508c922f3b7edf5b65f (diff)
parent1178f113c4fc3f5f0938f3dcc608cea4a73adb7f (diff)
downloadglance_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.py157
-rw-r--r--glance_store/tests/unit/test_cinder_store.py44
-rw-r--r--glance_store/tests/unit/test_multistore_cinder.py46
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")