Replace cinderclient usage with openstacksdk
Change-Id: Ib4a533584da85281d425fdbffa12a52d4838e185 Closes-Bug: #2042494
This commit is contained in:
parent
1e4ef9395a
commit
91d4bacbec
@ -15,8 +15,8 @@
|
|||||||
import datetime
|
import datetime
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from cinderclient import exceptions as cinder_exceptions
|
import openstack
|
||||||
from cinderclient.v3 import client
|
from openstack.connection import exceptions as openstack_exc
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
|
|
||||||
from ironic.common import context as ironic_context
|
from ironic.common import context as ironic_context
|
||||||
@ -40,8 +40,8 @@ def _get_cinder_session():
|
|||||||
return _CINDER_SESSION
|
return _CINDER_SESSION
|
||||||
|
|
||||||
|
|
||||||
def get_client(context, auth_from_config=False):
|
def get_client(context=None, auth_from_config=False):
|
||||||
"""Get a cinder client connection.
|
"""Retrieve a cinder client connection.
|
||||||
|
|
||||||
:param context: request context,
|
:param context: request context,
|
||||||
instance of ironic.common.context.RequestContext
|
instance of ironic.common.context.RequestContext
|
||||||
@ -49,6 +49,7 @@ def get_client(context, auth_from_config=False):
|
|||||||
conf parameters
|
conf parameters
|
||||||
:returns: A cinder client.
|
:returns: A cinder client.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
service_auth = keystone.get_auth('cinder')
|
service_auth = keystone.get_auth('cinder')
|
||||||
session = _get_cinder_session()
|
session = _get_cinder_session()
|
||||||
# Used the service cached session to get the endpoint
|
# Used the service cached session to get the endpoint
|
||||||
@ -93,16 +94,12 @@ def get_client(context, auth_from_config=False):
|
|||||||
endpoint = keystone.get_endpoint('cinder', session=sess,
|
endpoint = keystone.get_endpoint('cinder', session=sess,
|
||||||
auth=user_auth)
|
auth=user_auth)
|
||||||
|
|
||||||
# NOTE(pas-ha) cinderclient has both 'connect_retries' (passed to
|
conn = openstack.connection.Connection(
|
||||||
# ksa.Adapter) and 'retries' (used in its subclass of ksa.Adapter) options.
|
session=sess,
|
||||||
# The first governs retries on establishing the HTTP connection,
|
block_storage_endpoint_override=endpoint,
|
||||||
# the second governs retries on OverLimit exceptions from API.
|
block_storage_api_version='3')
|
||||||
# The description of [cinder]/retries fits the first,
|
|
||||||
# so this is what we pass.
|
return conn.global_request(context.global_id).block_storage
|
||||||
return client.Client(session=sess, auth=user_auth,
|
|
||||||
endpoint_override=endpoint,
|
|
||||||
connect_retries=CONF.cinder.retries,
|
|
||||||
global_request_id=context.global_id)
|
|
||||||
|
|
||||||
|
|
||||||
def is_volume_available(volume):
|
def is_volume_available(volume):
|
||||||
@ -114,7 +111,7 @@ def is_volume_available(volume):
|
|||||||
"""
|
"""
|
||||||
return (volume.status == AVAILABLE
|
return (volume.status == AVAILABLE
|
||||||
or (volume.status == IN_USE
|
or (volume.status == IN_USE
|
||||||
and volume.multiattach))
|
and volume.is_multiattach))
|
||||||
|
|
||||||
|
|
||||||
def is_volume_attached(node, volume):
|
def is_volume_attached(node, volume):
|
||||||
@ -172,28 +169,6 @@ def _create_metadata_dictionary(node, action):
|
|||||||
return {label: json.dumps(data)}
|
return {label: json.dumps(data)}
|
||||||
|
|
||||||
|
|
||||||
def _init_client(task, auth_from_config=False):
|
|
||||||
"""Obtain cinder client and return it for use.
|
|
||||||
|
|
||||||
:param task: TaskManager instance representing the operation.
|
|
||||||
:param auth_from_config: If we should source our authentication parameters
|
|
||||||
from the configured service as opposed to request
|
|
||||||
context.
|
|
||||||
|
|
||||||
:returns: A cinder client.
|
|
||||||
:raises: StorageError If an exception is encountered creating the client.
|
|
||||||
"""
|
|
||||||
node = task.node
|
|
||||||
try:
|
|
||||||
return get_client(task.context,
|
|
||||||
auth_from_config=auth_from_config)
|
|
||||||
except Exception as e:
|
|
||||||
msg = (_('Failed to initialize cinder client for operations on node '
|
|
||||||
'%(uuid)s: %(err)s') % {'uuid': node.uuid, 'err': e})
|
|
||||||
LOG.error(msg)
|
|
||||||
raise exception.StorageError(msg)
|
|
||||||
|
|
||||||
|
|
||||||
def attach_volumes(task, volume_list, connector):
|
def attach_volumes(task, volume_list, connector):
|
||||||
"""Attach volumes to a node.
|
"""Attach volumes to a node.
|
||||||
|
|
||||||
@ -282,12 +257,17 @@ def attach_volumes(task, volume_list, connector):
|
|||||||
node = task.node
|
node = task.node
|
||||||
LOG.debug('Initializing volume attach for node %(node)s.',
|
LOG.debug('Initializing volume attach for node %(node)s.',
|
||||||
{'node': node.uuid})
|
{'node': node.uuid})
|
||||||
client = _init_client(task)
|
try:
|
||||||
|
block_storage = get_client(context=task.context)
|
||||||
|
except openstack_exc.SDKException as e:
|
||||||
|
msg = _('Failed to connect to block storage service '
|
||||||
|
': %(err)s') % {'err': e}
|
||||||
|
raise exception.StorageError(msg)
|
||||||
connected = []
|
connected = []
|
||||||
for volume_id in volume_list:
|
for volume_id in volume_list:
|
||||||
try:
|
try:
|
||||||
volume = client.volumes.get(volume_id)
|
volume = block_storage.get_volume(volume_id)
|
||||||
except cinder_exceptions.ClientException as e:
|
except openstack_exc.SDKException as e:
|
||||||
msg = (_('Failed to get volume %(vol_id)s from cinder for node '
|
msg = (_('Failed to get volume %(vol_id)s from cinder for node '
|
||||||
'%(uuid)s: %(err)s') %
|
'%(uuid)s: %(err)s') %
|
||||||
{'vol_id': volume_id, 'uuid': node.uuid, 'err': e})
|
{'vol_id': volume_id, 'uuid': node.uuid, 'err': e})
|
||||||
@ -308,8 +288,8 @@ def attach_volumes(task, volume_list, connector):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
client.volumes.reserve(volume_id)
|
block_storage.reserve_volume(volume)
|
||||||
except cinder_exceptions.ClientException as e:
|
except openstack_exc.SDKException as e:
|
||||||
msg = (_('Failed to reserve volume %(vol_id)s for node %(node)s: '
|
msg = (_('Failed to reserve volume %(vol_id)s for node %(node)s: '
|
||||||
'%(err)s)') %
|
'%(err)s)') %
|
||||||
{'vol_id': volume_id, 'node': node.uuid, 'err': e})
|
{'vol_id': volume_id, 'node': node.uuid, 'err': e})
|
||||||
@ -318,9 +298,9 @@ def attach_volumes(task, volume_list, connector):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
# Provide connector information to cinder
|
# Provide connector information to cinder
|
||||||
connection = client.volumes.initialize_connection(volume_id,
|
connection = block_storage.init_volume_attachment(
|
||||||
connector)
|
volume, connector)
|
||||||
except cinder_exceptions.ClientException as e:
|
except openstack_exc.SDKException as e:
|
||||||
msg = (_('Failed to initialize connection for volume '
|
msg = (_('Failed to initialize connection for volume '
|
||||||
'%(vol_id)s to node %(node)s: %(err)s') %
|
'%(vol_id)s to node %(node)s: %(err)s') %
|
||||||
{'vol_id': volume_id, 'node': node.uuid, 'err': e})
|
{'vol_id': volume_id, 'node': node.uuid, 'err': e})
|
||||||
@ -344,11 +324,11 @@ def attach_volumes(task, volume_list, connector):
|
|||||||
# been completed, which moves the volume to the
|
# been completed, which moves the volume to the
|
||||||
# 'attached' state. This action also sets a mountpoint
|
# 'attached' state. This action also sets a mountpoint
|
||||||
# for the volume, as cinder requires a mointpoint to
|
# for the volume, as cinder requires a mointpoint to
|
||||||
# attach the volume, thus we send 'mount_volume'.
|
# attach the volume, thus we send 'ironic_mountpoint'.
|
||||||
client.volumes.attach(volume_id, instance_uuid,
|
block_storage.attach_volume(
|
||||||
'ironic_mountpoint')
|
volume, 'ironic_mountpoint', instance=instance_uuid)
|
||||||
|
|
||||||
except cinder_exceptions.ClientException as e:
|
except openstack_exc.SDKException as e:
|
||||||
msg = (_('Failed to inform cinder that the attachment for volume '
|
msg = (_('Failed to inform cinder that the attachment for volume '
|
||||||
'%(vol_id)s for node %(node)s has been completed: '
|
'%(vol_id)s for node %(node)s has been completed: '
|
||||||
'%(err)s') %
|
'%(err)s') %
|
||||||
@ -358,11 +338,10 @@ def attach_volumes(task, volume_list, connector):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
# Set metadata to assist a user in volume identification
|
# Set metadata to assist a user in volume identification
|
||||||
client.volumes.set_metadata(
|
block_storage.set_volume_metadata(
|
||||||
volume_id,
|
volume, **_create_metadata_dictionary(node, 'attached'))
|
||||||
_create_metadata_dictionary(node, 'attached'))
|
|
||||||
|
|
||||||
except cinder_exceptions.ClientException as e:
|
except openstack_exc.SDKException as e:
|
||||||
LOG.warning('Failed to update volume metadata for volume '
|
LOG.warning('Failed to update volume metadata for volume '
|
||||||
'%(vol_id)s for node %(node)s: %(err)s',
|
'%(vol_id)s for node %(node)s: %(err)s',
|
||||||
{'vol_id': volume_id, 'node': node.uuid, 'err': e})
|
{'vol_id': volume_id, 'node': node.uuid, 'err': e})
|
||||||
@ -410,15 +389,20 @@ def detach_volumes(task, volume_list, connector, allow_errors=False):
|
|||||||
LOG.error(msg)
|
LOG.error(msg)
|
||||||
raise exception.StorageError(msg)
|
raise exception.StorageError(msg)
|
||||||
|
|
||||||
client = _init_client(task, auth_from_config=False)
|
try:
|
||||||
|
block_storage = get_client(context=task.context)
|
||||||
|
except openstack_exc.SDKException as e:
|
||||||
|
msg = _('Failed to connect to block storage service '
|
||||||
|
': %(err)s') % {'err': e}
|
||||||
|
raise exception.StorageError(msg)
|
||||||
node = task.node
|
node = task.node
|
||||||
LOG.debug('Initializing volume detach for node %(node)s.',
|
LOG.debug('Initializing volume detach for node %(node)s.',
|
||||||
{'node': node.uuid})
|
{'node': node.uuid})
|
||||||
|
|
||||||
for volume_id in volume_list:
|
for volume_id in volume_list:
|
||||||
try:
|
try:
|
||||||
volume = client.volumes.get(volume_id)
|
volume = block_storage.get_volume(volume_id)
|
||||||
except cinder_exceptions.ClientException as e:
|
except openstack_exc.SDKException as e:
|
||||||
_handle_errors(_('Failed to get volume %(vol_id)s from cinder for '
|
_handle_errors(_('Failed to get volume %(vol_id)s from cinder for '
|
||||||
'node %(node)s: %(err)s') %
|
'node %(node)s: %(err)s') %
|
||||||
{'vol_id': volume_id, 'node': node.uuid, 'err': e})
|
{'vol_id': volume_id, 'node': node.uuid, 'err': e})
|
||||||
@ -434,8 +418,8 @@ def detach_volumes(task, volume_list, connector, allow_errors=False):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
client.volumes.begin_detaching(volume_id)
|
block_storage.begin_volume_detaching(volume)
|
||||||
except cinder_exceptions.ClientException as e:
|
except openstack_exc.SDKException as e:
|
||||||
_handle_errors(_('Failed to request detach for volume %(vol_id)s '
|
_handle_errors(_('Failed to request detach for volume %(vol_id)s '
|
||||||
'from cinder for node %(node)s: %(err)s') %
|
'from cinder for node %(node)s: %(err)s') %
|
||||||
{'vol_id': volume_id, 'node': node.uuid, 'err': e}
|
{'vol_id': volume_id, 'node': node.uuid, 'err': e}
|
||||||
@ -445,8 +429,8 @@ def detach_volumes(task, volume_list, connector, allow_errors=False):
|
|||||||
# is set to True.
|
# is set to True.
|
||||||
try:
|
try:
|
||||||
# Remove the attachment
|
# Remove the attachment
|
||||||
client.volumes.terminate_connection(volume_id, connector)
|
block_storage.terminate_volume_attachment(volume, connector)
|
||||||
except cinder_exceptions.ClientException as e:
|
except openstack_exc.SDKException as e:
|
||||||
_handle_errors(_('Failed to detach volume %(vol_id)s from node '
|
_handle_errors(_('Failed to detach volume %(vol_id)s from node '
|
||||||
'%(node)s: %(err)s') %
|
'%(node)s: %(err)s') %
|
||||||
{'vol_id': volume_id, 'node': node.uuid, 'err': e})
|
{'vol_id': volume_id, 'node': node.uuid, 'err': e})
|
||||||
@ -462,8 +446,8 @@ def detach_volumes(task, volume_list, connector, allow_errors=False):
|
|||||||
attachment_id = _get_attachment_id(node, volume)
|
attachment_id = _get_attachment_id(node, volume)
|
||||||
try:
|
try:
|
||||||
# Update the API attachment record
|
# Update the API attachment record
|
||||||
client.volumes.detach(volume_id, attachment_id)
|
block_storage.detach_volume(volume, attachment_id)
|
||||||
except cinder_exceptions.ClientException as e:
|
except openstack_exc.SDKException as e:
|
||||||
_handle_errors(_('Failed to inform cinder that the detachment for '
|
_handle_errors(_('Failed to inform cinder that the detachment for '
|
||||||
'volume %(vol_id)s from node %(node)s has been '
|
'volume %(vol_id)s from node %(node)s has been '
|
||||||
'completed: %(err)s') %
|
'completed: %(err)s') %
|
||||||
@ -473,10 +457,10 @@ def detach_volumes(task, volume_list, connector, allow_errors=False):
|
|||||||
# is set to True.
|
# is set to True.
|
||||||
try:
|
try:
|
||||||
# Set metadata to assist in volume identification.
|
# Set metadata to assist in volume identification.
|
||||||
client.volumes.set_metadata(
|
block_storage.set_volume_metadata(
|
||||||
volume_id,
|
volume,
|
||||||
_create_metadata_dictionary(node, 'detached'))
|
**_create_metadata_dictionary(node, 'detached'))
|
||||||
except cinder_exceptions.ClientException as e:
|
except openstack_exc.SDKException as e:
|
||||||
LOG.warning('Failed to update volume %(vol_id)s metadata for node '
|
LOG.warning('Failed to update volume %(vol_id)s metadata for node '
|
||||||
'%(node)s: %(err)s',
|
'%(node)s: %(err)s',
|
||||||
{'vol_id': volume_id, 'node': node.uuid, 'err': e})
|
{'vol_id': volume_id, 'node': node.uuid, 'err': e})
|
||||||
|
@ -19,8 +19,11 @@ from ironic.conf import auth
|
|||||||
opts = [
|
opts = [
|
||||||
cfg.IntOpt('retries',
|
cfg.IntOpt('retries',
|
||||||
default=3,
|
default=3,
|
||||||
help=_('Client retries in the case of a failed request '
|
deprecated_for_removal=True,
|
||||||
'connection.')),
|
deprecated_reason=_('Replaced by status_code_retries and '
|
||||||
|
'status_code_retry_delay.'),
|
||||||
|
help=_('DEPRECATED: Client retries in the case of a failed '
|
||||||
|
'request.')),
|
||||||
cfg.IntOpt('action_retries',
|
cfg.IntOpt('action_retries',
|
||||||
default=3,
|
default=3,
|
||||||
help=_('Number of retries in the case of a failed '
|
help=_('Number of retries in the case of a failed '
|
||||||
@ -33,8 +36,6 @@ opts = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
# NOTE(pas-ha) cinder V3 which ironic requires is registered as volumev3
|
|
||||||
# service type ATM
|
|
||||||
def register_opts(conf):
|
def register_opts(conf):
|
||||||
conf.register_opts(opts, group='cinder')
|
conf.register_opts(opts, group='cinder')
|
||||||
auth.register_auth_opts(conf, 'cinder', service_type='volumev3')
|
auth.register_auth_opts(conf, 'cinder', service_type='volumev3')
|
||||||
|
@ -12,122 +12,83 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
from http import client as http_client
|
|
||||||
import json
|
import json
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
from cinderclient import exceptions as cinder_exceptions
|
from keystoneauth1 import loading as ks_loading
|
||||||
import cinderclient.v3 as cinderclient
|
import openstack
|
||||||
|
from openstack.connection import exceptions as openstack_exc
|
||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
|
|
||||||
from ironic.common import cinder
|
from ironic.common import cinder
|
||||||
from ironic.common import context
|
from ironic.common import context
|
||||||
from ironic.common import exception
|
from ironic.common import exception
|
||||||
from ironic.common import keystone
|
|
||||||
from ironic.conductor import task_manager
|
from ironic.conductor import task_manager
|
||||||
from ironic.tests import base
|
from ironic.tests import base
|
||||||
from ironic.tests.unit.db import base as db_base
|
from ironic.tests.unit.db import base as db_base
|
||||||
from ironic.tests.unit.objects import utils as object_utils
|
from ironic.tests.unit.objects import utils as object_utils
|
||||||
|
|
||||||
|
|
||||||
@mock.patch.object(keystone, 'get_auth', autospec=True)
|
|
||||||
@mock.patch.object(keystone, 'get_session', autospec=True)
|
|
||||||
class TestCinderSession(base.TestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(TestCinderSession, self).setUp()
|
|
||||||
self.config(timeout=1,
|
|
||||||
retries=2,
|
|
||||||
group='cinder')
|
|
||||||
cinder._CINDER_SESSION = None
|
|
||||||
|
|
||||||
def test__get_cinder_session(self, mock_keystone_session, mock_auth):
|
|
||||||
"""Check establishing new session when no session exists."""
|
|
||||||
mock_keystone_session.return_value = 'session1'
|
|
||||||
self.assertEqual('session1', cinder._get_cinder_session())
|
|
||||||
mock_keystone_session.assert_called_once_with('cinder')
|
|
||||||
|
|
||||||
"""Check if existing session is used."""
|
|
||||||
mock_keystone_session.reset_mock()
|
|
||||||
mock_keystone_session.return_value = 'session2'
|
|
||||||
self.assertEqual('session1', cinder._get_cinder_session())
|
|
||||||
self.assertFalse(mock_keystone_session.called)
|
|
||||||
self.assertFalse(mock_auth.called)
|
|
||||||
|
|
||||||
|
|
||||||
@mock.patch('ironic.common.keystone.get_adapter', autospec=True)
|
|
||||||
@mock.patch('ironic.common.keystone.get_service_auth', autospec=True,
|
@mock.patch('ironic.common.keystone.get_service_auth', autospec=True,
|
||||||
return_value=mock.sentinel.sauth)
|
return_value=mock.sentinel.sauth)
|
||||||
@mock.patch('ironic.common.keystone.get_auth', autospec=True)
|
@mock.patch('ironic.common.keystone.get_auth', autospec=True,
|
||||||
|
return_value=mock.sentinel.auth)
|
||||||
|
@mock.patch('ironic.common.keystone.get_adapter', autospec=True)
|
||||||
@mock.patch('ironic.common.keystone.get_session', autospec=True,
|
@mock.patch('ironic.common.keystone.get_session', autospec=True,
|
||||||
return_value=mock.sentinel.session)
|
return_value=mock.sentinel.session)
|
||||||
@mock.patch.object(cinderclient.Client, '__init__', autospec=True,
|
@mock.patch.object(openstack.connection, "Connection", autospec=True)
|
||||||
return_value=None)
|
|
||||||
class TestCinderClient(base.TestCase):
|
class TestCinderClient(base.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestCinderClient, self).setUp()
|
super(TestCinderClient, self).setUp()
|
||||||
self.config(timeout=1,
|
# NOTE(pas-ha) register keystoneauth dynamic options manually
|
||||||
retries=2,
|
plugin = ks_loading.get_plugin_loader('password')
|
||||||
|
opts = ks_loading.get_auth_plugin_conf_options(plugin)
|
||||||
|
self.cfg_fixture.register_opts(opts, group='cinder')
|
||||||
|
self.config(retries=2,
|
||||||
group='cinder')
|
group='cinder')
|
||||||
|
self.config(username='test-admin-user',
|
||||||
|
project_name='test-admin-tenant',
|
||||||
|
password='test-admin-password',
|
||||||
|
auth_url='test-auth-uri',
|
||||||
|
auth_type='password',
|
||||||
|
interface='internal',
|
||||||
|
service_type='block_storage',
|
||||||
|
timeout=10,
|
||||||
|
group='cinder')
|
||||||
|
# force-reset the global session object
|
||||||
cinder._CINDER_SESSION = None
|
cinder._CINDER_SESSION = None
|
||||||
self.context = context.RequestContext(global_request_id='global')
|
self.context = context.RequestContext(global_request_id='global')
|
||||||
|
|
||||||
def _assert_client_call(self, init_mock, url, auth=mock.sentinel.auth,
|
def test_get_cinder_client_with_context(self, mock_client_init,
|
||||||
auth_from_config=None):
|
mock_session, mock_adapter,
|
||||||
if not auth_from_config:
|
mock_auth, mock_sauth):
|
||||||
self.context.auth_token = 'meow'
|
self.context = context.RequestContext(global_request_id='global',
|
||||||
cinder.get_client(self.context, auth_from_config=auth_from_config)
|
auth_token='test-token-123')
|
||||||
init_mock.assert_called_once_with(
|
cinder.get_client(context=self.context)
|
||||||
mock.ANY,
|
mock_client_init.assert_called_once_with(
|
||||||
session=mock.sentinel.session,
|
session=mock.sentinel.session,
|
||||||
auth=auth,
|
block_storage_endpoint_override=mock.ANY,
|
||||||
endpoint_override=url,
|
block_storage_api_version='3')
|
||||||
connect_retries=2,
|
# testing handling of default url_timeout
|
||||||
global_request_id='global')
|
|
||||||
|
|
||||||
def test_get_client(self, mock_client_init, mock_session, mock_auth,
|
|
||||||
mock_sauth, mock_adapter):
|
|
||||||
mock_auth.return_value = mock_auth_obj = mock.Mock()
|
|
||||||
mock_auth_obj.get_project_id.return_value = '1111'
|
|
||||||
mock_adapter.return_value = mock_adapter_obj = mock.Mock()
|
|
||||||
mock_adapter_obj.get_endpoint.side_effect = iter([
|
|
||||||
'cinder_url/1111',
|
|
||||||
'cinder_url'])
|
|
||||||
self._assert_client_call(mock_client_init, 'cinder_url',
|
|
||||||
auth=mock.sentinel.sauth)
|
|
||||||
mock_session.assert_has_calls([
|
mock_session.assert_has_calls([
|
||||||
mock.call('cinder'),
|
mock.call('cinder'),
|
||||||
mock.call('cinder', timeout=1, auth=mock.sentinel.sauth)])
|
mock.call('cinder', auth=mock.sentinel.sauth, timeout=10)
|
||||||
mock_auth.assert_called_once_with('cinder')
|
])
|
||||||
mock_adapter.assert_has_calls([
|
|
||||||
mock.call('cinder', session=mock.sentinel.session,
|
|
||||||
auth=mock_auth_obj),
|
|
||||||
|
|
||||||
mock.call('cinder', session=mock.sentinel.session,
|
def test__get_cinder_session(self, mock_client_init,
|
||||||
auth=mock.sentinel.sauth)])
|
mock_session, mock_adapter,
|
||||||
self.assertTrue(mock_sauth.called)
|
mock_auth, mock_sauth):
|
||||||
|
"""Check establishing new session when no session exists."""
|
||||||
|
mock_session.return_value = 'session1'
|
||||||
|
self.assertEqual('session1', cinder._get_cinder_session())
|
||||||
|
mock_session.assert_called_once_with('cinder')
|
||||||
|
|
||||||
def test_get_client_service_token(self, mock_client_init, mock_session,
|
"""Check if existing session is used."""
|
||||||
mock_auth, mock_sauth, mock_adapter):
|
mock_session.reset_mock()
|
||||||
mock_auth.return_value = mock_auth_obj = mock.Mock()
|
mock_session.return_value = 'session2'
|
||||||
mock_auth_obj.get_project_id.return_value = '1111'
|
self.assertEqual('session1', cinder._get_cinder_session())
|
||||||
mock_adapter.return_value = mock_adapter_obj = mock.Mock()
|
self.assertFalse(mock_session.called)
|
||||||
mock_adapter_obj.get_endpoint.side_effect = iter([
|
|
||||||
'cinder_url/1111',
|
|
||||||
'cinder_url'])
|
|
||||||
self._assert_client_call(
|
|
||||||
mock_client_init,
|
|
||||||
'cinder_url',
|
|
||||||
auth=None,
|
|
||||||
auth_from_config=True)
|
|
||||||
mock_session.assert_has_calls([
|
|
||||||
mock.call('cinder'),
|
|
||||||
mock.call('cinder', timeout=1, auth=mock_auth_obj)])
|
|
||||||
mock_auth.assert_called_once_with('cinder')
|
|
||||||
mock_adapter.assert_called_once_with(
|
|
||||||
'cinder', session=mock.sentinel.session, auth=mock_auth_obj)
|
|
||||||
self.assertFalse(mock_sauth.called)
|
|
||||||
|
|
||||||
|
|
||||||
class TestCinderUtils(db_base.DbTestCase):
|
class TestCinderUtils(db_base.DbTestCase):
|
||||||
@ -140,11 +101,11 @@ class TestCinderUtils(db_base.DbTestCase):
|
|||||||
|
|
||||||
def test_is_volume_available(self):
|
def test_is_volume_available(self):
|
||||||
available_volumes = [
|
available_volumes = [
|
||||||
mock.Mock(status=cinder.AVAILABLE, multiattach=False),
|
mock.Mock(status=cinder.AVAILABLE, is_multiattach=False),
|
||||||
mock.Mock(status=cinder.IN_USE, multiattach=True)]
|
mock.Mock(status=cinder.IN_USE, is_multiattach=True)]
|
||||||
unavailable_volumes = [
|
unavailable_volumes = [
|
||||||
mock.Mock(status=cinder.IN_USE, multiattach=False),
|
mock.Mock(status=cinder.IN_USE, is_multiattach=False),
|
||||||
mock.Mock(status='fake-non-status', multiattach=True)]
|
mock.Mock(status='fake-non-status', is_multiattach=True)]
|
||||||
|
|
||||||
for vol in available_volumes:
|
for vol in available_volumes:
|
||||||
result = cinder.is_volume_available(vol)
|
result = cinder.is_volume_available(vol)
|
||||||
@ -201,10 +162,7 @@ class TestCinderUtils(db_base.DbTestCase):
|
|||||||
self.assertEqual(expected_data, data)
|
self.assertEqual(expected_data, data)
|
||||||
|
|
||||||
|
|
||||||
@mock.patch.object(cinder, '_get_cinder_session', autospec=True)
|
@mock.patch.object(cinder, 'get_client', autospec=True)
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager, 'set_metadata',
|
|
||||||
autospec=True)
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager, 'get', autospec=True)
|
|
||||||
class TestCinderActions(db_base.DbTestCase):
|
class TestCinderActions(db_base.DbTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -214,17 +172,10 @@ class TestCinderActions(db_base.DbTestCase):
|
|||||||
instance_uuid=uuidutils.generate_uuid())
|
instance_uuid=uuidutils.generate_uuid())
|
||||||
self.mount_point = 'ironic_mountpoint'
|
self.mount_point = 'ironic_mountpoint'
|
||||||
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager, 'attach',
|
|
||||||
autospec=True)
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager,
|
|
||||||
'initialize_connection', autospec=True)
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager, 'reserve',
|
|
||||||
autospec=True)
|
|
||||||
@mock.patch.object(cinder, 'is_volume_attached', autospec=True)
|
@mock.patch.object(cinder, 'is_volume_attached', autospec=True)
|
||||||
@mock.patch.object(cinder, '_create_metadata_dictionary', autospec=True)
|
@mock.patch.object(cinder, '_create_metadata_dictionary', autospec=True)
|
||||||
def test_attach_volumes(self, mock_create_meta, mock_is_attached,
|
def test_attach_volumes(self, mock_create_meta, mock_is_attached,
|
||||||
mock_reserve, mock_init, mock_attach, mock_get,
|
mock_client):
|
||||||
mock_set_meta, mock_session):
|
|
||||||
"""Iterate once on a single volume with success."""
|
"""Iterate once on a single volume with success."""
|
||||||
|
|
||||||
volume_id = '111111111-0000-0000-0000-000000000003'
|
volume_id = '111111111-0000-0000-0000-000000000003'
|
||||||
@ -241,7 +192,16 @@ class TestCinderActions(db_base.DbTestCase):
|
|||||||
connector = {'foo': 'bar'}
|
connector = {'foo': 'bar'}
|
||||||
mock_create_meta.return_value = {'bar': 'baz'}
|
mock_create_meta.return_value = {'bar': 'baz'}
|
||||||
mock_is_attached.return_value = False
|
mock_is_attached.return_value = False
|
||||||
mock_get.return_value = mock.Mock(attachments=[], id='000-001')
|
|
||||||
|
mock_bs = mock_client.return_value
|
||||||
|
mock_get = mock_bs.get_volume
|
||||||
|
mock_init = mock_bs.init_volume_attachment
|
||||||
|
mock_reserve = mock_bs.reserve_volume
|
||||||
|
mock_attach = mock_bs.attach_volume
|
||||||
|
mock_set_meta = mock_bs.set_volume_metadata
|
||||||
|
|
||||||
|
volume = mock.Mock(attachments=[], id='000-001')
|
||||||
|
mock_get.return_value = volume
|
||||||
|
|
||||||
mock_init.return_value = {
|
mock_init.return_value = {
|
||||||
'driver_volume_type': 'iscsi',
|
'driver_volume_type': 'iscsi',
|
||||||
@ -254,25 +214,17 @@ class TestCinderActions(db_base.DbTestCase):
|
|||||||
attachments = cinder.attach_volumes(task, volumes, connector)
|
attachments = cinder.attach_volumes(task, volumes, connector)
|
||||||
|
|
||||||
self.assertEqual(expected, attachments)
|
self.assertEqual(expected, attachments)
|
||||||
mock_reserve.assert_called_once_with(mock.ANY, volume_id)
|
mock_reserve.assert_called_once_with(volume)
|
||||||
mock_init.assert_called_once_with(mock.ANY, volume_id, connector)
|
mock_init.assert_called_once_with(volume, connector)
|
||||||
mock_attach.assert_called_once_with(mock.ANY, volume_id,
|
mock_attach.assert_called_once_with(volume,
|
||||||
self.node.instance_uuid,
|
self.mount_point,
|
||||||
self.mount_point)
|
instance=self.node.instance_uuid)
|
||||||
mock_set_meta.assert_called_once_with(mock.ANY, volume_id,
|
mock_set_meta.assert_called_once_with(volume, bar='baz')
|
||||||
{'bar': 'baz'})
|
mock_get.assert_called_once_with(volume_id)
|
||||||
mock_get.assert_called_once_with(mock.ANY, volume_id)
|
|
||||||
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager, 'attach',
|
|
||||||
autospec=True)
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager,
|
|
||||||
'initialize_connection', autospec=True)
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager, 'reserve',
|
|
||||||
autospec=True)
|
|
||||||
@mock.patch.object(cinder, '_create_metadata_dictionary', autospec=True)
|
@mock.patch.object(cinder, '_create_metadata_dictionary', autospec=True)
|
||||||
def test_attach_volumes_one_attached(
|
def test_attach_volumes_one_attached(
|
||||||
self, mock_create_meta, mock_reserve, mock_init, mock_attach,
|
self, mock_create_meta, mock_client):
|
||||||
mock_get, mock_set_meta, mock_session):
|
|
||||||
"""Iterate with two volumes, one already attached."""
|
"""Iterate with two volumes, one already attached."""
|
||||||
|
|
||||||
volume_id = '111111111-0000-0000-0000-000000000003'
|
volume_id = '111111111-0000-0000-0000-000000000003'
|
||||||
@ -292,8 +244,17 @@ class TestCinderActions(db_base.DbTestCase):
|
|||||||
volumes = [volume_id, 'already_attached']
|
volumes = [volume_id, 'already_attached']
|
||||||
connector = {'foo': 'bar'}
|
connector = {'foo': 'bar'}
|
||||||
mock_create_meta.return_value = {'bar': 'baz'}
|
mock_create_meta.return_value = {'bar': 'baz'}
|
||||||
|
|
||||||
|
mock_bs = mock_client.return_value
|
||||||
|
mock_get = mock_bs.get_volume
|
||||||
|
mock_init = mock_bs.init_volume_attachment
|
||||||
|
mock_reserve = mock_bs.reserve_volume
|
||||||
|
mock_attach = mock_bs.attach_volume
|
||||||
|
mock_set_meta = mock_bs.set_volume_metadata
|
||||||
|
|
||||||
|
volume = mock.Mock(attachments=[], id='000-000')
|
||||||
mock_get.side_effect = [
|
mock_get.side_effect = [
|
||||||
mock.Mock(attachments=[], id='000-000'),
|
volume,
|
||||||
mock.Mock(attachments=[{'server_id': self.node.uuid}],
|
mock.Mock(attachments=[{'server_id': self.node.uuid}],
|
||||||
id='000-001')
|
id='000-001')
|
||||||
]
|
]
|
||||||
@ -309,21 +270,18 @@ class TestCinderActions(db_base.DbTestCase):
|
|||||||
attachments = cinder.attach_volumes(task, volumes, connector)
|
attachments = cinder.attach_volumes(task, volumes, connector)
|
||||||
|
|
||||||
self.assertEqual(expected, attachments)
|
self.assertEqual(expected, attachments)
|
||||||
mock_reserve.assert_called_once_with(mock.ANY, volume_id)
|
mock_reserve.assert_called_once_with(volume)
|
||||||
mock_init.assert_called_once_with(mock.ANY, volume_id, connector)
|
mock_init.assert_called_once_with(volume, connector)
|
||||||
mock_attach.assert_called_once_with(mock.ANY, volume_id,
|
mock_attach.assert_called_once_with(volume,
|
||||||
self.node.instance_uuid,
|
self.mount_point,
|
||||||
self.mount_point)
|
instance=self.node.instance_uuid)
|
||||||
mock_set_meta.assert_called_once_with(mock.ANY, volume_id,
|
mock_set_meta.assert_called_once_with(volume, bar='baz')
|
||||||
{'bar': 'baz'})
|
|
||||||
|
|
||||||
@mock.patch.object(cinderclient.Client, '__init__', autospec=True)
|
def test_attach_volumes_conn_init_failure(
|
||||||
def test_attach_volumes_client_init_failure(
|
self, mock_client):
|
||||||
self, mock_client, mock_get, mock_set_meta, mock_session):
|
|
||||||
connector = {'foo': 'bar'}
|
connector = {'foo': 'bar'}
|
||||||
volumes = ['111111111-0000-0000-0000-000000000003']
|
volumes = ['111111111-0000-0000-0000-000000000003']
|
||||||
mock_client.side_effect = cinder_exceptions.BadRequest(
|
mock_client.side_effect = openstack_exc.EndpointNotFound()
|
||||||
http_client.BAD_REQUEST)
|
|
||||||
|
|
||||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||||
self.assertRaises(exception.StorageError,
|
self.assertRaises(exception.StorageError,
|
||||||
@ -332,29 +290,31 @@ class TestCinderActions(db_base.DbTestCase):
|
|||||||
volumes,
|
volumes,
|
||||||
connector)
|
connector)
|
||||||
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager, 'attach',
|
|
||||||
autospec=True)
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager,
|
|
||||||
'initialize_connection', autospec=True)
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager, 'reserve',
|
|
||||||
autospec=True)
|
|
||||||
@mock.patch.object(cinder, '_create_metadata_dictionary', autospec=True)
|
@mock.patch.object(cinder, '_create_metadata_dictionary', autospec=True)
|
||||||
def test_attach_volumes_vol_not_found(
|
def test_attach_volumes_vol_not_found(
|
||||||
self, mock_create_meta, mock_reserve, mock_init, mock_attach,
|
self, mock_create_meta, mock_client):
|
||||||
mock_get, mock_set_meta, mock_session):
|
|
||||||
"""Raise an error if the volume lookup fails"""
|
"""Raise an error if the volume lookup fails"""
|
||||||
|
|
||||||
def __mock_get_side_effect(client, volume_id):
|
volume = mock.Mock(attachments=[], uuid='000-000')
|
||||||
if volume_id == 'not_found':
|
|
||||||
raise cinder_exceptions.NotFound(
|
def __mock_get_side_effect(vol):
|
||||||
http_client.NOT_FOUND, message='error')
|
if vol == 'not_found':
|
||||||
|
raise openstack_exc.ResourceNotFound()
|
||||||
else:
|
else:
|
||||||
return mock.Mock(attachments=[], uuid='000-000')
|
return volume
|
||||||
|
|
||||||
volumes = ['111111111-0000-0000-0000-000000000003',
|
volumes = ['111111111-0000-0000-0000-000000000003',
|
||||||
'not_found',
|
'not_found',
|
||||||
'not_reached']
|
'not_reached']
|
||||||
connector = {'foo': 'bar'}
|
connector = {'foo': 'bar'}
|
||||||
|
|
||||||
|
mock_bs = mock_client.return_value
|
||||||
|
mock_get = mock_bs.get_volume
|
||||||
|
mock_init = mock_bs.init_volume_attachment
|
||||||
|
mock_reserve = mock_bs.reserve_volume
|
||||||
|
mock_attach = mock_bs.attach_volume
|
||||||
|
mock_set_meta = mock_bs.set_volume_metadata
|
||||||
|
|
||||||
mock_get.side_effect = __mock_get_side_effect
|
mock_get.side_effect = __mock_get_side_effect
|
||||||
mock_create_meta.return_value = {'bar': 'baz'}
|
mock_create_meta.return_value = {'bar': 'baz'}
|
||||||
|
|
||||||
@ -364,33 +324,27 @@ class TestCinderActions(db_base.DbTestCase):
|
|||||||
task,
|
task,
|
||||||
volumes,
|
volumes,
|
||||||
connector)
|
connector)
|
||||||
mock_get.assert_any_call(mock.ANY,
|
mock_get.assert_any_call('111111111-0000-0000-0000-000000000003')
|
||||||
'111111111-0000-0000-0000-000000000003')
|
mock_get.assert_any_call('not_found')
|
||||||
mock_get.assert_any_call(mock.ANY, 'not_found')
|
|
||||||
self.assertEqual(2, mock_get.call_count)
|
self.assertEqual(2, mock_get.call_count)
|
||||||
mock_reserve.assert_called_once_with(
|
mock_reserve.assert_called_once_with(volume)
|
||||||
mock.ANY, '111111111-0000-0000-0000-000000000003')
|
mock_init.assert_called_once_with(volume, connector)
|
||||||
mock_init.assert_called_once_with(
|
|
||||||
mock.ANY, '111111111-0000-0000-0000-000000000003', connector)
|
|
||||||
mock_attach.assert_called_once_with(
|
mock_attach.assert_called_once_with(
|
||||||
mock.ANY, '111111111-0000-0000-0000-000000000003',
|
volume, self.mount_point, instance=self.node.instance_uuid)
|
||||||
self.node.instance_uuid, self.mount_point)
|
mock_set_meta.assert_called_once_with(volume, bar='baz')
|
||||||
mock_set_meta.assert_called_once_with(
|
|
||||||
mock.ANY, '111111111-0000-0000-0000-000000000003', {'bar': 'baz'})
|
|
||||||
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager, 'reserve',
|
|
||||||
autospec=True)
|
|
||||||
@mock.patch.object(cinder, 'is_volume_attached', autospec=True)
|
@mock.patch.object(cinder, 'is_volume_attached', autospec=True)
|
||||||
def test_attach_volumes_reserve_failure(self, mock_is_attached,
|
def test_attach_volumes_reserve_failure(self, mock_is_attached,
|
||||||
mock_reserve, mock_get,
|
mock_client):
|
||||||
mock_set_meta, mock_session):
|
|
||||||
volumes = ['111111111-0000-0000-0000-000000000003']
|
volumes = ['111111111-0000-0000-0000-000000000003']
|
||||||
connector = {'foo': 'bar'}
|
connector = {'foo': 'bar'}
|
||||||
volume = mock.Mock(attachments=[])
|
volume = mock.Mock(attachments=[])
|
||||||
|
mock_bs = mock_client.return_value
|
||||||
|
mock_get = mock_bs.get_volume
|
||||||
|
mock_reserve = mock_bs.reserve_volume
|
||||||
mock_get.return_value = volume
|
mock_get.return_value = volume
|
||||||
mock_is_attached.return_value = False
|
mock_is_attached.return_value = False
|
||||||
mock_reserve.side_effect = cinder_exceptions.NotAcceptable(
|
mock_reserve.side_effect = openstack_exc.HttpException()
|
||||||
http_client.NOT_ACCEPTABLE)
|
|
||||||
|
|
||||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||||
self.assertRaises(exception.StorageError,
|
self.assertRaises(exception.StorageError,
|
||||||
@ -400,15 +354,11 @@ class TestCinderActions(db_base.DbTestCase):
|
|||||||
connector)
|
connector)
|
||||||
mock_is_attached.assert_called_once_with(mock.ANY, volume)
|
mock_is_attached.assert_called_once_with(mock.ANY, volume)
|
||||||
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager,
|
|
||||||
'initialize_connection', autospec=True)
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager, 'reserve',
|
|
||||||
autospec=True)
|
|
||||||
@mock.patch.object(cinder, 'is_volume_attached', autospec=True)
|
@mock.patch.object(cinder, 'is_volume_attached', autospec=True)
|
||||||
@mock.patch.object(cinder, '_create_metadata_dictionary', autospec=True)
|
@mock.patch.object(cinder, '_create_metadata_dictionary', autospec=True)
|
||||||
def test_attach_volumes_initialize_connection_failure(
|
def test_attach_volumes_initialize_connection_failure(
|
||||||
self, mock_create_meta, mock_is_attached, mock_reserve, mock_init,
|
self, mock_create_meta, mock_is_attached,
|
||||||
mock_get, mock_set_meta, mock_session):
|
mock_client):
|
||||||
"""Fail attachment upon an initialization failure."""
|
"""Fail attachment upon an initialization failure."""
|
||||||
|
|
||||||
volume_id = '111111111-0000-0000-0000-000000000003'
|
volume_id = '111111111-0000-0000-0000-000000000003'
|
||||||
@ -416,9 +366,15 @@ class TestCinderActions(db_base.DbTestCase):
|
|||||||
connector = {'foo': 'bar'}
|
connector = {'foo': 'bar'}
|
||||||
mock_create_meta.return_value = {'bar': 'baz'}
|
mock_create_meta.return_value = {'bar': 'baz'}
|
||||||
mock_is_attached.return_value = False
|
mock_is_attached.return_value = False
|
||||||
mock_get.return_value = mock.Mock(attachments=[])
|
|
||||||
mock_init.side_effect = cinder_exceptions.NotAcceptable(
|
mock_bs = mock_client.return_value
|
||||||
http_client.NOT_ACCEPTABLE)
|
mock_get = mock_bs.get_volume
|
||||||
|
mock_init = mock_bs.init_volume_attachment
|
||||||
|
mock_reserve = mock_bs.reserve_volume
|
||||||
|
|
||||||
|
volume = mock.Mock(attachments=[])
|
||||||
|
mock_get.return_value = volume
|
||||||
|
mock_init.side_effect = openstack_exc.HttpException("not acceptable")
|
||||||
|
|
||||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||||
self.assertRaises(exception.StorageError,
|
self.assertRaises(exception.StorageError,
|
||||||
@ -427,63 +383,55 @@ class TestCinderActions(db_base.DbTestCase):
|
|||||||
volumes,
|
volumes,
|
||||||
connector)
|
connector)
|
||||||
|
|
||||||
mock_get.assert_called_once_with(mock.ANY, volume_id)
|
mock_get.assert_called_once_with(volume_id)
|
||||||
mock_reserve.assert_called_once_with(mock.ANY, volume_id)
|
mock_reserve.assert_called_once_with(volume)
|
||||||
mock_init.assert_called_once_with(mock.ANY, volume_id, connector)
|
mock_init.assert_called_once_with(volume, connector)
|
||||||
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager, 'attach',
|
|
||||||
autospec=True)
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager,
|
|
||||||
'initialize_connection', autospec=True)
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager, 'reserve',
|
|
||||||
autospec=True)
|
|
||||||
@mock.patch.object(cinder, 'is_volume_attached', autospec=True)
|
@mock.patch.object(cinder, 'is_volume_attached', autospec=True)
|
||||||
@mock.patch.object(cinder, '_create_metadata_dictionary', autospec=True)
|
@mock.patch.object(cinder, '_create_metadata_dictionary', autospec=True)
|
||||||
def test_attach_volumes_attach_record_failure(
|
def test_attach_volumes_attach_record_failure(
|
||||||
self, mock_create_meta, mock_is_attached, mock_reserve,
|
self, mock_create_meta, mock_is_attached, mock_client):
|
||||||
mock_init, mock_attach, mock_get, mock_set_meta, mock_session):
|
|
||||||
"""Attach a volume and fail if final record failure occurs"""
|
"""Attach a volume and fail if final record failure occurs"""
|
||||||
volume_id = '111111111-0000-0000-0000-000000000003'
|
volume_id = '111111111-0000-0000-0000-000000000003'
|
||||||
volumes = [volume_id]
|
volumes = [volume_id]
|
||||||
connector = {'foo': 'bar'}
|
connector = {'foo': 'bar'}
|
||||||
mock_create_meta.return_value = {'bar': 'baz'}
|
mock_create_meta.return_value = {'bar': 'baz'}
|
||||||
mock_is_attached.return_value = False
|
mock_is_attached.return_value = False
|
||||||
mock_get.return_value = mock.Mock(attachments=[], id='000-003')
|
|
||||||
|
mock_bs = mock_client.return_value
|
||||||
|
mock_get = mock_bs.get_volume
|
||||||
|
mock_init = mock_bs.init_volume_attachment
|
||||||
|
mock_reserve = mock_bs.reserve_volume
|
||||||
|
mock_attach = mock_bs.attach_volume
|
||||||
|
|
||||||
|
volume = mock.Mock(attachments=[], id='000-003')
|
||||||
|
mock_get.return_value = volume
|
||||||
mock_init.return_value = {
|
mock_init.return_value = {
|
||||||
'driver_volume_type': 'iscsi',
|
'driver_volume_type': 'iscsi',
|
||||||
'data': {
|
'data': {
|
||||||
'target_iqn': 'iqn.2010-10.org.openstack:volume-00000002',
|
'target_iqn': 'iqn.2010-10.org.openstack:volume-00000002',
|
||||||
'target_portal': '127.0.0.0.1:3260',
|
'target_portal': '127.0.0.0.1:3260',
|
||||||
'target_lun': 2}}
|
'target_lun': 2}}
|
||||||
mock_attach.side_effect = cinder_exceptions.ClientException(
|
mock_attach.side_effect = openstack_exc.HttpException("not acceptable")
|
||||||
http_client.NOT_ACCEPTABLE, 'error')
|
|
||||||
|
|
||||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||||
self.assertRaises(exception.StorageError, cinder.attach_volumes,
|
self.assertRaises(exception.StorageError, cinder.attach_volumes,
|
||||||
task, volumes, connector)
|
task, volumes, connector)
|
||||||
|
|
||||||
mock_reserve.assert_called_once_with(mock.ANY, volume_id)
|
mock_reserve.assert_called_once_with(volume)
|
||||||
mock_init.assert_called_once_with(mock.ANY, volume_id, connector)
|
mock_init.assert_called_once_with(volume, connector)
|
||||||
mock_attach.assert_called_once_with(mock.ANY, volume_id,
|
mock_attach.assert_called_once_with(volume,
|
||||||
self.node.instance_uuid,
|
self.mount_point,
|
||||||
self.mount_point)
|
instance=self.node.instance_uuid)
|
||||||
mock_get.assert_called_once_with(mock.ANY, volume_id)
|
mock_get.assert_called_once_with(volume_id)
|
||||||
mock_is_attached.assert_called_once_with(mock.ANY,
|
mock_is_attached.assert_called_once_with(mock.ANY, volume)
|
||||||
mock_get.return_value)
|
|
||||||
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager, 'attach',
|
|
||||||
autospec=True)
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager,
|
|
||||||
'initialize_connection', autospec=True)
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager, 'reserve',
|
|
||||||
autospec=True)
|
|
||||||
@mock.patch.object(cinder, 'is_volume_attached', autospec=True)
|
@mock.patch.object(cinder, 'is_volume_attached', autospec=True)
|
||||||
@mock.patch.object(cinder, '_create_metadata_dictionary', autospec=True)
|
@mock.patch.object(cinder, '_create_metadata_dictionary', autospec=True)
|
||||||
@mock.patch.object(cinder, 'LOG', autospec=True)
|
@mock.patch.object(cinder, 'LOG', autospec=True)
|
||||||
def test_attach_volumes_attach_set_meta_failure(
|
def test_attach_volumes_attach_set_meta_failure(
|
||||||
self, mock_log, mock_create_meta, mock_is_attached,
|
self, mock_log, mock_create_meta, mock_is_attached,
|
||||||
mock_reserve, mock_init, mock_attach, mock_get, mock_set_meta,
|
mock_client):
|
||||||
mock_session):
|
|
||||||
"""Attach a volume and tolerate set_metadata failure."""
|
"""Attach a volume and tolerate set_metadata failure."""
|
||||||
|
|
||||||
expected = [{
|
expected = [{
|
||||||
@ -499,43 +447,42 @@ class TestCinderActions(db_base.DbTestCase):
|
|||||||
connector = {'foo': 'bar'}
|
connector = {'foo': 'bar'}
|
||||||
mock_create_meta.return_value = {'bar': 'baz'}
|
mock_create_meta.return_value = {'bar': 'baz'}
|
||||||
mock_is_attached.return_value = False
|
mock_is_attached.return_value = False
|
||||||
mock_get.return_value = mock.Mock(attachments=[], id='000-000')
|
|
||||||
|
mock_bs = mock_client.return_value
|
||||||
|
mock_get = mock_bs.get_volume
|
||||||
|
mock_init = mock_bs.init_volume_attachment
|
||||||
|
mock_reserve = mock_bs.reserve_volume
|
||||||
|
mock_attach = mock_bs.attach_volume
|
||||||
|
mock_set_meta = mock_bs.set_volume_metadata
|
||||||
|
|
||||||
|
volume = mock.Mock(attachments=[], id='000-000')
|
||||||
|
mock_get.return_value = volume
|
||||||
mock_init.return_value = {
|
mock_init.return_value = {
|
||||||
'driver_volume_type': 'iscsi',
|
'driver_volume_type': 'iscsi',
|
||||||
'data': {
|
'data': {
|
||||||
'target_iqn': 'iqn.2010-10.org.openstack:volume-00000002',
|
'target_iqn': 'iqn.2010-10.org.openstack:volume-00000002',
|
||||||
'target_portal': '127.0.0.0.1:3260',
|
'target_portal': '127.0.0.0.1:3260',
|
||||||
'target_lun': 2}}
|
'target_lun': 2}}
|
||||||
mock_set_meta.side_effect = cinder_exceptions.NotAcceptable(
|
mock_set_meta.side_effect = openstack_exc.HttpException()
|
||||||
http_client.NOT_ACCEPTABLE)
|
|
||||||
|
|
||||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||||
attachments = cinder.attach_volumes(task, volumes, connector)
|
attachments = cinder.attach_volumes(task, volumes, connector)
|
||||||
|
|
||||||
self.assertEqual(expected, attachments)
|
self.assertEqual(expected, attachments)
|
||||||
mock_reserve.assert_called_once_with(mock.ANY, volume_id)
|
mock_reserve.assert_called_once_with(volume)
|
||||||
mock_init.assert_called_once_with(mock.ANY, volume_id, connector)
|
mock_init.assert_called_once_with(volume, connector)
|
||||||
mock_attach.assert_called_once_with(mock.ANY, volume_id,
|
mock_attach.assert_called_once_with(volume,
|
||||||
self.node.instance_uuid,
|
self.mount_point,
|
||||||
self.mount_point)
|
instance=self.node.instance_uuid)
|
||||||
mock_set_meta.assert_called_once_with(mock.ANY, volume_id,
|
mock_set_meta.assert_called_once_with(volume, bar='baz')
|
||||||
{'bar': 'baz'})
|
mock_get.assert_called_once_with(volume_id)
|
||||||
mock_get.assert_called_once_with(mock.ANY, volume_id)
|
mock_is_attached.assert_called_once_with(mock.ANY, volume)
|
||||||
mock_is_attached.assert_called_once_with(mock.ANY,
|
|
||||||
mock_get.return_value)
|
|
||||||
self.assertTrue(mock_log.warning.called)
|
self.assertTrue(mock_log.warning.called)
|
||||||
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager, 'detach',
|
|
||||||
autospec=True)
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager,
|
|
||||||
'terminate_connection', autospec=True)
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager, 'begin_detaching',
|
|
||||||
autospec=True)
|
|
||||||
@mock.patch.object(cinder, 'is_volume_attached', autospec=True)
|
@mock.patch.object(cinder, 'is_volume_attached', autospec=True)
|
||||||
@mock.patch.object(cinder, '_create_metadata_dictionary', autospec=True)
|
@mock.patch.object(cinder, '_create_metadata_dictionary', autospec=True)
|
||||||
def test_detach_volumes(
|
def test_detach_volumes(
|
||||||
self, mock_create_meta, mock_is_attached, mock_begin, mock_term,
|
self, mock_create_meta, mock_is_attached, mock_client):
|
||||||
mock_detach, mock_get, mock_set_meta, mock_session):
|
|
||||||
"""Iterate once and detach a volume without issues."""
|
"""Iterate once and detach a volume without issues."""
|
||||||
volume_id = '111111111-0000-0000-0000-000000000003'
|
volume_id = '111111111-0000-0000-0000-000000000003'
|
||||||
volumes = [volume_id]
|
volumes = [volume_id]
|
||||||
@ -543,28 +490,29 @@ class TestCinderActions(db_base.DbTestCase):
|
|||||||
connector = {'foo': 'bar'}
|
connector = {'foo': 'bar'}
|
||||||
mock_create_meta.return_value = {'bar': 'baz'}
|
mock_create_meta.return_value = {'bar': 'baz'}
|
||||||
mock_is_attached.return_value = True
|
mock_is_attached.return_value = True
|
||||||
mock_get.return_value = mock.Mock(attachments=[
|
|
||||||
|
mock_bs = mock_client.return_value
|
||||||
|
mock_get = mock_bs.get_volume
|
||||||
|
mock_begin = mock_bs.begin_volume_detaching
|
||||||
|
mock_term = mock_bs.terminate_volume_attachment
|
||||||
|
mock_detach = mock_bs.detach_volume
|
||||||
|
mock_set_meta = mock_bs.set_volume_metadata
|
||||||
|
|
||||||
|
volume = mock.Mock(attachments=[
|
||||||
{'server_id': self.node.uuid, 'attachment_id': 'qux'}])
|
{'server_id': self.node.uuid, 'attachment_id': 'qux'}])
|
||||||
|
mock_get.return_value = volume
|
||||||
|
|
||||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||||
cinder.detach_volumes(task, volumes, connector, allow_errors=False)
|
cinder.detach_volumes(task, volumes, connector, allow_errors=False)
|
||||||
|
|
||||||
mock_begin.assert_called_once_with(mock.ANY, volume_id)
|
mock_begin.assert_called_once_with(volume)
|
||||||
mock_term.assert_called_once_with(mock.ANY, volume_id, {'foo': 'bar'})
|
mock_term.assert_called_once_with(volume, {'foo': 'bar'})
|
||||||
mock_detach.assert_called_once_with(mock.ANY, volume_id, 'qux')
|
mock_detach.assert_called_once_with(volume, 'qux')
|
||||||
mock_set_meta.assert_called_once_with(mock.ANY, volume_id,
|
mock_set_meta.assert_called_once_with(volume, bar='baz')
|
||||||
{'bar': 'baz'})
|
|
||||||
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager, 'detach',
|
|
||||||
autospec=True)
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager,
|
|
||||||
'terminate_connection', autospec=True)
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager, 'begin_detaching',
|
|
||||||
autospec=True)
|
|
||||||
@mock.patch.object(cinder, '_create_metadata_dictionary', autospec=True)
|
@mock.patch.object(cinder, '_create_metadata_dictionary', autospec=True)
|
||||||
def test_detach_volumes_one_detached(
|
def test_detach_volumes_one_detached(
|
||||||
self, mock_create_meta, mock_begin, mock_term, mock_detach,
|
self, mock_create_meta, mock_client):
|
||||||
mock_get, mock_set_meta, mock_session):
|
|
||||||
"""Iterate with two volumes, one already detached."""
|
"""Iterate with two volumes, one already detached."""
|
||||||
volume_id = '111111111-0000-0000-0000-000000000003'
|
volume_id = '111111111-0000-0000-0000-000000000003'
|
||||||
volumes = [volume_id, 'detached']
|
volumes = [volume_id, 'detached']
|
||||||
@ -572,56 +520,49 @@ class TestCinderActions(db_base.DbTestCase):
|
|||||||
connector = {'foo': 'bar'}
|
connector = {'foo': 'bar'}
|
||||||
mock_create_meta.return_value = {'bar': 'baz'}
|
mock_create_meta.return_value = {'bar': 'baz'}
|
||||||
|
|
||||||
|
mock_bs = mock_client.return_value
|
||||||
|
mock_get = mock_bs.get_volume
|
||||||
|
mock_begin = mock_bs.begin_volume_detaching
|
||||||
|
mock_term = mock_bs.terminate_volume_attachment
|
||||||
|
mock_detach = mock_bs.detach_volume
|
||||||
|
mock_set_meta = mock_bs.set_volume_metadata
|
||||||
|
|
||||||
|
volume = mock.Mock(attachments=[
|
||||||
|
{'server_id': self.node.uuid, 'attachment_id': 'qux'}])
|
||||||
mock_get.side_effect = [
|
mock_get.side_effect = [
|
||||||
mock.Mock(attachments=[
|
volume, mock.Mock(attachments=[])
|
||||||
{'server_id': self.node.uuid, 'attachment_id': 'qux'}]),
|
|
||||||
mock.Mock(attachments=[])
|
|
||||||
]
|
]
|
||||||
|
|
||||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||||
cinder.detach_volumes(task, volumes, connector, allow_errors=False)
|
cinder.detach_volumes(task, volumes, connector, allow_errors=False)
|
||||||
|
|
||||||
mock_begin.assert_called_once_with(mock.ANY, volume_id)
|
mock_begin.assert_called_once_with(volume)
|
||||||
mock_term.assert_called_once_with(mock.ANY, volume_id, {'foo': 'bar'})
|
mock_term.assert_called_once_with(volume, {'foo': 'bar'})
|
||||||
mock_detach.assert_called_once_with(mock.ANY, volume_id, 'qux')
|
mock_detach.assert_called_once_with(volume, 'qux')
|
||||||
mock_set_meta.assert_called_once_with(mock.ANY, volume_id,
|
mock_set_meta.assert_called_once_with(volume, bar='baz')
|
||||||
{'bar': 'baz'})
|
|
||||||
|
|
||||||
@mock.patch.object(cinderclient.Client, '__init__', autospec=True)
|
def test_detach_volumes_conn_init_failure_bad_request(
|
||||||
def test_detach_volumes_client_init_failure_bad_request(
|
self, mock_client):
|
||||||
self, mock_client, mock_get, mock_set_meta, mock_session):
|
|
||||||
connector = {'foo': 'bar'}
|
connector = {'foo': 'bar'}
|
||||||
volumes = ['111111111-0000-0000-0000-000000000003']
|
volumes = ['111111111-0000-0000-0000-000000000003']
|
||||||
|
|
||||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||||
mock_client.side_effect = cinder_exceptions.BadRequest(
|
mock_client.side_effect = openstack_exc.BadRequestException()
|
||||||
http_client.BAD_REQUEST)
|
|
||||||
self.assertRaises(exception.StorageError,
|
self.assertRaises(exception.StorageError,
|
||||||
cinder.detach_volumes,
|
cinder.detach_volumes,
|
||||||
task,
|
task,
|
||||||
volumes,
|
volumes,
|
||||||
connector)
|
connector)
|
||||||
|
|
||||||
@mock.patch.object(cinderclient.Client, '__init__', autospec=True)
|
def test_detach_volumes_vol_not_found(self, mock_client):
|
||||||
def test_detach_volumes_client_init_failure_invalid_parameter_value(
|
|
||||||
self, mock_client, mock_get, mock_set_meta, mock_session):
|
|
||||||
connector = {'foo': 'bar'}
|
|
||||||
volumes = ['111111111-0000-0000-0000-000000000003']
|
|
||||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
|
||||||
# While we would be permitting failures, this is an exception that
|
|
||||||
# must be raised since the client cannot be initialized.
|
|
||||||
mock_client.side_effect = exception.InvalidParameterValue('error')
|
|
||||||
self.assertRaises(exception.StorageError,
|
|
||||||
cinder.detach_volumes, task, volumes,
|
|
||||||
connector, allow_errors=True)
|
|
||||||
|
|
||||||
def test_detach_volumes_vol_not_found(self, mock_get, mock_set_meta,
|
|
||||||
mock_session):
|
|
||||||
"""Raise an error if the volume lookup fails"""
|
"""Raise an error if the volume lookup fails"""
|
||||||
volumes = ['vol1']
|
volumes = ['vol1']
|
||||||
connector = {'foo': 'bar'}
|
connector = {'foo': 'bar'}
|
||||||
mock_get.side_effect = cinder_exceptions.NotFound(
|
mock_bs = mock_client.return_value
|
||||||
http_client.NOT_FOUND, message='error')
|
mock_get = mock_bs.get_volume
|
||||||
|
mock_set_meta = mock_bs.set_volume_metadata
|
||||||
|
|
||||||
|
mock_get.side_effect = openstack_exc.NotFoundException()
|
||||||
|
|
||||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||||
self.assertRaises(exception.StorageError,
|
self.assertRaises(exception.StorageError,
|
||||||
@ -635,27 +576,26 @@ class TestCinderActions(db_base.DbTestCase):
|
|||||||
cinder.detach_volumes(task, volumes, connector, allow_errors=True)
|
cinder.detach_volumes(task, volumes, connector, allow_errors=True)
|
||||||
self.assertFalse(mock_set_meta.called)
|
self.assertFalse(mock_set_meta.called)
|
||||||
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager, 'detach',
|
|
||||||
autospec=True)
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager,
|
|
||||||
'terminate_connection', autospec=True)
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager, 'begin_detaching',
|
|
||||||
autospec=True)
|
|
||||||
@mock.patch.object(cinder, 'is_volume_attached', autospec=True)
|
@mock.patch.object(cinder, 'is_volume_attached', autospec=True)
|
||||||
@mock.patch.object(cinder, '_create_metadata_dictionary', autospec=True)
|
@mock.patch.object(cinder, '_create_metadata_dictionary', autospec=True)
|
||||||
def test_detach_volumes_begin_detaching_failure(
|
def test_detach_volumes_begin_detaching_failure(
|
||||||
self, mock_create_meta, mock_is_attached, mock_begin, mock_term,
|
self, mock_create_meta, mock_is_attached, mock_client):
|
||||||
mock_detach, mock_get, mock_set_meta, mock_session):
|
|
||||||
|
|
||||||
volume_id = '111111111-0000-0000-0000-000000000003'
|
volume_id = '111111111-0000-0000-0000-000000000003'
|
||||||
volumes = [volume_id]
|
volumes = [volume_id]
|
||||||
connector = {'foo': 'bar'}
|
connector = {'foo': 'bar'}
|
||||||
|
mock_bs = mock_client.return_value
|
||||||
|
mock_get = mock_bs.get_volume
|
||||||
|
mock_begin = mock_bs.begin_volume_detaching
|
||||||
|
mock_term = mock_bs.terminate_volume_attachment
|
||||||
|
mock_detach = mock_bs.detach_volume
|
||||||
|
mock_set_meta = mock_bs.set_volume_metadata
|
||||||
|
|
||||||
volume = mock.Mock(attachments=[])
|
volume = mock.Mock(attachments=[])
|
||||||
mock_get.return_value = volume
|
mock_get.return_value = volume
|
||||||
mock_create_meta.return_value = {'bar': 'baz'}
|
mock_create_meta.return_value = {'bar': 'baz'}
|
||||||
mock_is_attached.return_value = True
|
mock_is_attached.return_value = True
|
||||||
mock_begin.side_effect = cinder_exceptions.NotAcceptable(
|
mock_begin.side_effect = openstack_exc.HttpException("not acceptable")
|
||||||
http_client.NOT_ACCEPTABLE)
|
|
||||||
|
|
||||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||||
self.assertRaises(exception.StorageError,
|
self.assertRaises(exception.StorageError,
|
||||||
@ -665,30 +605,30 @@ class TestCinderActions(db_base.DbTestCase):
|
|||||||
connector)
|
connector)
|
||||||
mock_is_attached.assert_called_once_with(mock.ANY, volume)
|
mock_is_attached.assert_called_once_with(mock.ANY, volume)
|
||||||
cinder.detach_volumes(task, volumes, connector, allow_errors=True)
|
cinder.detach_volumes(task, volumes, connector, allow_errors=True)
|
||||||
mock_term.assert_called_once_with(mock.ANY, volume_id,
|
mock_term.assert_called_once_with(volume,
|
||||||
{'foo': 'bar'})
|
{'foo': 'bar'})
|
||||||
mock_detach.assert_called_once_with(mock.ANY, volume_id, None)
|
mock_detach.assert_called_once_with(volume, None)
|
||||||
mock_set_meta.assert_called_once_with(mock.ANY, volume_id,
|
mock_set_meta.assert_called_once_with(volume, bar='baz')
|
||||||
{'bar': 'baz'})
|
|
||||||
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager,
|
|
||||||
'terminate_connection', autospec=True)
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager, 'begin_detaching',
|
|
||||||
autospec=True)
|
|
||||||
@mock.patch.object(cinder, 'is_volume_attached', autospec=True)
|
@mock.patch.object(cinder, 'is_volume_attached', autospec=True)
|
||||||
@mock.patch.object(cinder, '_create_metadata_dictionary', autospec=True)
|
@mock.patch.object(cinder, '_create_metadata_dictionary', autospec=True)
|
||||||
def test_detach_volumes_term_failure(
|
def test_detach_volumes_term_failure(
|
||||||
self, mock_create_meta, mock_is_attached, mock_begin, mock_term,
|
self, mock_create_meta, mock_is_attached, mock_client):
|
||||||
mock_get, mock_set_meta, mock_session):
|
|
||||||
|
|
||||||
volume_id = '111111111-0000-0000-0000-000000000003'
|
volume_id = '111111111-0000-0000-0000-000000000003'
|
||||||
volumes = [volume_id]
|
volumes = [volume_id]
|
||||||
connector = {'foo': 'bar'}
|
connector = {'foo': 'bar'}
|
||||||
mock_create_meta.return_value = {'bar': 'baz'}
|
mock_create_meta.return_value = {'bar': 'baz'}
|
||||||
mock_is_attached.return_value = True
|
mock_is_attached.return_value = True
|
||||||
mock_get.return_value = {'id': volume_id, 'attachments': []}
|
mock_bs = mock_client.return_value
|
||||||
mock_term.side_effect = cinder_exceptions.NotAcceptable(
|
mock_get = mock_bs.get_volume
|
||||||
http_client.NOT_ACCEPTABLE)
|
mock_begin = mock_bs.begin_volume_detaching
|
||||||
|
mock_term = mock_bs.terminate_volume_attachment
|
||||||
|
mock_set_meta = mock_bs.set_volume_metadata
|
||||||
|
|
||||||
|
volume = mock.Mock(id=volume_id, attachments=[])
|
||||||
|
mock_get.return_value = volume
|
||||||
|
mock_term.side_effect = openstack_exc.HttpException("not acceptable")
|
||||||
|
|
||||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||||
self.assertRaises(exception.StorageError,
|
self.assertRaises(exception.StorageError,
|
||||||
@ -696,32 +636,30 @@ class TestCinderActions(db_base.DbTestCase):
|
|||||||
task,
|
task,
|
||||||
volumes,
|
volumes,
|
||||||
connector)
|
connector)
|
||||||
mock_begin.assert_called_once_with(mock.ANY, volume_id)
|
mock_begin.assert_called_once_with(volume)
|
||||||
mock_term.assert_called_once_with(mock.ANY, volume_id, connector)
|
mock_term.assert_called_once_with(volume, connector)
|
||||||
cinder.detach_volumes(task, volumes, connector, allow_errors=True)
|
cinder.detach_volumes(task, volumes, connector, allow_errors=True)
|
||||||
self.assertFalse(mock_set_meta.called)
|
self.assertFalse(mock_set_meta.called)
|
||||||
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager, 'detach',
|
|
||||||
autospec=True)
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager,
|
|
||||||
'terminate_connection', autospec=True)
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager, 'begin_detaching',
|
|
||||||
autospec=True)
|
|
||||||
@mock.patch.object(cinder, 'is_volume_attached', autospec=True)
|
@mock.patch.object(cinder, 'is_volume_attached', autospec=True)
|
||||||
@mock.patch.object(cinder, '_create_metadata_dictionary', autospec=True)
|
@mock.patch.object(cinder, '_create_metadata_dictionary', autospec=True)
|
||||||
def test_detach_volumes_detach_failure_errors_not_allowed(
|
def test_detach_volumes_detach_failure_errors_not_allowed(
|
||||||
self, mock_create_meta, mock_is_attached, mock_begin, mock_term,
|
self, mock_create_meta, mock_is_attached, mock_client):
|
||||||
mock_detach, mock_get, mock_set_meta, mock_session):
|
|
||||||
|
|
||||||
volume_id = '111111111-0000-0000-0000-000000000003'
|
volume_id = '111111111-0000-0000-0000-000000000003'
|
||||||
volumes = [volume_id]
|
volumes = [volume_id]
|
||||||
connector = {'foo': 'bar'}
|
connector = {'foo': 'bar'}
|
||||||
mock_create_meta.return_value = {'bar': 'baz'}
|
mock_create_meta.return_value = {'bar': 'baz'}
|
||||||
mock_is_attached.return_value = True
|
mock_is_attached.return_value = True
|
||||||
mock_get.return_value = mock.Mock(attachments=[
|
mock_bs = mock_client.return_value
|
||||||
|
mock_get = mock_bs.get_volume
|
||||||
|
mock_detach = mock_bs.detach_volume
|
||||||
|
mock_set_meta = mock_bs.set_volume_metadata
|
||||||
|
|
||||||
|
volume = mock.Mock(attachments=[
|
||||||
{'server_id': self.node.uuid, 'attachment_id': 'qux'}])
|
{'server_id': self.node.uuid, 'attachment_id': 'qux'}])
|
||||||
mock_detach.side_effect = cinder_exceptions.NotAcceptable(
|
mock_get.return_value = volume
|
||||||
http_client.NOT_ACCEPTABLE)
|
mock_detach.side_effect = openstack_exc.HttpException("not acceptable")
|
||||||
|
|
||||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||||
self.assertRaises(exception.StorageError,
|
self.assertRaises(exception.StorageError,
|
||||||
@ -730,61 +668,55 @@ class TestCinderActions(db_base.DbTestCase):
|
|||||||
volumes,
|
volumes,
|
||||||
connector,
|
connector,
|
||||||
allow_errors=False)
|
allow_errors=False)
|
||||||
mock_detach.assert_called_once_with(mock.ANY, volume_id, 'qux')
|
mock_detach.assert_called_once_with(volume, 'qux')
|
||||||
self.assertFalse(mock_set_meta.called)
|
self.assertFalse(mock_set_meta.called)
|
||||||
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager, 'detach',
|
|
||||||
autospec=True)
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager,
|
|
||||||
'terminate_connection', autospec=True)
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager, 'begin_detaching',
|
|
||||||
autospec=True)
|
|
||||||
@mock.patch.object(cinder, 'is_volume_attached', autospec=True)
|
@mock.patch.object(cinder, 'is_volume_attached', autospec=True)
|
||||||
@mock.patch.object(cinder, '_create_metadata_dictionary', autospec=True)
|
@mock.patch.object(cinder, '_create_metadata_dictionary', autospec=True)
|
||||||
def test_detach_volumes_detach_failure_errors_allowed(
|
def test_detach_volumes_detach_failure_errors_allowed(
|
||||||
self, mock_create_meta, mock_is_attached, mock_begin, mock_term,
|
self, mock_create_meta, mock_is_attached, mock_client):
|
||||||
mock_detach, mock_get, mock_set_meta, mock_session):
|
|
||||||
|
|
||||||
volume_id = '111111111-0000-0000-0000-000000000003'
|
volume_id = '111111111-0000-0000-0000-000000000003'
|
||||||
volumes = [volume_id]
|
volumes = [volume_id]
|
||||||
connector = {'foo': 'bar'}
|
connector = {'foo': 'bar'}
|
||||||
mock_create_meta.return_value = {'bar': 'baz'}
|
mock_create_meta.return_value = {'bar': 'baz'}
|
||||||
mock_is_attached.return_value = True
|
mock_is_attached.return_value = True
|
||||||
mock_get.return_value = mock.Mock(attachments=[
|
mock_bs = mock_client.return_value
|
||||||
|
mock_get = mock_bs.get_volume
|
||||||
|
mock_detach = mock_bs.detach_volume
|
||||||
|
mock_set_meta = mock_bs.set_volume_metadata
|
||||||
|
|
||||||
|
volume = mock.Mock(attachments=[
|
||||||
{'server_id': self.node.uuid, 'attachment_id': 'qux'}])
|
{'server_id': self.node.uuid, 'attachment_id': 'qux'}])
|
||||||
mock_set_meta.side_effect = cinder_exceptions.NotAcceptable(
|
mock_get.return_value = volume
|
||||||
http_client.NOT_ACCEPTABLE)
|
mock_set_meta.side_effect = openstack_exc.HttpException()
|
||||||
|
|
||||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||||
cinder.detach_volumes(task, volumes, connector, allow_errors=True)
|
cinder.detach_volumes(task, volumes, connector, allow_errors=True)
|
||||||
mock_detach.assert_called_once_with(mock.ANY, volume_id, 'qux')
|
mock_detach.assert_called_once_with(volume, 'qux')
|
||||||
mock_set_meta.assert_called_once_with(mock.ANY, volume_id,
|
mock_set_meta.assert_called_once_with(volume, bar='baz')
|
||||||
{'bar': 'baz'})
|
|
||||||
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager, 'detach',
|
|
||||||
autospec=True)
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager,
|
|
||||||
'terminate_connection', autospec=True)
|
|
||||||
@mock.patch.object(cinderclient.volumes.VolumeManager, 'begin_detaching',
|
|
||||||
autospec=True)
|
|
||||||
@mock.patch.object(cinder, 'is_volume_attached', autospec=True)
|
@mock.patch.object(cinder, 'is_volume_attached', autospec=True)
|
||||||
@mock.patch.object(cinder, '_create_metadata_dictionary', autospec=True)
|
@mock.patch.object(cinder, '_create_metadata_dictionary', autospec=True)
|
||||||
def test_detach_volumes_detach_meta_failure_errors_not_allowed(
|
def test_detach_volumes_detach_meta_failure_errors_not_allowed(
|
||||||
self, mock_create_meta, mock_is_attached, mock_begin, mock_term,
|
self, mock_create_meta, mock_is_attached, mock_client):
|
||||||
mock_detach, mock_get, mock_set_meta, mock_session):
|
|
||||||
|
|
||||||
volume_id = '111111111-0000-0000-0000-000000000003'
|
volume_id = '111111111-0000-0000-0000-000000000003'
|
||||||
volumes = [volume_id]
|
volumes = [volume_id]
|
||||||
connector = {'foo': 'bar'}
|
connector = {'foo': 'bar'}
|
||||||
mock_create_meta.return_value = {'bar': 'baz'}
|
mock_create_meta.return_value = {'bar': 'baz'}
|
||||||
mock_is_attached.return_value = True
|
mock_is_attached.return_value = True
|
||||||
mock_get.return_value = mock.Mock(attachments=[
|
mock_bs = mock_client.return_value
|
||||||
|
mock_get = mock_bs.get_volume
|
||||||
|
mock_detach = mock_bs.detach_volume
|
||||||
|
mock_set_meta = mock_bs.set_volume_metadata
|
||||||
|
|
||||||
|
volume = mock.Mock(attachments=[
|
||||||
{'server_id': self.node.uuid, 'attachment_id': 'qux'}])
|
{'server_id': self.node.uuid, 'attachment_id': 'qux'}])
|
||||||
mock_set_meta.side_effect = cinder_exceptions.NotAcceptable(
|
mock_get.return_value = volume
|
||||||
http_client.NOT_ACCEPTABLE)
|
mock_set_meta.side_effect = openstack_exc.HttpException()
|
||||||
|
|
||||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||||
cinder.detach_volumes(task, volumes, connector, allow_errors=False)
|
cinder.detach_volumes(task, volumes, connector, allow_errors=False)
|
||||||
mock_detach.assert_called_once_with(mock.ANY, volume_id, 'qux')
|
mock_detach.assert_called_once_with(volume, 'qux')
|
||||||
mock_set_meta.assert_called_once_with(mock.ANY, volume_id,
|
mock_set_meta.assert_called_once_with(volume, bar='baz')
|
||||||
{'bar': 'baz'})
|
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
upgrade:
|
||||||
|
- |
|
||||||
|
`python-cinderclient` is no longer a dependency, all OpenStack Cinder
|
||||||
|
operations are now done using `openstacksdk`.
|
@ -8,7 +8,6 @@ alembic>=1.4.2 # MIT
|
|||||||
automaton>=1.9.0 # Apache-2.0
|
automaton>=1.9.0 # Apache-2.0
|
||||||
eventlet>=0.30.1 # MIT
|
eventlet>=0.30.1 # MIT
|
||||||
WebOb>=1.7.1 # MIT
|
WebOb>=1.7.1 # MIT
|
||||||
python-cinderclient>=3.3.0 # Apache-2.0
|
|
||||||
keystoneauth1>=4.2.0 # Apache-2.0
|
keystoneauth1>=4.2.0 # Apache-2.0
|
||||||
ironic-lib>=6.0.0 # Apache-2.0
|
ironic-lib>=6.0.0 # Apache-2.0
|
||||||
stevedore>=1.29.0 # Apache-2.0
|
stevedore>=1.29.0 # Apache-2.0
|
||||||
@ -41,7 +40,7 @@ jsonschema>=4.0.0 # MIT
|
|||||||
psutil>=3.2.2 # BSD
|
psutil>=3.2.2 # BSD
|
||||||
futurist>=1.2.0 # Apache-2.0
|
futurist>=1.2.0 # Apache-2.0
|
||||||
tooz>=2.7.0 # Apache-2.0
|
tooz>=2.7.0 # Apache-2.0
|
||||||
openstacksdk>=0.48.0 # Apache-2.0
|
openstacksdk>=0.99.0 # Apache-2.0
|
||||||
sushy>=4.8.0
|
sushy>=4.8.0
|
||||||
construct>=2.9.39 # MIT
|
construct>=2.9.39 # MIT
|
||||||
netaddr>=0.9.0 # BSD
|
netaddr>=0.9.0 # BSD
|
||||||
|
Loading…
Reference in New Issue
Block a user