From 05554b01d56551f89ff594597196acc2c397832b Mon Sep 17 00:00:00 2001 From: David Shrewsbury Date: Thu, 29 May 2014 11:36:06 -0400 Subject: [PATCH] Set instance default_ephemeral_device Duplicate the old nova-bm logic of setting the default ephemeral device to /dev/sda1 (first partition on the disk) when an ephemeral partition is being used. This is a short-term solution to fix the majority of cases that depend on this value being present in the instance metadata (e.g., cloud-init). Longer term, we should consider using something like udev by-label names (/dev/disk/by-label/NNN) or similar. Closes-Bug: #1324286 Change-Id: Ia85f0fd0bfa5cca0320db0e8c7f1e0e2b61b4ef6 --- ironic/nova/tests/virt/ironic/test_driver.py | 53 ++++++++++++++++---- ironic/nova/virt/ironic/driver.py | 7 +++ 2 files changed, 51 insertions(+), 9 deletions(-) diff --git a/ironic/nova/tests/virt/ironic/test_driver.py b/ironic/nova/tests/virt/ironic/test_driver.py index 3384020c7b..b9102e5c1d 100644 --- a/ironic/nova/tests/virt/ironic/test_driver.py +++ b/ironic/nova/tests/virt/ironic/test_driver.py @@ -426,6 +426,7 @@ class IronicDriverTestCase(test.NoDBTestCase): result = self.driver.macs_for_instance(instance) self.assertEqual([], result) + @mock.patch.object(instance_obj.Instance, 'save') @mock.patch.object(FAKE_CLIENT, 'node') @mock.patch.object(flavor_obj, 'get_by_id') @mock.patch.object(cw.IronicClientWrapper, '_get_client') @@ -433,11 +434,11 @@ class IronicDriverTestCase(test.NoDBTestCase): @mock.patch.object(ironic_driver.IronicDriver, '_plug_vifs') @mock.patch.object(ironic_driver.IronicDriver, '_start_firewall') def test_spawn(self, mock_sf, mock_pvifs, mock_adf, mock_cli, - mock_fg_bid, mock_node): + mock_fg_bid, mock_node, mock_save): node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' node = ironic_utils.get_test_node(driver='fake', uuid=node_uuid) instance = fake_instance.fake_instance_obj(self.ctx, node=node_uuid) - fake_flavor = 'fake-flavor' + fake_flavor = { 'ephemeral_gb': 0 } mock_node.get.return_value = node mock_node.validate.return_value = ironic_utils.get_test_validation() @@ -458,6 +459,9 @@ class IronicDriverTestCase(test.NoDBTestCase): mock_sf.assert_called_once_with(instance, None) mock_node.set_provision_state.assert_called_once_with(node_uuid, 'active') + self.assertIsNone(instance['default_ephemeral_device']) + self.assertFalse(mock_save.called) + @mock.patch.object(cw.IronicClientWrapper, '_get_client') @mock.patch.object(FAKE_CLIENT.node, 'update') def test__add_driver_fields_good(self, mock_update, mock_cli): @@ -513,7 +517,7 @@ class IronicDriverTestCase(test.NoDBTestCase): node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' node = ironic_utils.get_test_node(driver='fake', uuid=node_uuid) instance = fake_instance.fake_instance_obj(self.ctx, node=node_uuid) - fake_flavor = 'fake-flavor' + fake_flavor = { 'ephemeral_gb': 0 } mock_node.validate.return_value = ironic_utils.get_test_validation( power=False, deploy=False) @@ -535,12 +539,14 @@ class IronicDriverTestCase(test.NoDBTestCase): @mock.patch.object(ironic_driver.IronicDriver, '_cleanup_deploy') def test_spawn_node_prepare_for_deploy_fail(self, mock_cleanup_deploy, mock_pvifs, mock_sf, mock_cli, - mock_fg_bid, mock_node): + mock_flavor, mock_node): node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' node = ironic_utils.get_test_node(driver='fake', uuid=node_uuid) instance = fake_instance.fake_instance_obj(self.ctx, node=node_uuid) mock_node.get.return_value = node mock_node.validate.return_value = ironic_utils.get_test_validation() + fake_flavor = { 'ephemeral_gb': 0 } + mock_flavor.return_value = fake_flavor class TestException(Exception): pass @@ -552,7 +558,7 @@ class IronicDriverTestCase(test.NoDBTestCase): mock_node.get.assert_called_once_with(node_uuid) mock_node.validate.assert_called_once_with(node_uuid) - mock_fg_bid.assert_called_once_with(self.ctx, + mock_flavor.assert_called_once_with(self.ctx, instance['instance_type_id']) mock_cleanup_deploy.assert_called_with(node, instance, None) @@ -564,10 +570,12 @@ class IronicDriverTestCase(test.NoDBTestCase): @mock.patch.object(ironic_driver.IronicDriver, '_cleanup_deploy') def test_spawn_node_trigger_deploy_fail(self, mock_cleanup_deploy, mock_pvifs, mock_sf, mock_cli, - mock_fg_bid, mock_node): + mock_flavor, mock_node): node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' node = ironic_utils.get_test_node(driver='fake', uuid=node_uuid) instance = fake_instance.fake_instance_obj(self.ctx, node=node_uuid) + fake_flavor = { 'ephemeral_gb': 0 } + mock_flavor.return_value = fake_flavor mock_node.get.return_value = node mock_node.validate.return_value = ironic_utils.get_test_validation() @@ -579,7 +587,7 @@ class IronicDriverTestCase(test.NoDBTestCase): mock_node.get.assert_called_once_with(node_uuid) mock_node.validate.assert_called_once_with(node_uuid) - mock_fg_bid.assert_called_once_with(self.ctx, + mock_flavor.assert_called_once_with(self.ctx, instance['instance_type_id']) mock_cleanup_deploy.assert_called_once_with(node, instance, None) @@ -591,10 +599,12 @@ class IronicDriverTestCase(test.NoDBTestCase): @mock.patch.object(ironic_driver.IronicDriver, '_cleanup_deploy') def test_spawn_node_trigger_deploy_fail2(self, mock_cleanup_deploy, mock_pvifs, mock_sf, mock_cli, - mock_fg_bid, mock_node): + mock_flavor, mock_node): node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' node = ironic_utils.get_test_node(driver='fake', uuid=node_uuid) instance = fake_instance.fake_instance_obj(self.ctx, node=node_uuid) + fake_flavor = { 'ephemeral_gb': 0 } + mock_flavor.return_value = fake_flavor mock_node.get.return_value = node mock_node.validate.return_value = ironic_utils.get_test_validation() @@ -606,10 +616,35 @@ class IronicDriverTestCase(test.NoDBTestCase): mock_node.get.assert_called_once_with(node_uuid) mock_node.validate.assert_called_once_with(node_uuid) - mock_fg_bid.assert_called_once_with(self.ctx, + mock_flavor.assert_called_once_with(self.ctx, instance['instance_type_id']) mock_cleanup_deploy.assert_called_once_with(node, instance, None) + @mock.patch.object(instance_obj.Instance, 'save') + @mock.patch.object(FAKE_CLIENT, 'node') + @mock.patch.object(flavor_obj, 'get_by_id') + @mock.patch.object(cw.IronicClientWrapper, '_get_client') + @mock.patch.object(ironic_driver.IronicDriver, '_plug_vifs') + @mock.patch.object(ironic_driver.IronicDriver, '_start_firewall') + def test_spawn_sets_default_ephemeral_device(self, mock_sf, mock_pvifs, + mock_cli, mock_flavor, + mock_node, mock_save): + node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' + node = ironic_utils.get_test_node(driver='fake', uuid=node_uuid) + instance = fake_instance.fake_instance_obj(self.ctx, node=node_uuid) + fake_flavor = { 'ephemeral_gb': 1 } + mock_flavor.return_value = fake_flavor + mock_cli.return_value = FAKE_CLIENT + mock_node.get_by_instance_uuid.return_value = node + mock_node.set_provision_state.return_value = mock.MagicMock() + node.provision_state = ironic_states.ACTIVE + + self.driver.spawn(self.ctx, instance, None, [], None) + mock_flavor.assert_called_once_with(self.ctx, + instance['instance_type_id']) + self.assertTrue(mock_save.called) + self.assertEqual('/dev/sda1', instance['default_ephemeral_device']) + @mock.patch.object(cw.IronicClientWrapper, '_get_client') @mock.patch.object(FAKE_CLIENT, 'node') @mock.patch.object(ironic_driver.IronicDriver, '_cleanup_deploy') diff --git a/ironic/nova/virt/ironic/driver.py b/ironic/nova/virt/ironic/driver.py index ce3967e90d..114c785ba3 100644 --- a/ironic/nova/virt/ironic/driver.py +++ b/ironic/nova/virt/ironic/driver.py @@ -405,6 +405,13 @@ class IronicDriver(virt_driver.ComputeDriver): instance['instance_type_id']) self._add_driver_fields(node, instance, image_meta, flavor) + # NOTE(Shrews): The default ephemeral device needs to be set for + # services (like cloud-init) that depend on it being returned by the + # metadata server. Addresses bug https://launchpad.net/bugs/1324286. + if flavor['ephemeral_gb']: + instance.default_ephemeral_device = '/dev/sda1' + instance.save() + #validate we ready to do the deploy validate_chk = icli.call("node.validate", node_uuid) if not validate_chk.deploy or not validate_chk.power: