Files
nova-powervm/nova_powervm/tests/virt/powervm/test_live_migration.py
Kyle L. Henderson bf76d4c828 Initial code for live migration
Add initial driver methods for live migration. This support
is limited to implementing the 'good path' for migration.
Following change sets will implement more of the validation
checking and error paths.

Change-Id: I7edc4ee4ba478bf74f1030ac72c14ec07b8def78
2015-08-11 10:17:43 -05:00

177 lines
7.3 KiB
Python

# 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 import objects
from nova import test
from nova_powervm.tests.virt import powervm
from nova_powervm.tests.virt.powervm import fixtures as fx
from nova_powervm.virt.powervm import live_migration as lpm
class TestLPM(test.TestCase):
def setUp(self):
super(TestLPM, self).setUp()
self.flags(disk_driver='localdisk', group='powervm')
self.drv_fix = self.useFixture(fx.PowerVMComputeDriver())
self.drv = self.drv_fix.drv
self.apt = self.drv_fix.pypvm.apt
self.inst = objects.Instance(**powervm.TEST_INSTANCE)
self.lpmsrc = lpm.LiveMigrationSrc(self.drv, self.inst, {})
self.lpmdst = lpm.LiveMigrationDest(self.drv, self.inst)
@mock.patch('nova_powervm.virt.powervm.media.ConfigDrivePowerVM')
@mock.patch('nova_powervm.virt.powervm.vm.get_instance_wrapper')
@mock.patch('pypowervm.wrappers.managed_system.System.migration_data',
new_callable=mock.PropertyMock, name='MigDataProp')
def test_lpm_source(self, mock_migrdata, mock_get_wrap, mock_cd):
migr_data = {'active_migrations_supported': 4,
'active_migrations_in_progress': 2}
mock_migrdata.return_value = migr_data
with mock.patch.object(
self.lpmsrc, '_check_dlpar_rmc', return_value=None):
# Test the bad path first, then patch in values to make suceed
self.lpmsrc.dest_data = {'dest_proc_compat': 'a,b,c'}
mock_wrap = mock.Mock()
mock_get_wrap.return_value = mock_wrap
self.assertRaises(lpm.LiveMigrationProcCompat,
self.lpmsrc.check_source, 'context',
'block_device_info')
# Patch the proc compat fields, to get further
pm = mock.PropertyMock(return_value='b')
type(mock_wrap).proc_compat_mode = pm
self.assertRaises(lpm.LiveMigrationInvalidState,
self.lpmsrc.check_source, 'context',
'block_device_info')
pm = mock.PropertyMock(return_value='Not_Migrating')
type(mock_wrap).migration_state = pm
# Finally, good path.
self.lpmsrc.check_source('context', 'block_device_info')
# Ensure we tried to remove the vopts.
mock_cd.return_value.dlt_vopt.assert_called_once_with(
mock.ANY)
# Ensure migration counts are validated
migr_data['active_migrations_in_progress'] = 4
self.assertRaises(lpm.LiveMigrationCapacity,
self.lpmsrc.check_source, 'context',
'block_device_info')
@mock.patch('pypowervm.wrappers.managed_system.System.migration_data',
new_callable=mock.PropertyMock, name='MigDataProp')
def test_lpm_dest(self, mock_migrdata):
src_compute_info = {'stats': {'memory_region_size': 1}}
dst_compute_info = {'stats': {'memory_region_size': 1}}
migr_data = {'active_migrations_supported': 4,
'active_migrations_in_progress': 2}
mock_migrdata.return_value = migr_data
with mock.patch.object(self.drv.host_wrapper, 'refresh') as mock_rfh:
self.lpmdst.check_destination(
'context', src_compute_info, dst_compute_info)
mock_rfh.assert_called_once_with()
# Ensure migration counts are validated
migr_data['active_migrations_in_progress'] = 4
self.assertRaises(lpm.LiveMigrationCapacity,
self.lpmdst.check_destination, 'context',
src_compute_info, dst_compute_info)
# Repair the stat
migr_data['active_migrations_in_progress'] = 2
# Ensure diff memory sizes raises an exception
dst_compute_info['stats']['memory_region_size'] = 2
self.assertRaises(lpm.LiveMigrationMRS,
self.lpmdst.check_destination, 'context',
src_compute_info, dst_compute_info)
def test_pre_live_mig(self):
self.lpmdst.pre_live_migration('context', 'block_device_info',
'network_info', 'disk_info',
{})
@mock.patch('pypowervm.tasks.migration.migrate_lpar')
def test_live_migration(self, mock_migr):
self.lpmsrc.lpar_w = mock.Mock()
self.lpmsrc.dest_data = dict(
dest_sys_name='a', dest_ip='1', dest_user_id='neo')
self.lpmsrc.live_migration('context', 'migrate_data')
mock_migr.called_once_with('context')
# Test that we raise errors received during migration
mock_migr.side_effect = ValueError()
self.assertRaises(ValueError, self.lpmsrc.live_migration, 'context',
'migrate_data')
mock_migr.called_once_with('context')
def test_post_live_mig_src(self):
self.lpmsrc.post_live_migration_at_source('network_info')
def test_post_live_mig_dest(self):
self.lpmdst.post_live_migration_at_destination('network_info')
@mock.patch('pypowervm.tasks.migration.migrate_recover')
def test_rollback(self, mock_migr):
self.lpmsrc.lpar_w = mock.Mock()
# Test no need to rollback
self.lpmsrc.lpar_w.migration_state = 'Not_Migrating'
self.lpmsrc.rollback_live_migration('context')
self.assertTrue(self.lpmsrc.lpar_w.refresh.called)
self.assertFalse(mock_migr.called)
# Test calling the rollback
self.lpmsrc.lpar_w.reset_mock()
self.lpmsrc.lpar_w.migration_state = 'Pretend its Migrating'
self.lpmsrc.rollback_live_migration('context')
self.assertTrue(self.lpmsrc.lpar_w.refresh.called)
mock_migr.assert_called_once_with(self.lpmsrc.lpar_w, force=True)
# Test exception from rollback
mock_migr.reset_mock()
self.lpmsrc.lpar_w.reset_mock()
mock_migr.side_effect = ValueError()
self.lpmsrc.rollback_live_migration('context')
self.assertTrue(self.lpmsrc.lpar_w.refresh.called)
mock_migr.assert_called_once_with(self.lpmsrc.lpar_w, force=True)
def test_check_dlpar_rmc(self):
lpar_w = mock.Mock()
lpar_w.check_dlpar_connectivity.return_value = (1, 'active')
self.lpmsrc._check_dlpar_rmc(lpar_w)
lpar_w.check_dlpar_connectivity.return_value = (0, 'active')
self.assertRaises(lpm.LiveMigrationDLPAR,
self.lpmsrc._check_dlpar_rmc, lpar_w)
lpar_w.check_dlpar_connectivity.return_value = (1, 'not active')
self.assertRaises(lpm.LiveMigrationRMC,
self.lpmsrc._check_dlpar_rmc, lpar_w)