# Copyright 2015 IBM Corp. # # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import mock from nova.compute import task_states from nova import exception from nova import test from nova_powervm.virt.powervm.tasks import vm as tf_vm from pypowervm import const as pvmc from taskflow import engines as tf_eng from taskflow.patterns import linear_flow as tf_lf from taskflow import task as tf_tsk class TestVMTasks(test.NoDBTestCase): def setUp(self): super(TestVMTasks, self).setUp() self.apt = mock.Mock() self.instance = mock.Mock(uuid='fake-uuid') @mock.patch('pypowervm.utils.transaction.FeedTask') @mock.patch('pypowervm.tasks.partition.build_active_vio_feed_task') @mock.patch('pypowervm.tasks.storage.add_lpar_storage_scrub_tasks') @mock.patch('nova_powervm.virt.powervm.vm.create_lpar') def test_create(self, mock_vm_crt, mock_stg, mock_bld, mock_ftsk): nvram_mgr = mock.Mock() nvram_mgr.fetch.return_value = 'data' lpar_entry = mock.Mock() # Test create with normal (non-recreate) ftsk crt = tf_vm.Create(self.apt, 'host_wrapper', self.instance, stg_ftsk=mock_ftsk, nvram_mgr=nvram_mgr, slot_mgr='slot_mgr') mock_vm_crt.return_value = lpar_entry crt_entry = crt.execute() mock_ftsk.execute.assert_not_called() mock_vm_crt.assert_called_once_with( self.apt, 'host_wrapper', self.instance, nvram='data', slot_mgr='slot_mgr') self.assertEqual(lpar_entry, crt_entry) nvram_mgr.fetch.assert_called_once_with(self.instance) mock_ftsk.name = 'create_scrubber' mock_bld.return_value = mock_ftsk # Test create with recreate ftsk rcrt = tf_vm.Create(self.apt, 'host_wrapper', self.instance, stg_ftsk=None, nvram_mgr=nvram_mgr, slot_mgr='slot_mgr') mock_bld.assert_called_once_with( self.apt, name='create_scrubber', xag={pvmc.XAG.VIO_SMAP, pvmc.XAG.VIO_FMAP}) rcrt.execute() mock_ftsk.execute.assert_called_once_with() @mock.patch('nova_powervm.virt.powervm.vm.get_pvm_uuid') @mock.patch('nova_powervm.virt.powervm.tasks.vm.Create.execute') @mock.patch('nova_powervm.virt.powervm.vm.delete_lpar') def test_create_revert(self, mock_vm_dlt, mock_crt_exc, mock_get_pvm_uuid): mock_crt_exc.side_effect = exception.NovaException() crt = tf_vm.Create(self.apt, 'host_wrapper', self.instance, 'stg_ftsk', None) # Assert that a failure while building does not revert crt.instance.task_state = task_states.SPAWNING flow_test = tf_lf.Flow("test_revert") flow_test.add(crt) self.assertRaises(exception.NovaException, tf_eng.run, flow_test) mock_vm_dlt.assert_not_called() # Assert that a failure when rebuild results in revert crt.instance.task_state = task_states.REBUILD_SPAWNING flow_test = tf_lf.Flow("test_revert") flow_test.add(crt) self.assertRaises(exception.NovaException, tf_eng.run, flow_test) mock_vm_dlt.assert_called() @mock.patch('nova_powervm.virt.powervm.vm.power_on') def test_power_on(self, mock_pwron): pwron = tf_vm.PowerOn(self.apt, self.instance, pwr_opts='opt') pwron.execute() mock_pwron.assert_called_once_with(self.apt, self.instance, opts='opt') @mock.patch('nova_powervm.virt.powervm.vm.power_on') @mock.patch('nova_powervm.virt.powervm.vm.power_off') def test_power_on_revert(self, mock_pwroff, mock_pwron): flow = tf_lf.Flow('revert_power_on') pwron = tf_vm.PowerOn(self.apt, self.instance, pwr_opts='opt') flow.add(pwron) # Dummy Task that fails, triggering flow revert def failure(*a, **k): raise ValueError() flow.add(tf_tsk.FunctorTask(failure)) # When PowerOn.execute doesn't fail, revert calls power_off self.assertRaises(ValueError, tf_eng.run, flow) mock_pwron.assert_called_once_with(self.apt, self.instance, opts='opt') mock_pwroff.assert_called_once_with(self.apt, self.instance, force_immediate=True) mock_pwron.reset_mock() mock_pwroff.reset_mock() # When PowerOn.execute fails, revert doesn't call power_off mock_pwron.side_effect = exception.NovaException() self.assertRaises(exception.NovaException, tf_eng.run, flow) mock_pwron.assert_called_once_with(self.apt, self.instance, opts='opt') mock_pwroff.assert_not_called() @mock.patch('nova_powervm.virt.powervm.vm.power_off') def test_power_off(self, mock_pwroff): # Default force_immediate pwroff = tf_vm.PowerOff(self.apt, self.instance) pwroff.execute() mock_pwroff.assert_called_once_with(self.apt, self.instance, force_immediate=False) mock_pwroff.reset_mock() # Explicit force_immediate pwroff = tf_vm.PowerOff(self.apt, self.instance, force_immediate=True) pwroff.execute() mock_pwroff.assert_called_once_with(self.apt, self.instance, force_immediate=True) @mock.patch('nova_powervm.virt.powervm.vm.delete_lpar') def test_delete(self, mock_dlt): delete = tf_vm.Delete(self.apt, self.instance) delete.execute() mock_dlt.assert_called_once_with(self.apt, self.instance) @mock.patch('nova_powervm.virt.powervm.vm.update') def test_resize(self, mock_vm_update): resize = tf_vm.Resize(self.apt, 'host_wrapper', self.instance, name='new_name') mock_vm_update.return_value = 'resized_entry' resized_entry = resize.execute() mock_vm_update.assert_called_once_with( self.apt, 'host_wrapper', self.instance, entry=None, name='new_name') self.assertEqual('resized_entry', resized_entry) @mock.patch('nova_powervm.virt.powervm.vm.rename') def test_rename(self, mock_vm_rename): mock_vm_rename.return_value = 'new_entry' rename = tf_vm.Rename(self.apt, self.instance, 'new_name') new_entry = rename.execute() mock_vm_rename.assert_called_once_with( self.apt, self.instance, 'new_name') self.assertEqual('new_entry', new_entry) def test_store_nvram(self): nvram_mgr = mock.Mock() store_nvram = tf_vm.StoreNvram(nvram_mgr, self.instance, immediate=True) store_nvram.execute() nvram_mgr.store.assert_called_once_with(self.instance, immediate=True) # No exception is raised if the NVRAM could not be stored. nvram_mgr.reset_mock() nvram_mgr.store.side_effect = ValueError('Not Available') store_nvram.execute() nvram_mgr.store.assert_called_once_with(self.instance, immediate=True) def test_delete_nvram(self): nvram_mgr = mock.Mock() delete_nvram = tf_vm.DeleteNvram(nvram_mgr, self.instance) delete_nvram.execute() nvram_mgr.remove.assert_called_once_with(self.instance) # No exception is raised if the NVRAM could not be stored. nvram_mgr.reset_mock() nvram_mgr.remove.side_effect = ValueError('Not Available') delete_nvram.execute() nvram_mgr.remove.assert_called_once_with(self.instance)