Skip to content

Commit f260f12

Browse files
committed
Drop pre-cinder 3.44 version compatibility
The new style volume attach flow semantics, which were needed to support multiattach volumes, relies on cinder v3.44 and was added in Queens: Ifc01dbf98545104c998ab96f65ff8623a6db0f28 Now that we're in Train, let's require Cinder API to be at least running Queens level code and drop the compat checks for queens level nova-compute code and Cinder API older than Queens. Lots of old style attachment test code is dropped as a result since we don't need the version boundary handling in the API code. The way a lot of the "new flow" tests were written were as copies of existing tests modified for the new flow so the old flow tests could just be dropped later, and that's what happens in this change. Change-Id: I6a777b4b7a5729488f939df8c40e49bd40aec3dd
1 parent be1e0b9 commit f260f12

File tree

13 files changed

+74
-1034
lines changed

13 files changed

+74
-1034
lines changed

nova/compute/api.py

Lines changed: 19 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@
103103
AGGREGATE_ACTION_UPDATE_META = 'UpdateMeta'
104104
AGGREGATE_ACTION_DELETE = 'Delete'
105105
AGGREGATE_ACTION_ADD = 'Add'
106-
CINDER_V3_ATTACH_MIN_COMPUTE_VERSION = 24
107106
MIN_COMPUTE_TRUSTED_CERTS = 31
108107
MIN_COMPUTE_ABORT_QUEUED_LIVE_MIGRATION = 34
109108
MIN_COMPUTE_VOLUME_TYPE = 36
@@ -4026,46 +4025,17 @@ def _check_attach_and_reserve_volume(self, context, volume, instance,
40264025
if volume['multiattach'] and not supports_multiattach:
40274026
raise exception.MultiattachNotSupportedOldMicroversion()
40284027

4029-
if 'id' in instance:
4030-
# This is a volume attach to an existing instance, so
4031-
# we only care about the cell the instance is in.
4032-
min_compute_version = objects.Service.get_minimum_version(
4033-
context, 'nova-compute')
4034-
else:
4035-
# The instance is being created and we don't know which
4036-
# cell it's going to land in, so check all cells.
4037-
# NOTE(danms): We don't require all cells to report here since
4038-
# we're really concerned about the new-ness of cells that the
4039-
# instance may be scheduled into. If a cell doesn't respond here,
4040-
# then it won't be a candidate for the instance and thus doesn't
4041-
# matter.
4042-
min_compute_version = \
4043-
objects.service.get_minimum_version_all_cells(
4044-
context, ['nova-compute'])
4045-
4046-
if min_compute_version >= CINDER_V3_ATTACH_MIN_COMPUTE_VERSION:
4047-
# Attempt a new style volume attachment, but fallback to old-style
4048-
# in case Cinder API 3.44 isn't available.
4049-
try:
4050-
attachment_id = self.volume_api.attachment_create(
4051-
context, volume_id, instance.uuid)['id']
4052-
bdm.attachment_id = attachment_id
4053-
# NOTE(ildikov): In case of boot from volume the BDM at this
4054-
# point is not yet created in a cell database, so we can't
4055-
# call save(). When attaching a volume to an existing
4056-
# instance, the instance is already in a cell and the BDM has
4057-
# been created in that same cell so updating here in that case
4058-
# is "ok".
4059-
if bdm.obj_attr_is_set('id'):
4060-
bdm.save()
4061-
except exception.CinderAPIVersionNotAvailable:
4062-
LOG.debug('The available Cinder microversion is not high '
4063-
'enough to create new style volume attachment.')
4064-
self.volume_api.reserve_volume(context, volume_id)
4065-
else:
4066-
LOG.debug('The compute service version is not high enough to '
4067-
'create a new style volume attachment.')
4068-
self.volume_api.reserve_volume(context, volume_id)
4028+
attachment_id = self.volume_api.attachment_create(
4029+
context, volume_id, instance.uuid)['id']
4030+
bdm.attachment_id = attachment_id
4031+
# NOTE(ildikov): In case of boot from volume the BDM at this
4032+
# point is not yet created in a cell database, so we can't
4033+
# call save(). When attaching a volume to an existing
4034+
# instance, the instance is already in a cell and the BDM has
4035+
# been created in that same cell so updating here in that case
4036+
# is "ok".
4037+
if bdm.obj_attr_is_set('id'):
4038+
bdm.save()
40694039

40704040
# TODO(stephenfin): Fold this back in now that cells v1 no longer needs to
40714041
# override it.
@@ -4155,27 +4125,14 @@ def attach_volume(self, context, instance, volume_id, device=None,
41554125
if device and not block_device.match_device(device):
41564126
raise exception.InvalidDevicePath(path=device)
41574127

4158-
# Check to see if the computes in this cell can support new-style
4159-
# volume attachments.
4160-
min_compute_version = objects.Service.get_minimum_version(
4161-
context, 'nova-compute')
4162-
if min_compute_version >= CINDER_V3_ATTACH_MIN_COMPUTE_VERSION:
4163-
try:
4164-
# Check to see if Cinder is new enough to create new-style
4165-
# attachments.
4166-
cinder.is_microversion_supported(context, '3.44')
4167-
except exception.CinderAPIVersionNotAvailable:
4168-
pass
4169-
else:
4170-
# Make sure the volume isn't already attached to this instance
4171-
# because based on the above checks, we'll use the new style
4172-
# attachment flow in _check_attach_and_reserve_volume and
4173-
# Cinder will allow multiple attachments between the same
4174-
# volume and instance but the old flow API semantics don't
4175-
# allow that so we enforce it here.
4176-
self._check_volume_already_attached_to_instance(context,
4177-
instance,
4178-
volume_id)
4128+
# Make sure the volume isn't already attached to this instance
4129+
# because we'll use the v3.44 attachment flow in
4130+
# _check_attach_and_reserve_volume and Cinder will allow multiple
4131+
# attachments between the same volume and instance but the old flow
4132+
# API semantics don't allow that so we enforce it here.
4133+
self._check_volume_already_attached_to_instance(context,
4134+
instance,
4135+
volume_id)
41794136

41804137
volume = self.volume_api.get(context, volume_id)
41814138
is_shelved_offloaded = instance.vm_state == vm_states.SHELVED_OFFLOADED

nova/tests/fixtures.py

Lines changed: 8 additions & 192 deletions
Original file line numberDiff line numberDiff line change
@@ -1636,191 +1636,7 @@ def setUp(self):
16361636
lambda *args, **kwargs: mock.MagicMock()))
16371637

