Merge "Check for outstanding attachments during reserve"
This commit is contained in:
commit
1670e09d78
@ -178,3 +178,73 @@ class AttachmentManagerTestCase(test.TestCase):
|
|||||||
vref = objects.Volume.get_by_id(self.context,
|
vref = objects.Volume.get_by_id(self.context,
|
||||||
vref.id)
|
vref.id)
|
||||||
self.assertEqual(2, len(vref.volume_attachment))
|
self.assertEqual(2, len(vref.volume_attachment))
|
||||||
|
|
||||||
|
@mock.patch('cinder.volume.api.check_policy')
|
||||||
|
@mock.patch('cinder.volume.rpcapi.VolumeAPI.attachment_update')
|
||||||
|
def test_attachment_create_reserve_delete(
|
||||||
|
self,
|
||||||
|
mock_rpc_attachment_update,
|
||||||
|
mock_policy):
|
||||||
|
volume_params = {'status': 'available'}
|
||||||
|
connector = {
|
||||||
|
"initiator": "iqn.1993-08.org.debian:01:cad181614cec",
|
||||||
|
"ip": "192.168.1.20",
|
||||||
|
"platform": "x86_64",
|
||||||
|
"host": "tempest-1",
|
||||||
|
"os_type": "linux2",
|
||||||
|
"multipath": False}
|
||||||
|
|
||||||
|
connection_info = {'fake_key': 'fake_value',
|
||||||
|
'fake_key2': ['fake_value1', 'fake_value2']}
|
||||||
|
mock_rpc_attachment_update.return_value = connection_info
|
||||||
|
|
||||||
|
vref = tests_utils.create_volume(self.context, **volume_params)
|
||||||
|
aref = self.volume_api.attachment_create(self.context,
|
||||||
|
vref,
|
||||||
|
fake.UUID2,
|
||||||
|
connector=connector)
|
||||||
|
vref = objects.Volume.get_by_id(self.context,
|
||||||
|
vref.id)
|
||||||
|
# Need to set the status here because our mock isn't doing it for us
|
||||||
|
vref.status = 'in-use'
|
||||||
|
vref.save()
|
||||||
|
|
||||||
|
# Now a second attachment acting as a reserve
|
||||||
|
self.volume_api.attachment_create(self.context,
|
||||||
|
vref,
|
||||||
|
fake.UUID2)
|
||||||
|
|
||||||
|
# We should now be able to delete the original attachment that gave us
|
||||||
|
# 'in-use' status, and in turn we should revert to the outstanding
|
||||||
|
# attachments reserve
|
||||||
|
self.volume_api.attachment_delete(self.context,
|
||||||
|
aref)
|
||||||
|
vref = objects.Volume.get_by_id(self.context,
|
||||||
|
vref.id)
|
||||||
|
self.assertEqual('reserved', vref.status)
|
||||||
|
|
||||||
|
@mock.patch('cinder.volume.api.check_policy')
|
||||||
|
def test_reserve_reserve_delete(self, mock_policy):
|
||||||
|
"""Test that we keep reserved status across multiple reserves."""
|
||||||
|
volume_params = {'status': 'available'}
|
||||||
|
|
||||||
|
vref = tests_utils.create_volume(self.context, **volume_params)
|
||||||
|
aref = self.volume_api.attachment_create(self.context,
|
||||||
|
vref,
|
||||||
|
fake.UUID2)
|
||||||
|
vref = objects.Volume.get_by_id(self.context,
|
||||||
|
vref.id)
|
||||||
|
self.assertEqual('reserved', vref.status)
|
||||||
|
|
||||||
|
self.volume_api.attachment_create(self.context,
|
||||||
|
vref,
|
||||||
|
fake.UUID2)
|
||||||
|
vref = objects.Volume.get_by_id(self.context,
|
||||||
|
vref.id)
|
||||||
|
self.assertEqual('reserved', vref.status)
|
||||||
|
self.volume_api.attachment_delete(self.context,
|
||||||
|
aref)
|
||||||
|
vref = objects.Volume.get_by_id(self.context,
|
||||||
|
vref.id)
|
||||||
|
self.assertEqual('reserved', vref.status)
|
||||||
|
self.assertEqual(1, len(vref.volume_attachment))
|
||||||
|
@ -2043,19 +2043,37 @@ class API(base.Base):
|
|||||||
self.volume_rpcapi.attachment_delete(ctxt,
|
self.volume_rpcapi.attachment_delete(ctxt,
|
||||||
attachment.id,
|
attachment.id,
|
||||||
volume)
|
volume)
|
||||||
|
status_updates = {'status': 'available',
|
||||||
|
'attach_status': 'detached'}
|
||||||
remaining_attachments = AO_LIST.get_all_by_volume_id(ctxt, volume.id)
|
remaining_attachments = AO_LIST.get_all_by_volume_id(ctxt, volume.id)
|
||||||
|
|
||||||
# TODO(jdg): Make this check attachments_by_volume_id when we
|
# NOTE(jdg) Try and figure out the > state we have left and set that
|
||||||
# implement multi-attach for real
|
# attached > attaching > > detaching > reserved
|
||||||
if len(remaining_attachments) < 1:
|
pending_status_list = []
|
||||||
volume.status = 'available'
|
for attachment in remaining_attachments:
|
||||||
volume.attach_status = 'detached'
|
pending_status_list.append(attachment.attach_status)
|
||||||
|
if 'attached' in pending_status_list:
|
||||||
|
status_updates['status'] = 'in-use'
|
||||||
|
status_updates['attach_status'] = 'attached'
|
||||||
|
elif 'attaching' in pending_status_list:
|
||||||
|
status_updates['status'] = 'attaching'
|
||||||
|
status_updates['attach_status'] = 'attaching'
|
||||||
|
elif 'detaching' in pending_status_list:
|
||||||
|
status_updates['status'] = 'detaching'
|
||||||
|
status_updates['attach_status'] = 'detaching'
|
||||||
|
elif 'reserved' in pending_status_list:
|
||||||
|
status_updates['status'] = 'reserved'
|
||||||
|
status_updates['attach_status'] = 'reserved'
|
||||||
|
|
||||||
|
volume.status = status_updates['status']
|
||||||
|
volume.attach_status = status_updates['attach_status']
|
||||||
volume.save()
|
volume.save()
|
||||||
return remaining_attachments
|
return remaining_attachments
|
||||||
|
|
||||||
|
|
||||||
class HostAPI(base.Base):
|
class HostAPI(base.Base):
|
||||||
"""Sub-set of the Volume Manager API for managing host operations."""
|
"""Sub-set of the Volume Manager API for managing host operations."""
|
||||||
|
|
||||||
def set_host_enabled(self, context, host, enabled):
|
def set_host_enabled(self, context, host, enabled):
|
||||||
"""Sets the specified host's ability to accept new volumes."""
|
"""Sets the specified host's ability to accept new volumes."""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user