Skip to content

Commit 6f8decf

Browse files
auniyal61Elod Illes
authored andcommitted
Update Nova bdm with updated swap info
This change updates bdm for swap in finish_resize and revert_resize functionality. Change also adds supporting: - unit and functional tests - docs: releasenote Closes-Bug: #1552777 Change-Id: Ic8aaa0728a43936cd4c6e1ed590e01ba8f0fbf5b (cherry picked from commit 15dccae) (cherry picked from commit 3d3ada4) (cherry picked from commit 39714c2) Signed-off-by: Elod Illes <[email protected]>
1 parent 0d055b4 commit 6f8decf

File tree

4 files changed

+242
-4
lines changed

4 files changed

+242
-4
lines changed

nova/compute/manager.py

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4990,6 +4990,50 @@ def _delete_volume_attachments(self, ctxt, bdms):
49904990
'Error: %s', bdm.attachment_id, str(e),
49914991
instance_uuid=bdm.instance_uuid)
49924992

4993+
def _update_bdm_for_swap_to_finish_resize(
4994+
self, context, instance, confirm=True):
4995+
"""This updates bdm.swap with new swap info"""
4996+
4997+
bdms = instance.get_bdms()
4998+
if not (instance.old_flavor and instance.new_flavor):
4999+
return bdms
5000+
5001+
if instance.old_flavor.swap == instance.new_flavor.swap:
5002+
return bdms
5003+
5004+
old_swap = instance.old_flavor.swap
5005+
new_swap = instance.new_flavor.swap
5006+
if not confirm:
5007+
# revert flavor on _finish_revert_resize
5008+
old_swap = instance.new_flavor.swap
5009+
new_swap = instance.old_flavor.swap
5010+
5011+
# add swap
5012+
if old_swap == 0 and new_swap:
5013+
# (auniyal)old_swap = 0 means we did not have swap bdm
5014+
# for this instance.
5015+
# and as there is a new_swap, its a swap addition
5016+
new_swap_bdm = block_device.create_blank_bdm(new_swap, 'swap')
5017+
bdm_obj = objects.BlockDeviceMapping(
5018+
context, instance_uuid=instance.uuid, **new_swap_bdm)
5019+
bdm_obj.update_or_create()
5020+
return instance.get_bdms()
5021+
5022+
# update swap
5023+
for bdm in bdms:
5024+
if bdm.guest_format == 'swap' and bdm.device_type == 'disk':
5025+
if new_swap > 0:
5026+
LOG.info('Adding swap BDM.', instance=instance)
5027+
bdm.volume_size = new_swap
5028+
bdm.save()
5029+
break
5030+
elif new_swap == 0:
5031+
LOG.info('Deleting swap BDM.', instance=instance)
5032+
bdm.destroy()
5033+
bdms.objects.remove(bdm)
5034+
break
5035+
return bdms
5036+
49935037
@wrap_exception()
49945038
@reverts_task_state
49955039
@wrap_instance_event(prefix='compute')
@@ -5327,8 +5371,9 @@ def _finish_revert_resize(
53275371
):
53285372
"""Inner version of finish_revert_resize."""
53295373
with self._error_out_instance_on_exception(context, instance):
5330-
bdms = objects.BlockDeviceMappingList.get_by_instance_uuid(
5331-
context, instance.uuid)
5374+
bdms = self._update_bdm_for_swap_to_finish_resize(
5375+
context, instance, confirm=False)
5376+
53325377
self._notify_about_instance_usage(
53335378
context, instance, "resize.revert.start")
53345379
compute_utils.notify_about_instance_action(context, instance,
@@ -6265,8 +6310,7 @@ def _finish_resize_helper(self, context, disk_info, image, instance,
62656310
The caller must revert the instance's allocations if the migration
62666311
process failed.
62676312
"""
6268-
bdms = objects.BlockDeviceMappingList.get_by_instance_uuid(
6269-
context, instance.uuid)
6313+
bdms = self._update_bdm_for_swap_to_finish_resize(context, instance)
62706314

62716315
with self._error_out_instance_on_exception(context, instance):
62726316
image_meta = objects.ImageMeta.from_dict(image)

nova/tests/functional/test_servers.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3207,6 +3207,73 @@ def test_finish_resize_fails_allocation_cleanup(self):
32073207
self._test_resize_to_same_host_instance_fails(
32083208
'_finish_resize', 'compute_finish_resize')
32093209

3210+
def _verify_swap_resize_in_bdm(self, server_id, swap_size):
3211+
"""Verify swap dev in BDM"""
3212+
ctxt = context.get_admin_context()
3213+
bdms = objects.BlockDeviceMappingList.get_by_instance_uuid(
3214+
ctxt, server_id)
3215+
if swap_size != 0:
3216+
self.assertIn('swap', [bdm.guest_format for bdm in bdms])
3217+
swaps = [
3218+
bdm.volume_size for bdm in bdms if bdm.guest_format == 'swap']
3219+
self.assertEqual(len(swaps), 1)
3220+
self.assertIn(swap_size, swaps)
3221+
else:
3222+
self.assertNotIn('swap', [bdm.guest_format for bdm in bdms])
3223+
3224+
def _test_swap_resize(self, swap1, swap2, confirm=True):
3225+
fl_1 = self._create_flavor(swap=swap1)
3226+
fl_2 = self._create_flavor(swap=swap2)
3227+
server = self._create_server(flavor_id=fl_1, networks=[])
3228+
# before resize
3229+
self.assertEqual(server['flavor']['swap'], swap1)
3230+
server = self._resize_server(server, fl_2)
3231+
self.assertEqual(server['flavor']['swap'], swap2)
3232+
self._verify_swap_resize_in_bdm(server['id'], swap2)
3233+
3234+
if confirm:
3235+
server = self._confirm_resize(server)
3236+
# after resize
3237+
self.assertEqual(server['flavor']['swap'], swap2)
3238+
# verify block device mapping
3239+
self._verify_swap_resize_in_bdm(server['id'], swap2)
3240+
else:
3241+
server = self._revert_resize(server)
3242+
# after revert
3243+
self.assertEqual(server['flavor']['swap'], swap1)
3244+
# verify block device mapping
3245+
self._verify_swap_resize_in_bdm(server['id'], swap1)
3246+
3247+
def test_swap_expand_0_to_0_confirm(self):
3248+
self._test_swap_resize(0, 0)
3249+
3250+
def test_swap_expand_0_to_1024_confirm(self):
3251+
self._test_swap_resize(0, 1024)
3252+
3253+
def test_swap_expand_0_to_1024_revert(self):
3254+
self._test_swap_resize(0, 1024, confirm=False)
3255+
3256+
def test_swap_expand_1024_to_2048_confirm(self):
3257+
self._test_swap_resize(1024, 2048)
3258+
3259+
def test_swap_expand_1024_to_2048_revert(self):
3260+
self._test_swap_resize(1024, 2048, confirm=False)
3261+
3262+
def test_swap_expand_2048_to_2048_confirm(self):
3263+
self._test_swap_resize(2048, 2048)
3264+
3265+
def test_swap_shrink_1024_to_0_confirm(self):
3266+
self._test_swap_resize(1024, 0)
3267+
3268+
def test_swap_shrink_1024_to_0_revert(self):
3269+
self._test_swap_resize(1024, 0, confirm=False)
3270+
3271+
def test_swap_shrink_2048_to_1024_confirm(self):
3272+
self._test_swap_resize(2048, 1024)
3273+
3274+
def test_swap_shrink_2048_to_1024_revert(self):
3275+
self._test_swap_resize(2048, 1024, confirm=False)
3276+
32103277
def _server_created_with_host(self):
32113278
hostname = self.compute1.host
32123279
server_req = self._build_server(

nova/tests/unit/compute/test_compute_mgr.py

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13164,3 +13164,120 @@ def test_update_compute_provider_status_unexpected_error(self, m_exc):
1316413164
self.assertIn('An error occurred while updating '
1316513165
'COMPUTE_STATUS_DISABLED trait',
1316613166
m_exc.call_args_list[0][0][0])
13167+
13168+
13169+
class ComputeManagerBDMUpdateTestCase(test.TestCase):
13170+
13171+
def setUp(self):
13172+
super(ComputeManagerBDMUpdateTestCase, self).setUp()
13173+
self.compute = manager.ComputeManager()
13174+
self.context = context.RequestContext(fakes.FAKE_USER_ID,
13175+
fakes.FAKE_PROJECT_ID)
13176+
self.instance = mock.Mock()
13177+
13178+
@mock.patch('nova.block_device.create_blank_bdm')
13179+
@mock.patch('nova.objects.BlockDeviceMapping')
13180+
def test_no_flavor_change(self, mock_bdm_obj, mock_create_bdm):
13181+
self.instance.get_bdms.return_value = []
13182+
self.instance.old_flavor = None
13183+
self.instance.new_flavor = None
13184+
13185+
bdms = self.compute._update_bdm_for_swap_to_finish_resize(
13186+
self.context, self.instance)
13187+
13188+
self.assertEqual(bdms, [])
13189+
self.instance.get_bdms.assert_called_once()
13190+
13191+
@mock.patch('nova.block_device.create_blank_bdm')
13192+
@mock.patch('nova.objects.BlockDeviceMapping.create')
13193+
def test_no_swap_change(self, mock_bdm_obj, mock_create_bdm):
13194+
self.instance.old_flavor = mock.Mock(swap=1024)
13195+
self.instance.new_flavor = mock.Mock(swap=1024)
13196+
13197+
existing_swap_bdm = objects.BlockDeviceMapping(
13198+
guest_format='swap',
13199+
device_type='disk',
13200+
volume_size=1024)
13201+
13202+
bdms = objects.BlockDeviceMappingList(objects=[existing_swap_bdm])
13203+
13204+
self.instance.get_bdms.return_value = bdms
13205+
13206+
new_bdms = self.compute._update_bdm_for_swap_to_finish_resize(
13207+
self.context, self.instance)
13208+
13209+
self.assertEqual(new_bdms, bdms)
13210+
self.instance.get_bdms.assert_called_once()
13211+
13212+
@mock.patch('nova.block_device.create_blank_bdm')
13213+
@mock.patch('nova.objects.BlockDeviceMapping')
13214+
def test_add_new_swap_bdm(self, mock_bdm_obj, mock_create_bdm):
13215+
self.instance.old_flavor = mock.Mock(swap=0)
13216+
self.instance.new_flavor = mock.Mock(swap=1024)
13217+
13218+
self.instance.get_bdms.return_value = []
13219+
13220+
new_swap_bdm = {
13221+
'guest_format': 'swap',
13222+
'device_type': 'disk',
13223+
'volume_size': 1024}
13224+
mock_create_bdm.return_value = new_swap_bdm
13225+
mock_bdm_instance = mock_bdm_obj.return_value
13226+
13227+
self.compute._update_bdm_for_swap_to_finish_resize(
13228+
self.context, self.instance)
13229+
13230+
mock_bdm_obj.assert_called_once_with(
13231+
self.context, instance_uuid=self.instance.uuid, **new_swap_bdm
13232+
)
13233+
mock_bdm_instance.update_or_create.assert_called_once()
13234+
# called twice
13235+
self.assertEqual(self.instance.get_bdms.call_count, 2)
13236+
13237+
@mock.patch('nova.block_device.create_blank_bdm')
13238+
@mock.patch('nova.objects.BlockDeviceMapping.create')
13239+
@mock.patch('nova.objects.BlockDeviceMapping.save')
13240+
def test_update_swap_bdm(
13241+
self, mock_bdm_save, mock_bdm_create,
13242+
mock_create_blank_bdm):
13243+
self.instance.old_flavor = mock.Mock(swap=1024) # Existing swap size
13244+
self.instance.new_flavor = mock.Mock(swap=2048) # New swap size
13245+
13246+
existing_swap_bdm = objects.BlockDeviceMapping(
13247+
guest_format='swap',
13248+
device_type='disk',
13249+
volume_size=1024)
13250+
13251+
bdms = objects.BlockDeviceMappingList(objects=[existing_swap_bdm])
13252+
13253+
self.instance.get_bdms.return_value = bdms
13254+
13255+
self.compute._update_bdm_for_swap_to_finish_resize(
13256+
self.context, self.instance)
13257+
13258+
# assert bdm get saved in DB
13259+
existing_swap_bdm.save.assert_called_once()
13260+
# here we are returning same bdms object, not freh from DB
13261+
self.assertEqual(existing_swap_bdm.volume_size, 2048)
13262+
# get_bdms is called only once
13263+
self.assertEqual(self.instance.get_bdms.call_count, 1)
13264+
13265+
@mock.patch('nova.block_device.create_blank_bdm')
13266+
@mock.patch('nova.objects.BlockDeviceMapping.destroy')
13267+
def test_delete_swap_bdm(self, mock_bdm_destroy, mock_create_bdm):
13268+
self.instance.old_flavor = mock.Mock(swap=1024)
13269+
self.instance.new_flavor = mock.Mock(swap=0)
13270+
13271+
existing_swap_bdm = objects.BlockDeviceMapping(
13272+
guest_format='swap',
13273+
device_type='disk',
13274+
volume_size=1024)
13275+
13276+
self.instance.get_bdms.return_value = objects.BlockDeviceMappingList(
13277+
objects=[existing_swap_bdm])
13278+
13279+
self.compute._update_bdm_for_swap_to_finish_resize(
13280+
self.context, self.instance)
13281+
13282+
mock_bdm_destroy.assert_called_once()
13283+
self.instance.get_bdms.assert_called_once()
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
3+
fixes:
4+
- |
5+
With this change, operators can now resize the instance flavor swap to
6+
a smaller swap size, it can be expand and shrunk down to 0 using the same
7+
resize API.
8+
For more details see: `bug 1552777`_
9+
10+
.. _`bug 1552777`: https://bugs.launchpad.net/nova/+bug/1552777

0 commit comments

Comments
 (0)