16381638

1639-
class CinderFixture(fixtures.Fixture):
1640-
"""A fixture to volume operations"""
1641-
1642-
# the default project_id in OSAPIFixtures
1643-
tenant_id = '6f70656e737461636b20342065766572'
1644-
1645-
SWAP_OLD_VOL = 'a07f71dc-8151-4e7d-a0cc-cd24a3f11113'
1646-
SWAP_NEW_VOL = '227cc671-f30b-4488-96fd-7d0bf13648d8'
1647-
SWAP_ERR_OLD_VOL = '828419fa-3efb-4533-b458-4267ca5fe9b1'
1648-
SWAP_ERR_NEW_VOL = '9c6d9c2d-7a8f-4c80-938d-3bf062b8d489'
1649-
1650-
# This represents a bootable image-backed volume to test
1651-
# boot-from-volume scenarios.
1652-
IMAGE_BACKED_VOL = '6ca404f3-d844-4169-bb96-bc792f37de98'
1653-
1654-
def __init__(self, test):
1655-
super(CinderFixture, self).__init__()
1656-
self.test = test
1657-
self.swap_volume_instance_uuid = None
1658-
self.swap_volume_instance_error_uuid = None
1659-
self.reserved_volumes = list()
1660-
# This is a map of instance UUIDs mapped to a list of volume IDs.
1661-
# This map gets updated on attach/detach operations.
1662-
self.attachments = collections.defaultdict(list)
1663-
1664-
def volume_ids_for_instance(self, instance_uuid):
1665-
return self.attachments.get(instance_uuid)
1666-
1667-
def setUp(self):
1668-
super(CinderFixture, self).setUp()
1669-
1670-
def fake_get(self_api, context, volume_id, microversion=None):
1671-
# Check for the special swap volumes.
1672-
if volume_id in (CinderFixture.SWAP_OLD_VOL,
1673-
CinderFixture.SWAP_ERR_OLD_VOL):
1674-
volume = {
1675-
'status': 'available',
1676-
'display_name': 'TEST1',
1677-
'attach_status': 'detached',
1678-
'id': volume_id,
1679-
'multiattach': False,
1680-
'size': 1
1681-
}
1682-
if ((self.swap_volume_instance_uuid and
1683-
volume_id == CinderFixture.SWAP_OLD_VOL) or
1684-
(self.swap_volume_instance_error_uuid and
1685-
volume_id == CinderFixture.SWAP_ERR_OLD_VOL)):
1686-
instance_uuid = (self.swap_volume_instance_uuid
1687-
if volume_id == CinderFixture.SWAP_OLD_VOL
1688-
else self.swap_volume_instance_error_uuid)
1689-
1690-
volume.update({
1691-
'status': 'in-use',
1692-
'attachments': {
1693-
instance_uuid: {
1694-
'mountpoint': '/dev/vdb',
1695-
'attachment_id': volume_id
1696-
}
1697-
},
1698-
'attach_status': 'attached'
1699-
})
1700-
return volume
1701-
1702-
# Check to see if the volume is attached.
1703-
for instance_uuid, volumes in self.attachments.items():
1704-
if volume_id in volumes:
1705-
# The volume is attached.
1706-
volume = {
1707-
'status': 'in-use',
1708-
'display_name': volume_id,
1709-
'attach_status': 'attached',
1710-
'id': volume_id,
1711-
'multiattach': False,
1712-
'size': 1,
1713-
'attachments': {
1714-
instance_uuid: {
1715-
'attachment_id': volume_id,
1716-
'mountpoint': '/dev/vdb'
1717-
}
1718-
}
1719-
}
1720-
break
1721-
else:
1722-
# This is a test that does not care about the actual details.
1723-
reserved_volume = (volume_id in self.reserved_volumes)
1724-
volume = {
1725-
'status': 'attaching' if reserved_volume else 'available',
1726-
'display_name': 'TEST2',
1727-
'attach_status': 'detached',
1728-
'id': volume_id,
1729-
'multiattach': False,
1730-
'size': 1
1731-
}
1732-
1733-
# Check for our special image-backed volume.
1734-
if volume_id == self.IMAGE_BACKED_VOL:
1735-
# Make it a bootable volume.
1736-
volume['bootable'] = True
1737-
# Add the image_id metadata.
1738-
volume['volume_image_metadata'] = {
1739-
# There would normally be more image metadata in here...
1740-
'image_id': '155d900f-4e14-4e4c-a73d-069cbf4541e6'
1741-
}
1742-
1743-
return volume
1744-
1745-
def fake_initialize_connection(self, context, volume_id, connector):
1746-
if volume_id == CinderFixture.SWAP_ERR_NEW_VOL:
1747-
# Return a tuple in order to raise an exception.
1748-
return ()
1749-
return {}
1750-
1751-
def fake_migrate_volume_completion(self, context, old_volume_id,
1752-
new_volume_id, error):
1753-
return {'save_volume_id': new_volume_id}
1754-
1755-
def fake_reserve_volume(self_api, context, volume_id):
1756-
self.reserved_volumes.append(volume_id)
1757-
1758-
def fake_unreserve_volume(self_api, context, volume_id):
1759-
# NOTE(mnaser): It's possible that we unreserve a volume that was
1760-
# never reserved (ex: instance.volume_attach.error
1761-
# notification tests)
1762-
if volume_id in self.reserved_volumes:
1763-
self.reserved_volumes.remove(volume_id)
1764-
1765-
def fake_attach(_self, context, volume_id, instance_uuid,
1766-
mountpoint, mode='rw'):
1767-
# Check to see if the volume is already attached to any server.
1768-
for instance, volumes in self.attachments.items():
1769-
if volume_id in volumes:
1770-
raise exception.InvalidInput(
1771-
reason='Volume %s is already attached to '
1772-
'instance %s' % (volume_id, instance))
1773-
# It's not attached so let's "attach" it.
1774-
self.attachments[instance_uuid].append(volume_id)
1775-
1776-
self.test.stub_out('nova.volume.cinder.API.attach',
1777-
fake_attach)
1778-
1779-
def fake_detach(_self, context, volume_id, instance_uuid=None,
1780-
attachment_id=None):
1781-
# NOTE(mnaser): It's possible that we unreserve a volume that was
1782-
# never reserved (ex: instance.volume_attach.error
1783-
# notification tests)
1784-
if volume_id in self.reserved_volumes:
1785-
self.reserved_volumes.remove(volume_id)
1786-
1787-
if instance_uuid is not None:
1788-
# If the volume isn't attached to this instance it will
1789-
# result in a ValueError which indicates a broken test or
1790-
# code, so we just let that raise up.
1791-
self.attachments[instance_uuid].remove(volume_id)
1792-
else:
1793-
for instance, volumes in self.attachments.items():
1794-
if volume_id in volumes:
1795-
volumes.remove(volume_id)
1796-
break
1797-
1798-
self.test.stub_out('nova.volume.cinder.API.detach', fake_detach)
1799-
1800-
self.test.stub_out('nova.volume.cinder.API.begin_detaching',
1801-
lambda *args, **kwargs: None)
1802-
self.test.stub_out('nova.volume.cinder.API.get',
1803-
fake_get)
1804-
self.test.stub_out('nova.volume.cinder.API.initialize_connection',
1805-
fake_initialize_connection)
1806-
self.test.stub_out(
1807-
'nova.volume.cinder.API.migrate_volume_completion',
1808-
fake_migrate_volume_completion)
1809-
self.test.stub_out('nova.volume.cinder.API.reserve_volume',
1810-
fake_reserve_volume)
1811-
self.test.stub_out('nova.volume.cinder.API.roll_detaching',
1812-
lambda *args, **kwargs: None)
1813-
self.test.stub_out('nova.volume.cinder.API.terminate_connection',
1814-
lambda *args, **kwargs: None)
1815-
self.test.stub_out('nova.volume.cinder.API.unreserve_volume',
1816-
fake_unreserve_volume)
1817-
self.test.stub_out('nova.volume.cinder.API.check_attached',
1818-
lambda *args, **kwargs: None)
1819-
1820-
1821-
# TODO(mriedem): We can probably pull some of the common parts from the
1822-
# CinderFixture into a common mixin class for things like the variables
1823-
# and fake_get.
1639+
# TODO(mriedem): Just rename this to be CinderFixture.
18241640
class CinderFixtureNewAttachFlow(fixtures.Fixture):
18251641
"""A fixture to volume operations with the new Cinder attach/detach API"""
18261642

@@ -1874,8 +1690,8 @@ def fake_get(self_api, context, volume_id, microversion=None):
18741690
# Check for the special swap volumes.
18751691
attachments = self.volume_to_attachment[volume_id]
18761692

1877-
if volume_id in (CinderFixture.SWAP_OLD_VOL,
1878-
CinderFixture.SWAP_ERR_OLD_VOL):
1693+
if volume_id in (self.SWAP_OLD_VOL,
1694+
self.SWAP_ERR_OLD_VOL):
18791695
volume = {
18801696
'status': 'available',
18811697
'display_name': 'TEST1',
@@ -1885,11 +1701,11 @@ def fake_get(self_api, context, volume_id, microversion=None):
18851701
'size': 1
18861702
}
18871703
if ((self.swap_volume_instance_uuid and
1888-
volume_id == CinderFixture.SWAP_OLD_VOL) or
1704+
volume_id == self.SWAP_OLD_VOL) or
18891705
(self.swap_volume_instance_error_uuid and
1890-
volume_id == CinderFixture.SWAP_ERR_OLD_VOL)):
1706+
volume_id == self.SWAP_ERR_OLD_VOL)):
18911707
instance_uuid = (self.swap_volume_instance_uuid
1892-
if volume_id == CinderFixture.SWAP_OLD_VOL
1708+
if volume_id == self.SWAP_OLD_VOL
18931709
else self.swap_volume_instance_error_uuid)
18941710

18951711
if attachments:
@@ -1956,7 +1772,7 @@ def fake_get(self_api, context, volume_id, microversion=None):
19561772

19571773
return volume
19581774

1959-
def fake_migrate_volume_completion(self, context, old_volume_id,
1775+
def fake_migrate_volume_completion(_self, context, old_volume_id,
19601776
new_volume_id, error):
19611777
return {'save_volume_id': new_volume_id}
19621778

@@ -2021,7 +1837,7 @@ def fake_attachment_update(_self, context, attachment_id, connector,
20211837
'connection_info': {'data':
20221838
{'foo': 'bar',
20231839
'target_lun': '1'}}}
2024-
if attachment_id == CinderFixtureNewAttachFlow.SWAP_ERR_ATTACH_ID:
1840+
if attachment_id == self.SWAP_ERR_ATTACH_ID:
20251841
# This intentionally triggers a TypeError for the
20261842
# instance.volume_swap.error versioned notification tests.
20271843
attachment_ref = {'connection_info': ()}

nova/tests/functional/api_sample_tests/test_volumes.py

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
from oslo_utils.fixture import uuidsentinel as uuids
1919

20-
from nova.compute import api as compute_api
2120
from nova import context
2221
from nova import objects
2322
from nova.tests import fixtures
@@ -28,10 +27,6 @@
2827
from nova.tests.unit import fake_instance
2928

3029

31-
COMPUTE_VERSION_OLD_ATTACH_FLOW = \
32-
compute_api.CINDER_V3_ATTACH_MIN_COMPUTE_VERSION - 1
33-
34-
3530
class SnapshotsSampleJsonTests(api_sample_base.ApiSampleTestBaseV21):
3631
sample_dir = "os-volumes"
3732

@@ -263,11 +258,9 @@ def _get_vol_attachment_subs(self, subs):
263258
return subs
264259

265260
def test_attach_volume_to_server(self):
266-
self.stub_out('nova.objects.Service.get_minimum_version',
267-
lambda *a, **k: COMPUTE_VERSION_OLD_ATTACH_FLOW)
268261
self.stub_out('nova.volume.cinder.API.get', fakes.stub_volume_get)
269-
self.stub_out('nova.volume.cinder.API.reserve_volume',
270-
lambda *a, **k: None)
262+
self.stub_out('nova.volume.cinder.API.attachment_create',
263+
lambda *a, **k: {'id': uuids.attachment_id})
271264
device_name = '/dev/vdd'
272265
bdm = objects.BlockDeviceMapping()
273266
bdm['device_name'] = device_name
@@ -294,8 +287,6 @@ def test_attach_volume_to_server(self):
294287
response, 200)
295288

296289
def test_attach_volume_to_server_new_flow(self):
297-
self.stub_out('nova.volume.cinder.is_microversion_supported',
298-
lambda *a, **k: None)
299290
self.stub_out('nova.volume.cinder.API.get', fakes.stub_volume_get)
300291
self.stub_out('nova.volume.cinder.API.attachment_create',
301292
lambda *a, **k: {'id': uuids.volume})

0 commit comments

Comments
 (0)