OpenStack Compute (Nova)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

7461 lines
363 KiB

# 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.
"""Unit tests for ComputeManager()."""
import contextlib
import copy
import datetime
import time
from cinderclient import exceptions as cinder_exception
from cursive import exception as cursive_exception
from eventlet import event as eventlet_event
import mock
import netaddr
import oslo_messaging as messaging
from oslo_serialization import jsonutils
from oslo_utils import timeutils
from oslo_utils import uuidutils
import six
import testtools
import nova
from nova.compute import build_results
from nova.compute import manager
from nova.compute import power_state
from nova.compute import resource_tracker
from nova.compute import task_states
from nova.compute import utils as compute_utils
from nova.compute import vm_states
from nova.conductor import api as conductor_api
import nova.conf
from nova import context
from nova import db
from nova import exception
from nova.network import api as network_api
from nova.network import model as network_model
from nova import objects
from nova.objects import block_device as block_device_obj
from nova.objects import fields
from nova.objects import instance as instance_obj
from nova.objects import migrate_data as migrate_data_obj
from nova.objects import network_request as net_req_obj
from nova import test
from nova.tests import fixtures
from nova.tests.unit.api.openstack import fakes
from nova.tests.unit.compute import fake_resource_tracker
from nova.tests.unit import fake_block_device
from nova.tests.unit import fake_flavor
from nova.tests.unit import fake_instance
from nova.tests.unit import fake_network
from nova.tests.unit import fake_network_cache_model
from nova.tests.unit import fake_notifier
from nova.tests.unit.objects import test_instance_fault
from nova.tests.unit.objects import test_instance_info_cache
from nova.tests import uuidsentinel as uuids
from nova import utils
from nova.virt.block_device import DriverVolumeBlockDevice as driver_bdm_volume
from nova.virt import driver as virt_driver
from nova.virt import event as virtevent
from nova.virt import fake as fake_driver
from nova.virt import hardware
from nova.volume import cinder
CONF = nova.conf.CONF
fake_host_list = [mock.sentinel.host1]
class ComputeManagerUnitTestCase(test.NoDBTestCase):
def setUp(self):
super(ComputeManagerUnitTestCase, self).setUp()
self.compute = manager.ComputeManager()
self.context = context.RequestContext(fakes.FAKE_USER_ID,
fakes.FAKE_PROJECT_ID)
self.useFixture(fixtures.SpawnIsSynchronousFixture())
self.useFixture(fixtures.EventReporterStub())
@mock.patch.object(manager.ComputeManager, '_get_power_state')
@mock.patch.object(manager.ComputeManager, '_sync_instance_power_state')
@mock.patch.object(objects.Instance, 'get_by_uuid')
def _test_handle_lifecycle_event(self, mock_get, mock_sync,
mock_get_power_state, transition,
event_pwr_state, current_pwr_state):
event = mock.Mock()
event.get_instance_uuid.return_value = mock.sentinel.uuid
event.get_transition.return_value = transition
mock_get_power_state.return_value = current_pwr_state
self.compute.handle_lifecycle_event(event)
mock_get.assert_called_with(mock.ANY, mock.sentinel.uuid,
expected_attrs=[])
if event_pwr_state == current_pwr_state:
mock_sync.assert_called_with(mock.ANY, mock_get.return_value,
event_pwr_state)
else:
self.assertFalse(mock_sync.called)
def test_handle_lifecycle_event(self):
event_map = {virtevent.EVENT_LIFECYCLE_STOPPED: power_state.SHUTDOWN,
virtevent.EVENT_LIFECYCLE_STARTED: power_state.RUNNING,
virtevent.EVENT_LIFECYCLE_PAUSED: power_state.PAUSED,
virtevent.EVENT_LIFECYCLE_RESUMED: power_state.RUNNING,
virtevent.EVENT_LIFECYCLE_SUSPENDED:
power_state.SUSPENDED,
}
for transition, pwr_state in event_map.items():
self._test_handle_lifecycle_event(transition=transition,
event_pwr_state=pwr_state,
current_pwr_state=pwr_state)
def test_handle_lifecycle_event_state_mismatch(self):
self._test_handle_lifecycle_event(
transition=virtevent.EVENT_LIFECYCLE_STOPPED,
event_pwr_state=power_state.SHUTDOWN,
current_pwr_state=power_state.RUNNING)
@mock.patch('nova.compute.utils.notify_about_instance_action')
def test_delete_instance_info_cache_delete_ordering(self, mock_notify):
call_tracker = mock.Mock()
call_tracker.clear_events_for_instance.return_value = None
mgr_class = self.compute.__class__
orig_delete = mgr_class._delete_instance
specd_compute = mock.create_autospec(mgr_class)
# spec out everything except for the method we really want
# to test, then use call_tracker to verify call sequence
specd_compute._delete_instance = orig_delete
specd_compute.host = 'compute'
mock_inst = mock.Mock()
mock_inst.uuid = uuids.instance
mock_inst.save = mock.Mock()
mock_inst.destroy = mock.Mock()
mock_inst.system_metadata = mock.Mock()
def _mark_notify(*args, **kwargs):
call_tracker._notify_about_instance_usage(*args, **kwargs)
def _mark_shutdown(*args, **kwargs):
call_tracker._shutdown_instance(*args, **kwargs)
specd_compute.instance_events = call_tracker
specd_compute._notify_about_instance_usage = _mark_notify
specd_compute._shutdown_instance = _mark_shutdown
mock_inst.info_cache = call_tracker
mock_bdms = mock.Mock()
specd_compute._delete_instance(specd_compute,
self.context,
mock_inst,
mock_bdms)
methods_called = [n for n, a, k in call_tracker.mock_calls]
self.assertEqual(['clear_events_for_instance',
'_notify_about_instance_usage',
'_shutdown_instance', 'delete'],
methods_called)
mock_notify.assert_called_once_with(self.context,
mock_inst,
specd_compute.host,
action='delete',
phase='start',
bdms=mock_bdms)
def _make_compute_node(self, hyp_hostname, cn_id):
cn = mock.Mock(spec_set=['hypervisor_hostname', 'id',
'destroy'])
cn.id = cn_id
cn.hypervisor_hostname = hyp_hostname
return cn
@mock.patch.object(manager.ComputeManager, '_get_resource_tracker')
def test_update_available_resource_for_node(self, get_rt):
rt = mock.Mock(spec_set=['update_available_resource'])
get_rt.return_value = rt
self.compute.update_available_resource_for_node(
self.context,
mock.sentinel.node,
)
rt.update_available_resource.assert_called_once_with(
self.context,
mock.sentinel.node,
)
@mock.patch('nova.compute.manager.LOG')
@mock.patch.object(manager.ComputeManager, '_get_resource_tracker')
def test_update_available_resource_for_node_fail_no_host(self, get_rt,
log_mock):
rt = mock.Mock(spec_set=['update_available_resource'])
exc = exception.ComputeHostNotFound(host=mock.sentinel.host)
rt.update_available_resource.side_effect = exc
get_rt.return_value = rt
# Fake out the RT on the compute manager object so we can assert it's
# nulled out after the ComputeHostNotFound exception is raised.
self.compute._resource_tracker = rt
self.compute.update_available_resource_for_node(
self.context,
mock.sentinel.node,
)
rt.update_available_resource.assert_called_once_with(
self.context,
mock.sentinel.node,
)
self.assertTrue(log_mock.info.called)
self.assertIsNone(self.compute._resource_tracker)
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'delete_resource_provider')
@mock.patch.object(manager.ComputeManager,
'update_available_resource_for_node')
@mock.patch.object(fake_driver.FakeDriver, 'get_available_nodes')
@mock.patch.object(manager.ComputeManager, '_get_compute_nodes_in_db')
def test_update_available_resource(self, get_db_nodes, get_avail_nodes,
update_mock, del_rp_mock):
db_nodes = [self._make_compute_node('node%s' % i, i)
for i in range(1, 5)]
avail_nodes = set(['node2', 'node3', 'node4', 'node5'])
avail_nodes_l = list(avail_nodes)
get_db_nodes.return_value = db_nodes
get_avail_nodes.return_value = avail_nodes
self.compute.update_available_resource(self.context)
get_db_nodes.assert_called_once_with(self.context, use_slave=True,
startup=False)
update_mock.has_calls(
[mock.call(self.context, node) for node in avail_nodes_l]
)
# First node in set should have been removed from DB
for db_node in db_nodes:
if db_node.hypervisor_hostname == 'node1':
db_node.destroy.assert_called_once_with()
del_rp_mock.assert_called_once_with(self.context, db_node,
cascade=True)
else:
self.assertFalse(db_node.destroy.called)
@mock.patch('nova.context.get_admin_context')
def test_pre_start_hook(self, get_admin_context):
"""Very simple test just to make sure update_available_resource is
called as expected.
"""
with mock.patch.object(
self.compute, 'update_available_resource') as update_res:
self.compute.pre_start_hook()
update_res.assert_called_once_with(
get_admin_context.return_value, startup=True)
@mock.patch.object(objects.ComputeNodeList, 'get_all_by_host',
side_effect=exception.NotFound)
@mock.patch('nova.compute.manager.LOG')
def test_get_compute_nodes_in_db_on_startup(self, mock_log,
get_all_by_host):
"""Tests to make sure we only log a warning when we do not find a
compute node on startup since this may be expected.
"""
self.assertEqual([], self.compute._get_compute_nodes_in_db(
self.context, startup=True))
get_all_by_host.assert_called_once_with(
self.context, self.compute.host, use_slave=False)
self.assertTrue(mock_log.warning.called)
self.assertFalse(mock_log.error.called)
@mock.patch('nova.compute.utils.notify_about_instance_action')
def test_delete_instance_without_info_cache(self, mock_notify):
instance = fake_instance.fake_instance_obj(
self.context,
uuid=uuids.instance,
vm_state=vm_states.ERROR,
host=self.compute.host,
expected_attrs=['system_metadata'])
with test.nested(
mock.patch.object(self.compute, '_notify_about_instance_usage'),
mock.patch.object(self.compute, '_shutdown_instance'),
mock.patch.object(instance, 'obj_load_attr'),
mock.patch.object(instance, 'save'),
mock.patch.object(instance, 'destroy')
) as (
compute_notify_about_instance_usage, compute_shutdown_instance,
instance_obj_load_attr, instance_save, instance_destroy
):
instance.info_cache = None
self.compute._delete_instance(self.context, instance, [])
mock_notify.assert_has_calls([
mock.call(self.context, instance, 'fake-mini',
action='delete', phase='start', bdms=[]),
mock.call(self.context, instance, 'fake-mini',
action='delete', phase='end', bdms=[])])
def test_check_device_tagging_no_tagging(self):
bdms = objects.BlockDeviceMappingList(objects=[
objects.BlockDeviceMapping(source_type='volume',
destination_type='volume',
instance_uuid=uuids.instance)])
net_req = net_req_obj.NetworkRequest(tag=None)
net_req_list = net_req_obj.NetworkRequestList(objects=[net_req])
with mock.patch.dict(self.compute.driver.capabilities,
supports_device_tagging=False):
self.compute._check_device_tagging(net_req_list, bdms)
def test_check_device_tagging_no_networks(self):
bdms = objects.BlockDeviceMappingList(objects=[
objects.BlockDeviceMapping(source_type='volume',
destination_type='volume',
instance_uuid=uuids.instance)])
with mock.patch.dict(self.compute.driver.capabilities,
supports_device_tagging=False):
self.compute._check_device_tagging(None, bdms)
def test_check_device_tagging_tagged_net_req_no_virt_support(self):
bdms = objects.BlockDeviceMappingList(objects=[
objects.BlockDeviceMapping(source_type='volume',
destination_type='volume',
instance_uuid=uuids.instance)])
net_req = net_req_obj.NetworkRequest(port_id=uuids.bar, tag='foo')
net_req_list = net_req_obj.NetworkRequestList(objects=[net_req])
with mock.patch.dict(self.compute.driver.capabilities,
supports_device_tagging=False):
self.assertRaises(exception.BuildAbortException,
self.compute._check_device_tagging,
net_req_list, bdms)
def test_check_device_tagging_tagged_bdm_no_driver_support(self):
bdms = objects.BlockDeviceMappingList(objects=[
objects.BlockDeviceMapping(source_type='volume',
destination_type='volume',
tag='foo',
instance_uuid=uuids.instance)])
with mock.patch.dict(self.compute.driver.capabilities,
supports_device_tagging=False):
self.assertRaises(exception.BuildAbortException,
self.compute._check_device_tagging,
None, bdms)
def test_check_device_tagging_tagged_bdm_no_driver_support_declared(self):
bdms = objects.BlockDeviceMappingList(objects=[
objects.BlockDeviceMapping(source_type='volume',
destination_type='volume',
tag='foo',
instance_uuid=uuids.instance)])
with mock.patch.dict(self.compute.driver.capabilities):
self.compute.driver.capabilities.pop('supports_device_tagging',
None)
self.assertRaises(exception.BuildAbortException,
self.compute._check_device_tagging,
None, bdms)
def test_check_device_tagging_tagged_bdm_with_driver_support(self):
bdms = objects.BlockDeviceMappingList(objects=[
objects.BlockDeviceMapping(source_type='volume',
destination_type='volume',
tag='foo',
instance_uuid=uuids.instance)])
net_req = net_req_obj.NetworkRequest(network_id=uuids.bar)
net_req_list = net_req_obj.NetworkRequestList(objects=[net_req])
with mock.patch.dict(self.compute.driver.capabilities,
supports_device_tagging=True):
self.compute._check_device_tagging(net_req_list, bdms)
def test_check_device_tagging_tagged_net_req_with_driver_support(self):
bdms = objects.BlockDeviceMappingList(objects=[
objects.BlockDeviceMapping(source_type='volume',
destination_type='volume',
instance_uuid=uuids.instance)])
net_req = net_req_obj.NetworkRequest(network_id=uuids.bar, tag='foo')
net_req_list = net_req_obj.NetworkRequestList(objects=[net_req])
with mock.patch.dict(self.compute.driver.capabilities,
supports_device_tagging=True):
self.compute._check_device_tagging(net_req_list, bdms)
@mock.patch.object(objects.BlockDeviceMapping, 'create')
@mock.patch.object(objects.BlockDeviceMappingList, 'get_by_instance_uuid',
return_value=objects.BlockDeviceMappingList())
def test_reserve_block_device_name_with_tag(self, mock_get, mock_create):
instance = fake_instance.fake_instance_obj(self.context)
with test.nested(
mock.patch.object(self.compute,
'_get_device_name_for_instance',
return_value='/dev/vda'),
mock.patch.dict(self.compute.driver.capabilities,
supports_tagged_attach_volume=True)):
bdm = self.compute.reserve_block_device_name(
self.context, instance, None, None, None, None, tag='foo')
self.assertEqual('foo', bdm.tag)
@mock.patch.object(compute_utils, 'add_instance_fault_from_exc')
def test_reserve_block_device_name_raises(self, _):
with mock.patch.dict(self.compute.driver.capabilities,
supports_tagged_attach_volume=False):
self.assertRaises(exception.VolumeTaggedAttachNotSupported,
self.compute.reserve_block_device_name,
self.context,
fake_instance.fake_instance_obj(self.context),
'fake_device', 'fake_volume_id', 'fake_disk_bus',
'fake_device_type', tag='foo')
@mock.patch.object(objects.BlockDeviceMapping, 'create')
@mock.patch.object(objects.BlockDeviceMappingList, 'get_by_instance_uuid',
return_value=objects.BlockDeviceMappingList())
def test_reserve_block_device_name_multiattach(self, mock_get,
mock_create):
"""Tests the case that multiattach=True and the driver supports it."""
instance = fake_instance.fake_instance_obj(self.context)
with test.nested(
mock.patch.object(self.compute,
'_get_device_name_for_instance',
return_value='/dev/vda'),
mock.patch.dict(self.compute.driver.capabilities,
supports_multiattach=True)):
self.compute.reserve_block_device_name(
self.context, instance, device=None, volume_id=uuids.volume_id,
disk_bus=None, device_type=None, multiattach=True)
@mock.patch.object(compute_utils, 'add_instance_fault_from_exc')
def test_reserve_block_device_name_multiattach_raises(self, _):
with mock.patch.dict(self.compute.driver.capabilities,
supports_multiattach=False):
self.assertRaises(exception.MultiattachNotSupportedByVirtDriver,
self.compute.reserve_block_device_name,
self.context,
fake_instance.fake_instance_obj(self.context),
'fake_device', 'fake_volume_id', 'fake_disk_bus',
'fake_device_type', multiattach=True)
@mock.patch.object(objects.Instance, 'save')
@mock.patch.object(time, 'sleep')
def test_allocate_network_succeeds_after_retries(
self, mock_sleep, mock_save):
self.flags(network_allocate_retries=8)
instance = fake_instance.fake_instance_obj(
self.context, expected_attrs=['system_metadata'])
is_vpn = 'fake-is-vpn'
req_networks = objects.NetworkRequestList(
objects=[objects.NetworkRequest(network_id='fake')])
macs = 'fake-macs'
sec_groups = 'fake-sec-groups'
final_result = 'meow'
expected_sleep_times = [1, 2, 4, 8, 16, 30, 30, 30]
with mock.patch.object(
self.compute.network_api, 'allocate_for_instance',
side_effect=[test.TestingException()] * 7 + [final_result]):
res = self.compute._allocate_network_async(self.context, instance,
req_networks,
macs,
sec_groups,
is_vpn)
mock_sleep.has_calls(expected_sleep_times)
self.assertEqual(final_result, res)
# Ensure save is not called in while allocating networks, the instance
# is saved after the allocation.
self.assertFalse(mock_save.called)
self.assertEqual('True', instance.system_metadata['network_allocated'])
def test_allocate_network_fails(self):
self.flags(network_allocate_retries=0)
instance = {}
is_vpn = 'fake-is-vpn'
req_networks = objects.NetworkRequestList(
objects=[objects.NetworkRequest(network_id='fake')])
macs = 'fake-macs'
sec_groups = 'fake-sec-groups'
with mock.patch.object(
self.compute.network_api, 'allocate_for_instance',
side_effect=test.TestingException) as mock_allocate:
self.assertRaises(test.TestingException,
self.compute._allocate_network_async,
self.context, instance, req_networks, macs,
sec_groups, is_vpn)
mock_allocate.assert_called_once_with(
self.context, instance, vpn=is_vpn,
requested_networks=req_networks, macs=macs,
security_groups=sec_groups,
bind_host_id=instance.get('host'))
@mock.patch.object(manager.ComputeManager, '_instance_update')
@mock.patch.object(time, 'sleep')
def test_allocate_network_with_conf_value_is_one(
self, sleep, _instance_update):
self.flags(network_allocate_retries=1)
instance = fake_instance.fake_instance_obj(
self.context, expected_attrs=['system_metadata'])
is_vpn = 'fake-is-vpn'
req_networks = objects.NetworkRequestList(
objects=[objects.NetworkRequest(network_id='fake')])
macs = 'fake-macs'
sec_groups = 'fake-sec-groups'
final_result = 'zhangtralon'
with mock.patch.object(self.compute.network_api,
'allocate_for_instance',
side_effect = [test.TestingException(),
final_result]):
res = self.compute._allocate_network_async(self.context, instance,
req_networks,
macs,
sec_groups,
is_vpn)
self.assertEqual(final_result, res)
self.assertEqual(1, sleep.call_count)
def test_allocate_network_skip_for_no_allocate(self):
# Ensures that we don't do anything if requested_networks has 'none'
# for the network_id.
req_networks = objects.NetworkRequestList(
objects=[objects.NetworkRequest(network_id='none')])
nwinfo = self.compute._allocate_network_async(
self.context, mock.sentinel.instance, req_networks, macs=None,
security_groups=['default'], is_vpn=False)
self.assertEqual(0, len(nwinfo))
@mock.patch('nova.compute.manager.ComputeManager.'
'_do_build_and_run_instance')
def _test_max_concurrent_builds(self, mock_dbari):
with mock.patch.object(self.compute,
'_build_semaphore') as mock_sem:
instance = objects.Instance(uuid=uuidutils.generate_uuid())
for i in (1, 2, 3):
self.compute.build_and_run_instance(self.context, instance,
mock.sentinel.image,
mock.sentinel.request_spec,
{})
self.assertEqual(3, mock_sem.__enter__.call_count)
def test_max_concurrent_builds_limited(self):
self.flags(max_concurrent_builds=2)
self._test_max_concurrent_builds()
def test_max_concurrent_builds_unlimited(self):
self.flags(max_concurrent_builds=0)
self._test_max_concurrent_builds()
def test_max_concurrent_builds_semaphore_limited(self):
self.flags(max_concurrent_builds=123)
self.assertEqual(123,
manager.ComputeManager()._build_semaphore.balance)
def test_max_concurrent_builds_semaphore_unlimited(self):
self.flags(max_concurrent_builds=0)
compute = manager.ComputeManager()
self.assertEqual(0, compute._build_semaphore.balance)
self.assertIsInstance(compute._build_semaphore,
compute_utils.UnlimitedSemaphore)
def test_nil_out_inst_obj_host_and_node_sets_nil(self):
instance = fake_instance.fake_instance_obj(self.context,
uuid=uuids.instance,
host='foo-host',
node='foo-node')
self.assertIsNotNone(instance.host)
self.assertIsNotNone(instance.node)
self.compute._nil_out_instance_obj_host_and_node(instance)
self.assertIsNone(instance.host)
self.assertIsNone(instance.node)
def test_init_host(self):
our_host = self.compute.host
inst = fake_instance.fake_db_instance(
vm_state=vm_states.ACTIVE,
info_cache=dict(test_instance_info_cache.fake_info_cache,
network_info=None),
security_groups=None)
startup_instances = [inst, inst, inst]
def _make_instance_list(db_list):
return instance_obj._make_instance_list(
self.context, objects.InstanceList(), db_list, None)
@mock.patch.object(fake_driver.FakeDriver, 'init_host')
@mock.patch.object(fake_driver.FakeDriver, 'filter_defer_apply_on')
@mock.patch.object(fake_driver.FakeDriver, 'filter_defer_apply_off')
@mock.patch.object(objects.InstanceList, 'get_by_host')
@mock.patch.object(context, 'get_admin_context')
@mock.patch.object(manager.ComputeManager,
'_destroy_evacuated_instances')
@mock.patch.object(manager.ComputeManager, '_init_instance')
@mock.patch.object(self.compute, '_update_scheduler_instance_info')
def _do_mock_calls(mock_update_scheduler, mock_inst_init,
mock_destroy, mock_admin_ctxt, mock_host_get,
mock_filter_off, mock_filter_on, mock_init_host,
defer_iptables_apply):
mock_admin_ctxt.return_value = self.context
inst_list = _make_instance_list(startup_instances)
mock_host_get.return_value = inst_list
self.compute.init_host()
if defer_iptables_apply:
self.assertTrue(mock_filter_on.called)
mock_destroy.assert_called_once_with(self.context)
mock_inst_init.assert_has_calls(
[mock.call(self.context, inst_list[0]),
mock.call(self.context, inst_list[1]),
mock.call(self.context, inst_list[2])])
if defer_iptables_apply:
self.assertTrue(mock_filter_off.called)
mock_init_host.assert_called_once_with(host=our_host)
mock_host_get.assert_called_once_with(self.context, our_host,
expected_attrs=['info_cache', 'metadata'])
mock_update_scheduler.assert_called_once_with(
self.context, inst_list)
# Test with defer_iptables_apply
self.flags(defer_iptables_apply=True)
_do_mock_calls(defer_iptables_apply=True)
# Test without defer_iptables_apply
self.flags(defer_iptables_apply=False)
_do_mock_calls(defer_iptables_apply=False)
@mock.patch('nova.objects.InstanceList.get_by_host',
return_value=objects.InstanceList())
@mock.patch('nova.compute.manager.ComputeManager.'
'_destroy_evacuated_instances')
@mock.patch('nova.compute.manager.ComputeManager._init_instance',
mock.NonCallableMock())
@mock.patch('nova.compute.manager.ComputeManager.'
'_update_scheduler_instance_info', mock.NonCallableMock())
def test_init_host_no_instances(self, mock_destroy_evac_instances,
mock_get_by_host):
"""Tests the case that init_host runs and there are no instances
on this host yet (it's brand new). Uses NonCallableMock for the
methods we assert should not be called.
"""
self.compute.init_host()
@mock.patch('nova.objects.InstanceList')
@mock.patch('nova.objects.MigrationList.get_by_filters')
def test_cleanup_host(self, mock_miglist_get, mock_instance_list):
# just testing whether the cleanup_host method
# when fired will invoke the underlying driver's
# equivalent method.
mock_miglist_get.return_value = []
mock_instance_list.get_by_host.return_value = []
with mock.patch.object(self.compute, 'driver') as mock_driver:
self.compute.init_host()
mock_driver.init_host.assert_called_once_with(host='fake-mini')
self.compute.cleanup_host()
# register_event_listener is called on startup (init_host) and
# in cleanup_host
mock_driver.register_event_listener.assert_has_calls([
mock.call(self.compute.handle_events), mock.call(None)])
mock_driver.cleanup_host.assert_called_once_with(host='fake-mini')
def test_init_virt_events_disabled(self):
self.flags(handle_virt_lifecycle_events=False, group='workarounds')
with mock.patch.object(self.compute.driver,
'register_event_listener') as mock_register:
self.compute.init_virt_events()
self.assertFalse(mock_register.called)
@mock.patch('nova.objects.ComputeNode.get_by_host_and_nodename')
@mock.patch('nova.scheduler.utils.resources_from_flavor')
@mock.patch.object(manager.ComputeManager, '_get_instances_on_driver')
@mock.patch.object(manager.ComputeManager, 'init_virt_events')
@mock.patch.object(context, 'get_admin_context')
@mock.patch.object(objects.InstanceList, 'get_by_host')
@mock.patch.object(fake_driver.FakeDriver, 'destroy')
@mock.patch.object(fake_driver.FakeDriver, 'init_host')
@mock.patch('nova.utils.temporary_mutation')
@mock.patch('nova.objects.MigrationList.get_by_filters')
@mock.patch('nova.objects.Migration.save')
def test_init_host_with_evacuated_instance(self, mock_save, mock_mig_get,
mock_temp_mut, mock_init_host, mock_destroy, mock_host_get,
mock_admin_ctxt, mock_init_virt, mock_get_inst, mock_resources,
mock_get_node):
our_host = self.compute.host
not_our_host = 'not-' + our_host
deleted_instance = fake_instance.fake_instance_obj(
self.context, host=not_our_host, uuid=uuids.deleted_instance)
migration = objects.Migration(instance_uuid=deleted_instance.uuid)
migration.source_node = 'fake-node'
mock_mig_get.return_value = [migration]
mock_admin_ctxt.return_value = self.context
mock_host_get.return_value = objects.InstanceList()
our_node = objects.ComputeNode(host=our_host, uuid=uuids.our_node_uuid)
mock_get_node.return_value = our_node
mock_resources.return_value = mock.sentinel.my_resources
# simulate failed instance
mock_get_inst.return_value = [deleted_instance]
with test.nested(
mock.patch.object(
self.compute.network_api, 'get_instance_nw_info',
side_effect = exception.InstanceNotFound(
instance_id=deleted_instance['uuid'])),
mock.patch.object(
self.compute.reportclient,
'remove_provider_from_instance_allocation')
) as (mock_get_net, mock_remove_allocation):
self.compute.init_host()
mock_remove_allocation.assert_called_once_with(
deleted_instance.uuid, uuids.our_node_uuid,
deleted_instance.user_id, deleted_instance.project_id,
mock.sentinel.my_resources)
mock_init_host.assert_called_once_with(host=our_host)
mock_host_get.assert_called_once_with(self.context, our_host,
expected_attrs=['info_cache', 'metadata'])
mock_init_virt.assert_called_once_with()
mock_temp_mut.assert_called_once_with(self.context, read_deleted='yes')
mock_get_inst.assert_called_once_with(self.context)
mock_get_net.assert_called_once_with(self.context, deleted_instance)
# ensure driver.destroy is called so that driver may
# clean up any dangling files
mock_destroy.assert_called_once_with(self.context, deleted_instance,
mock.ANY, mock.ANY, mock.ANY)
mock_save.assert_called_once_with()
def test_init_instance_with_binding_failed_vif_type(self):
# this instance will plug a 'binding_failed' vif
instance = fake_instance.fake_instance_obj(
self.context,
uuid=uuids.instance,
info_cache=None,
power_state=power_state.RUNNING,
vm_state=vm_states.ACTIVE,
task_state=None,
host=self.compute.host,
expected_attrs=['info_cache'])
with test.nested(
mock.patch.object(context, 'get_admin_context',
return_value=self.context),
mock.patch.object(objects.Instance, 'get_network_info',
return_value=network_model.NetworkInfo()),
mock.patch.object(self.compute.driver, 'plug_vifs',
side_effect=exception.VirtualInterfacePlugException(
"Unexpected vif_type=binding_failed")),
mock.patch.object(self.compute, '_set_instance_obj_error_state')
) as (get_admin_context, get_nw_info, plug_vifs, set_error_state):
self.compute._init_instance(self.context, instance)
set_error_state.assert_called_once_with(self.context, instance)
def test__get_power_state_InstanceNotFound(self):
instance = fake_instance.fake_instance_obj(
self.context,
power_state=power_state.RUNNING)
with mock.patch.object(self.compute.driver,
'get_info',
side_effect=exception.InstanceNotFound(instance_id=1)):
self.assertEqual(self.compute._get_power_state(self.context,
instance),
power_state.NOSTATE)
def test__get_power_state_NotFound(self):
instance = fake_instance.fake_instance_obj(
self.context,
power_state=power_state.RUNNING)
with mock.patch.object(self.compute.driver,
'get_info',
side_effect=exception.NotFound()):
self.assertRaises(exception.NotFound,
self.compute._get_power_state,
self.context, instance)
@mock.patch.object(manager.ComputeManager, '_get_power_state')
@mock.patch.object(fake_driver.FakeDriver, 'plug_vifs')
@mock.patch.object(fake_driver.FakeDriver, 'resume_state_on_host_boot')
@mock.patch.object(manager.ComputeManager,
'_get_instance_block_device_info')
@mock.patch.object(manager.ComputeManager, '_set_instance_obj_error_state')
def test_init_instance_failed_resume_sets_error(self, mock_set_inst,
mock_get_inst, mock_resume, mock_plug, mock_get_power):
instance = fake_instance.fake_instance_obj(
self.context,
uuid=uuids.instance,
info_cache=None,
power_state=power_state.RUNNING,
vm_state=vm_states.ACTIVE,
task_state=None,
host=self.compute.host,
expected_attrs=['info_cache'])
self.flags(resume_guests_state_on_host_boot=True)
mock_get_power.side_effect = (power_state.SHUTDOWN,
power_state.SHUTDOWN)
mock_get_inst.return_value = 'fake-bdm'
mock_resume.side_effect = test.TestingException
self.compute._init_instance('fake-context', instance)
mock_get_power.assert_has_calls([mock.call(mock.ANY, instance),
mock.call(mock.ANY, instance)])
mock_plug.assert_called_once_with(instance, mock.ANY)
mock_get_inst.assert_called_once_with(mock.ANY, instance)
mock_resume.assert_called_once_with(mock.ANY, instance, mock.ANY,
'fake-bdm')
mock_set_inst.assert_called_once_with(mock.ANY, instance)
@mock.patch.object(objects.BlockDeviceMapping, 'destroy')
@mock.patch.object(objects.BlockDeviceMappingList, 'get_by_instance_uuid')
@mock.patch.object(objects.Instance, 'destroy')
@mock.patch.object(objects.Instance, 'obj_load_attr')
@mock.patch.object(objects.quotas, 'ids_from_instance')
def test_init_instance_complete_partial_deletion(
self, mock_ids_from_instance,
mock_inst_destroy, mock_obj_load_attr, mock_get_by_instance_uuid,
mock_bdm_destroy):
"""Test to complete deletion for instances in DELETED status but not
marked as deleted in the DB
"""
instance = fake_instance.fake_instance_obj(
self.context,
project_id=fakes.FAKE_PROJECT_ID,
uuid=uuids.instance,
vcpus=1,
memory_mb=64,
power_state=power_state.SHUTDOWN,
vm_state=vm_states.DELETED,
host=self.compute.host,
task_state=None,
deleted=False,
deleted_at=None,
metadata={},
system_metadata={},
expected_attrs=['metadata', 'system_metadata'])
# Make sure instance vm_state is marked as 'DELETED' but instance is
# not destroyed from db.
self.assertEqual(vm_states.DELETED, instance.vm_state)
self.assertFalse(instance.deleted)
def fake_inst_destroy():
instance.deleted = True
instance.deleted_at = timeutils.utcnow()
mock_ids_from_instance.return_value = (instance.project_id,
instance.user_id)
mock_inst_destroy.side_effect = fake_inst_destroy()
self.compute._init_instance(self.context, instance)
# Make sure that instance.destroy method was called and
# instance was deleted from db.
self.assertNotEqual(0, instance.deleted)
@mock.patch('nova.compute.manager.LOG')
def test_init_instance_complete_partial_deletion_raises_exception(
self, mock_log):
instance = fake_instance.fake_instance_obj(
self.context,
project_id=fakes.FAKE_PROJECT_ID,
uuid=uuids.instance,
vcpus=1,
memory_mb=64,
power_state=power_state.SHUTDOWN,
vm_state=vm_states.DELETED,
host=self.compute.host,
task_state=None,
deleted=False,
deleted_at=None,
metadata={},
system_metadata={},
expected_attrs=['metadata', 'system_metadata'])
with mock.patch.object(self.compute,
'_complete_partial_deletion') as mock_deletion:
mock_deletion.side_effect = test.TestingException()
self.compute._init_instance(self, instance)
msg = u'Failed to complete a deletion'
mock_log.exception.assert_called_once_with(msg, instance=instance)
def test_init_instance_stuck_in_deleting(self):
instance = fake_instance.fake_instance_obj(
self.context,
project_id=fakes.FAKE_PROJECT_ID,
uuid=uuids.instance,
vcpus=1,
memory_mb=64,
power_state=power_state.RUNNING,
vm_state=vm_states.ACTIVE,
host=self.compute.host,
task_state=task_states.DELETING)
bdms = []
with test.nested(
mock.patch.object(objects.BlockDeviceMappingList,
'get_by_instance_uuid',
return_value=bdms),
mock.patch.object(self.compute, '_delete_instance'),
mock.patch.object(instance, 'obj_load_attr')
) as (mock_get, mock_delete, mock_load):
self.compute._init_instance(self.context, instance)
mock_get.assert_called_once_with(self.context, instance.uuid)
mock_delete.assert_called_once_with(self.context, instance,
bdms)
@mock.patch.object(objects.Instance, 'get_by_uuid')
@mock.patch.object(objects.BlockDeviceMappingList, 'get_by_instance_uuid')
def test_init_instance_stuck_in_deleting_raises_exception(
self, mock_get_by_instance_uuid, mock_get_by_uuid):
instance = fake_instance.fake_instance_obj(
self.context,
project_id=fakes.FAKE_PROJECT_ID,
uuid=uuids.instance,
vcpus=1,
memory_mb=64,
metadata={},
system_metadata={},
host=self.compute.host,
vm_state=vm_states.ACTIVE,
task_state=task_states.DELETING,
expected_attrs=['metadata', 'system_metadata'])
bdms = []
def _create_patch(name, attr):
patcher = mock.patch.object(name, attr)
mocked_obj = patcher.start()
self.addCleanup(patcher.stop)
return mocked_obj
mock_delete_instance = _create_patch(self.compute, '_delete_instance')
mock_set_instance_error_state = _create_patch(
self.compute, '_set_instance_obj_error_state')
mock_get_by_instance_uuid.return_value = bdms
mock_get_by_uuid.return_value = instance
mock_delete_instance.side_effect = test.TestingException('test')
self.compute._init_instance(self.context, instance)
mock_set_instance_error_state.assert_called_once_with(
self.context, instance)
def _test_init_instance_reverts_crashed_migrations(self,
old_vm_state=None):
power_on = True if (not old_vm_state or
old_vm_state == vm_states.ACTIVE) else False
sys_meta = {
'old_vm_state': old_vm_state
}
instance = fake_instance.fake_instance_obj(
self.context,
uuid=uuids.instance,
vm_state=vm_states.ERROR,
task_state=task_states.RESIZE_MIGRATING,
power_state=power_state.SHUTDOWN,
system_metadata=sys_meta,
host=self.compute.host,
expected_attrs=['system_metadata'])
with test.nested(
mock.patch.object(objects.Instance, 'get_network_info',
return_value=network_model.NetworkInfo()),
mock.patch.object(self.compute.driver, 'plug_vifs'),
mock.patch.object(self.compute.driver, 'finish_revert_migration'),
mock.patch.object(self.compute, '_get_instance_block_device_info',
return_value=[]),
mock.patch.object(self.compute.driver, 'get_info'),
mock.patch.object(instance, 'save'),
mock.patch.object(self.compute, '_retry_reboot',
return_value=(False, None))
) as (mock_get_nw, mock_plug, mock_finish, mock_get_inst,
mock_get_info, mock_save, mock_retry):
mock_get_info.side_effect = (
hardware.InstanceInfo(state=power_state.SHUTDOWN),
hardware.InstanceInfo(state=power_state.SHUTDOWN))
self.compute._init_instance(self.context, instance)
mock_retry.assert_called_once_with(self.context, instance,
power_state.SHUTDOWN)
mock_get_nw.assert_called_once_with()
mock_plug.assert_called_once_with(instance, [])
mock_get_inst.assert_called_once_with(self.context, instance)
mock_finish.assert_called_once_with(self.context, instance,
[], [], power_on)
mock_save.assert_called_once_with()
mock_get_info.assert_has_calls([mock.call(instance),
mock.call(instance)])
self.assertIsNone(instance.task_state)
def test_init_instance_reverts_crashed_migration_from_active(self):
self._test_init_instance_reverts_crashed_migrations(
old_vm_state=vm_states.ACTIVE)
def test_init_instance_reverts_crashed_migration_from_stopped(self):
self._test_init_instance_reverts_crashed_migrations(
old_vm_state=vm_states.STOPPED)
def test_init_instance_reverts_crashed_migration_no_old_state(self):
self._test_init_instance_reverts_crashed_migrations(old_vm_state=None)
def test_init_instance_resets_crashed_live_migration(self):
instance = fake_instance.fake_instance_obj(
self.context,
uuid=uuids.instance,
vm_state=vm_states.ACTIVE,
host=self.compute.host,
task_state=task_states.MIGRATING)
with test.nested(
mock.patch.object(instance, 'save'),
mock.patch('nova.objects.Instance.get_network_info',
return_value=network_model.NetworkInfo())
) as (save, get_nw_info):
self.compute._init_instance(self.context, instance)
save.assert_called_once_with(expected_task_state=['migrating'])
get_nw_info.assert_called_once_with()
self.assertIsNone(instance.task_state)
self.assertEqual(vm_states.ACTIVE, instance.vm_state)
def _test_init_instance_sets_building_error(self, vm_state,
task_state=None):
instance = fake_instance.fake_instance_obj(
self.context,
uuid=uuids.instance,
vm_state=vm_state,
host=self.compute.host,
task_state=task_state)
with mock.patch.object(instance, 'save') as save:
self.compute._init_instance(self.context, instance)
save.assert_called_once_with()
self.assertIsNone(instance.task_state)
self.assertEqual(vm_states.ERROR, instance.vm_state)
def test_init_instance_sets_building_error(self):
self._test_init_instance_sets_building_error(vm_states.BUILDING)
def test_init_instance_sets_rebuilding_errors(self):
tasks = [task_states.REBUILDING,
task_states.REBUILD_BLOCK_DEVICE_MAPPING,
task_states.REBUILD_SPAWNING]
vms = [vm_states.ACTIVE, vm_states.STOPPED]
for vm_state in vms:
for task_state in tasks:
self._test_init_instance_sets_building_error(
vm_state, task_state)
def _test_init_instance_sets_building_tasks_error(self, instance):
instance.host = self.compute.host
with mock.patch.object(instance, 'save') as save:
self.compute._init_instance(self.context, instance)
save.assert_called_once_with()
self.assertIsNone(instance.task_state)
self.assertEqual(vm_states.ERROR, instance.vm_state)
def test_init_instance_sets_building_tasks_error_scheduling(self):
instance = fake_instance.fake_instance_obj(
self.context,
uuid=uuids.instance,
vm_state=None,
task_state=task_states.SCHEDULING)
self._test_init_instance_sets_building_tasks_error(instance)
def test_init_instance_sets_building_tasks_error_block_device(self):
instance = objects.Instance(self.context)
instance.uuid = uuids.instance
instance.vm_state = None
instance.task_state = task_states.BLOCK_DEVICE_MAPPING
self._test_init_instance_sets_building_tasks_error(instance)
def test_init_instance_sets_building_tasks_error_networking(self):
instance = objects.Instance(self.context)
instance.uuid = uuids.instance
instance.vm_state = None
instance.task_state = task_states.NETWORKING
self._test_init_instance_sets_building_tasks_error(instance)
def test_init_instance_sets_building_tasks_error_spawning(self):
instance = objects.Instance(self.context)
instance.uuid = uuids.instance
instance.vm_state = None
instance.task_state = task_states.SPAWNING
self._test_init_instance_sets_building_tasks_error(instance)
def _test_init_instance_cleans_image_states(self, instance):
with mock.patch.object(instance, 'save') as save:
self.compute._get_power_state = mock.Mock()
self.compute.driver.post_interrupted_snapshot_cleanup = mock.Mock()
instance.info_cache = None
instance.power_state = power_state.RUNNING
instance.host = self.compute.host
self.compute._init_instance(self.context, instance)
save.assert_called_once_with()
self.compute.driver.post_interrupted_snapshot_cleanup.\
assert_called_once_with(self.context, instance)
self.assertIsNone(instance.task_state)
@mock.patch('nova.compute.manager.ComputeManager._get_power_state',
return_value=power_state.RUNNING)
@mock.patch.object(objects.BlockDeviceMappingList, 'get_by_instance_uuid')
def _test_init_instance_cleans_task_states(self, powerstate, state,
mock_get_uuid, mock_get_power_state):
instance = objects.Instance(self.context)
instance.uuid = uuids.instance
instance.info_cache = None
instance.power_state = power_state.RUNNING
instance.vm_state = vm_states.ACTIVE
instance.task_state = state
instance.host = self.compute.host
mock_get_power_state.return_value = powerstate
self.compute._init_instance(self.context, instance)
return instance
def test_init_instance_cleans_image_state_pending_upload(self):
instance = objects.Instance(self.context)
instance.uuid = uuids.instance
instance.vm_state = vm_states.ACTIVE
instance.task_state = task_states.IMAGE_PENDING_UPLOAD
self._test_init_instance_cleans_image_states(instance)
def test_init_instance_cleans_image_state_uploading(self):
instance = objects.Instance(self.context)
instance.uuid = uuids.instance
instance.vm_state = vm_states.ACTIVE
instance.task_state = task_states.IMAGE_UPLOADING
self._test_init_instance_cleans_image_states(instance)
def test_init_instance_cleans_image_state_snapshot(self):
instance = objects.Instance(self.context)
instance.uuid = uuids.instance
instance.vm_state = vm_states.ACTIVE
instance.task_state = task_states.IMAGE_SNAPSHOT
self._test_init_instance_cleans_image_states(instance)
def test_init_instance_cleans_image_state_snapshot_pending(self):
instance = objects.Instance(self.context)
instance.uuid = uuids.instance
instance.vm_state = vm_states.ACTIVE
instance.task_state = task_states.IMAGE_SNAPSHOT_PENDING
self._test_init_instance_cleans_image_states(instance)
@mock.patch.object(objects.Instance, 'save')
def test_init_instance_cleans_running_pausing(self, mock_save):
instance = self._test_init_instance_cleans_task_states(
power_state.RUNNING, task_states.PAUSING)
mock_save.assert_called_once_with()
self.assertEqual(vm_states.ACTIVE, instance.vm_state)
self.assertIsNone(instance.task_state)
@mock.patch.object(objects.Instance, 'save')
def test_init_instance_cleans_running_unpausing(self, mock_save):
instance = self._test_init_instance_cleans_task_states(
power_state.RUNNING, task_states.UNPAUSING)
mock_save.assert_called_once_with()
self.assertEqual(vm_states.ACTIVE, instance.vm_state)
self.assertIsNone(instance.task_state)
@mock.patch('nova.compute.manager.ComputeManager.unpause_instance')
def test_init_instance_cleans_paused_unpausing(self, mock_unpause):
def fake_unpause(context, instance):
instance.task_state = None
mock_unpause.side_effect = fake_unpause
instance = self._test_init_instance_cleans_task_states(
power_state.PAUSED, task_states.UNPAUSING)
mock_unpause.assert_called_once_with(self.context, instance)
self.assertEqual(vm_states.ACTIVE, instance.vm_state)
self.assertIsNone(instance.task_state)
def test_init_instance_deletes_error_deleting_instance(self):
instance = fake_instance.fake_instance_obj(
self.context,
project_id=fakes.FAKE_PROJECT_ID,
uuid=uuids.instance,
vcpus=1,
memory_mb=64,
vm_state=vm_states.ERROR,
host=self.compute.host,
task_state=task_states.DELETING)
bdms = []
with test.nested(
mock.patch.object(objects.BlockDeviceMappingList,
'get_by_instance_uuid',
return_value=bdms),
mock.patch.object(self.compute, '_delete_instance'),
mock.patch.object(instance, 'obj_load_attr')
) as (mock_get, mock_delete, mock_load):
self.compute._init_instance(self.context, instance)
mock_get.assert_called_once_with(self.context, instance.uuid)
mock_delete.assert_called_once_with(self.context, instance,
bdms)
def test_init_instance_resize_prep(self):
instance = fake_instance.fake_instance_obj(
self.context,
uuid=uuids.instance,
vm_state=vm_states.ACTIVE,
host=self.compute.host,
task_state=task_states.RESIZE_PREP,
power_state=power_state.RUNNING)
with test.nested(
mock.patch.object(self.compute, '_get_power_state',
return_value=power_state.RUNNING),
mock.patch.object(objects.Instance, 'get_network_info'),
mock.patch.object(instance, 'save', autospec=True)
) as (mock_get_power_state, mock_nw_info, mock_instance_save):
self.compute._init_instance(self.context, instance)
mock_instance_save.assert_called_once_with()
self.assertIsNone(instance.task_state)
@mock.patch('nova.context.RequestContext.elevated')
@mock.patch('nova.objects.Instance.get_network_info')
@mock.patch(
'nova.compute.manager.ComputeManager._get_instance_block_device_info')
@mock.patch('nova.virt.driver.ComputeDriver.destroy')
@mock.patch('nova.virt.fake.FakeDriver.get_volume_connector')
@mock.patch('nova.compute.utils.notify_about_instance_action')
@mock.patch(
'nova.compute.manager.ComputeManager._notify_about_instance_usage')
def test_shutdown_instance_versioned_notifications(self,
mock_notify_unversioned, mock_notify, mock_connector,
mock_destroy, mock_blk_device_info, mock_nw_info, mock_elevated):
mock_elevated.return_value = self.context
instance = fake_instance.fake_instance_obj(
self.context,
uuid=uuids.instance,
vm_state=vm_states.ERROR,
task_state=task_states.DELETING)
bdms = [mock.Mock(id=1, is_volume=True)]
self.compute._shutdown_instance(self.context, instance, bdms,
notify=True, try_deallocate_networks=False)
mock_notify.assert_has_calls([
mock.call(self.context, instance, 'fake-mini',
action='shutdown', phase='start', bdms=bdms),
mock.call(self.context, instance, 'fake-mini',
action='shutdown', phase='end', bdms=bdms)])
@mock.patch('nova.context.RequestContext.elevated')
@mock.patch('nova.objects.Instance.get_network_info')
@mock.patch(
'nova.compute.manager.ComputeManager._get_instance_block_device_info')
@mock.patch('nova.virt.driver.ComputeDriver.destroy')
@mock.patch('nova.virt.fake.FakeDriver.get_volume_connector')
def _test_shutdown_instance_exception(self, exc, mock_connector,
mock_destroy, mock_blk_device_info, mock_nw_info, mock_elevated):
mock_connector.side_effect = exc
mock_elevated.return_value = self.context
instance = fake_instance.fake_instance_obj(
self.context,
uuid=uuids.instance,
vm_state=vm_states.ERROR,
task_state=task_states.DELETING)
bdms = [mock.Mock(id=1, is_volume=True)]
self.compute._shutdown_instance(self.context, instance, bdms,
notify=False, try_deallocate_networks=False)
def test_shutdown_instance_endpoint_not_found(self):
exc = cinder_exception.EndpointNotFound
self._test_shutdown_instance_exception(exc)
def test_shutdown_instance_client_exception(self):
exc = cinder_exception.ClientException(code=9001)
self._test_shutdown_instance_exception(exc)
def test_shutdown_instance_volume_not_found(self):
exc = exception.VolumeNotFound(volume_id=42)
self._test_shutdown_instance_exception(exc)
def test_shutdown_instance_disk_not_found(self):
exc = exception.DiskNotFound(location="not\\here")
self._test_shutdown_instance_exception(exc)
def test_shutdown_instance_other_exception(self):
exc = Exception('some other exception')
self._test_shutdown_instance_exception(exc)
def _test_init_instance_retries_reboot(self, instance, reboot_type,
return_power_state):
instance.host = self.compute.host
with test.nested(
mock.patch.object(self.compute, '_get_power_state',
return_value=return_power_state),
mock.patch.object(self.compute, 'reboot_instance'),
mock.patch.object(objects.Instance, 'get_network_info')
) as (
_get_power_state,
reboot_instance,
get_network_info
):
self.compute._init_instance(self.context, instance)
call = mock.call(self.context, instance, block_device_info=None,
reboot_type=reboot_type)
reboot_instance.assert_has_calls([call])
def test_init_instance_retries_reboot_pending(self):
instance = objects.Instance(self.context)
instance.uuid = uuids.instance
instance.task_state = task_states.REBOOT_PENDING
for state in vm_states.ALLOW_SOFT_REBOOT:
instance.vm_state = state
self._test_init_instance_retries_reboot(instance, 'SOFT',
power_state.RUNNING)
def test_init_instance_retries_reboot_pending_hard(self):
instance = objects.Instance(self.context)
instance.uuid = uuids.instance
instance.task_state = task_states.REBOOT_PENDING_HARD
for state in vm_states.ALLOW_HARD_REBOOT:
# NOTE(dave-mcnally) while a reboot of a vm in error state is
# possible we don't attempt to recover an error during init
if state == vm_states.ERROR:
continue
instance.vm_state = state
self._test_init_instance_retries_reboot(instance, 'HARD',
power_state.RUNNING)
def test_init_instance_retries_reboot_pending_soft_became_hard(self):
instance = objects.Instance(self.context)
instance.uuid = uuids.instance
instance.task_state = task_states.REBOOT_PENDING
for state in vm_states.ALLOW_HARD_REBOOT:
# NOTE(dave-mcnally) while a reboot of a vm in error state is
# possible we don't attempt to recover an error during init
if state == vm_states.ERROR:
continue
instance.vm_state = state
with mock.patch.object(instance, 'save'):
self._test_init_instance_retries_reboot(instance, 'HARD',
power_state.SHUTDOWN)
self.assertEqual(task_states.REBOOT_PENDING_HARD,
instance.task_state)
def test_init_instance_retries_reboot_started(self):
instance = objects.Instance(self.context)
instance.uuid = uuids.instance
instance.vm_state = vm_states.ACTIVE
instance.task_state = task_states.REBOOT_STARTED
with mock.patch.object(instance, 'save'):
self._test_init_instance_retries_reboot(instance, 'HARD',
power_state.NOSTATE)
def test_init_instance_retries_reboot_started_hard(self):
instance = objects.Instance(self.context)
instance.uuid = uuids.instance
instance.vm_state = vm_states.ACTIVE
instance.task_state = task_states.REBOOT_STARTED_HARD
self._test_init_instance_retries_reboot(instance, 'HARD',
power_state.NOSTATE)
def _test_init_instance_cleans_reboot_state(self, instance):
instance.host = self.compute.host
with test.nested(
mock.patch.object(self.compute, '_get_power_state',
return_value=power_state.RUNNING),
mock.patch.object(instance, 'save', autospec=True),
mock.patch.object(objects.Instance, 'get_network_info')
) as (
_get_power_state,
instance_save,
get_network_info
):
self.compute._init_instance(self.context, instance)
instance_save.assert_called_once_with()
self.assertIsNone(instance.task_state)
self.assertEqual(vm_states.ACTIVE, instance.vm_state)
def test_init_instance_cleans_image_state_reboot_started(self):
instance = objects.Instance(self.context)
instance.uuid = uuids.instance
instance.vm_state = vm_states.ACTIVE
instance.task_state = task_states.REBOOT_STARTED
instance.power_state = power_state.RUNNING
self._test_init_instance_cleans_reboot_state(instance)
def test_init_instance_cleans_image_state_reboot_started_hard(self):
instance = objects.Instance(self.context)
instance.uuid = uuids.instance
instance.vm_state = vm_states.ACTIVE
instance.task_state = task_states.REBOOT_STARTED_HARD
instance.power_state = power_state.RUNNING
self._test_init_instance_cleans_reboot_state(instance)
def test_init_instance_retries_power_off(self):
instance = objects.Instance(self.context)
instance.uuid = uuids.instance
instance.id = 1
instance.vm_state = vm_states.ACTIVE
instance.task_state = task_states.POWERING_OFF
instance.host = self.compute.host
with mock.patch.object(self.compute, 'stop_instance'):
self.compute._init_instance(self.context, instance)
call = mock.call(self.context, instance, True)
self.compute.stop_instance.assert_has_calls([call])
def test_init_instance_retries_power_on(self):
instance = objects.Instance(self.context)
instance.uuid = uuids.instance
instance.id = 1
instance.vm_state = vm_states.ACTIVE
instance.task_state = task_states.POWERING_ON
instance.host = self.compute.host
with mock.patch.object(self.compute, 'start_instance'):
self.compute._init_instance(self.context, instance)
call = mock.call(self.context, instance)
self.compute.start_instance.assert_has_calls([call])
def test_init_instance_retries_power_on_silent_exception(self):
instance = objects.Instance(self.context)
instance.uuid = uuids.instance
instance.id = 1
instance.vm_state = vm_states.ACTIVE
instance.task_state = task_states.POWERING_ON
instance.host = self.compute.host
with mock.patch.object(self.compute, 'start_instance',
return_value=Exception):
init_return = self.compute._init_instance(self.context, instance)
call = mock.call(self.context, instance)
self.compute.start_instance.assert_has_calls([call])
self.assertIsNone(init_return)
def test_init_instance_retries_power_off_silent_exception(self):
instance = objects.Instance(self.context)
instance.uuid = uuids.instance
instance.id = 1
instance.vm_state = vm_states.ACTIVE
instance.task_state = task_states.POWERING_OFF
instance.host = self.compute.host
with mock.patch.object(self.compute, 'stop_instance',
return_value=Exception):
init_return = self.compute._init_instance(self.context, instance)
call = mock.call(self.context, instance, True)
self.compute.stop_instance.assert_has_calls([call])
self.assertIsNone(init_return)
@mock.patch('nova.objects.InstanceList.get_by_filters')
def test_get_instances_on_driver(self, mock_instance_list):
driver_instances = []
for x in range(10):
driver_instances.append(fake_instance.fake_db_instance())
def _make_instance_list(db_list):
return instance_obj._make_instance_list(
self.context, objects.InstanceList(), db_list, None)
driver_uuids = [inst['uuid'] for inst in driver_instances]
mock_instance_list.return_value = _make_instance_list(driver_instances)
with mock.patch.object(self.compute.driver,
'list_instance_uuids') as mock_driver_uuids:
mock_driver_uuids.return_value = driver_uuids
result = self.compute._get_instances_on_driver(self.context)
self.assertEqual([x['uuid'] for x in driver_instances],
[x['uuid'] for x in result])
expected_filters = {'uuid': driver_uuids}
mock_instance_list.assert_called_with(self.context, expected_filters,
use_slave=True)
@mock.patch('nova.objects.InstanceList.get_by_filters')
def test_get_instances_on_driver_empty(self, mock_instance_list):
with mock.patch.object(self.compute.driver,
'list_instance_uuids') as mock_driver_uuids:
mock_driver_uuids.return_value = []
result = self.compute._get_instances_on_driver(self.context)
# Short circuit DB call, get_by_filters should not be called
self.assertEqual(0, mock_instance_list.call_count)
self.assertEqual(1, mock_driver_uuids.call_count)
self.assertEqual([], [x['uuid'] for x in result])
@mock.patch('nova.objects.InstanceList.get_by_filters')
def test_get_instances_on_driver_fallback(self, mock_instance_list):
# Test getting instances when driver doesn't support
# 'list_instance_uuids'
self.compute.host = 'host'
filters = {}
self.flags(instance_name_template='inst-%i')
all_instances = []
driver_instances = []
for x in range(10):
instance = fake_instance.fake_db_instance(name='inst-%i' % x,
id=x)
if x % 2:
driver_instances.append(instance)
all_instances.append(instance)
def _make_instance_list(db_list):
return instance_obj._make_instance_list(
self.context, objects.InstanceList(), db_list, None)
driver_instance_names = [inst['name'] for inst in driver_instances]
mock_instance_list.return_value = _make_instance_list(all_instances)
with test.nested(
mock.patch.object(self.compute.driver, 'list_instance_uuids'),
mock.patch.object(self.compute.driver, 'list_instances')
) as (
mock_driver_uuids,
mock_driver_instances
):
mock_driver_uuids.side_effect = NotImplementedError()
mock_driver_instances.return_value = driver_instance_names
result = self.compute._get_instances_on_driver(self.context,
filters)
self.assertEqual([x['uuid'] for x in driver_instances],
[x['uuid'] for x in result])
expected_filters = {'host': self.compute.host}
mock_instance_list.assert_called_with(self.context, expected_filters,
use_slave=True)
def test_instance_usage_audit(self):
instances = [objects.Instance(uuid=uuids.instance)]
def fake_task_log(*a, **k):
pass
def fake_get(*a, **k):
return instances
self.flags(instance_usage_audit=True)
with test.nested(
mock.patch.object(objects.TaskLog, 'get',
side_effect=fake_task_log),
mock.patch.object(objects.InstanceList,
'get_active_by_window_joined',
side_effect=fake_get),
mock.patch.object(objects.TaskLog, 'begin_task',
side_effect=fake_task_log),
mock.patch.object(objects.TaskLog, 'end_task',
side_effect=fake_task_log),
mock.patch.object(compute_utils, 'notify_usage_exists')
) as (mock_get, mock_get_active, mock_begin, mock_end, mock_notify):
self.compute._instance_usage_audit(self.context)
mock_notify.assert_called_once_with(self.compute.notifier,
self.context, instances[0], ignore_missing_network_data=False)
self.assertTrue(mock_get.called)
self.assertTrue(mock_get_active.called)
self.assertTrue(mock_begin.called)
self.assertTrue(mock_end.called)
@mock.patch.object(objects.InstanceList, 'get_by_host')
def test_sync_power_states(self, mock_get):
instance = mock.Mock()
mock_get.return_value = [instance]
with mock.patch.object(self.compute._sync_power_pool,
'spawn_n') as mock_spawn:
self.compute._sync_power_states(mock.sentinel.context)
mock_get.assert_called_with(mock.sentinel.context,
self.compute.host, expected_attrs=[],
use_slave=True)
mock_spawn.assert_called_once_with(mock.ANY, instance)
def _get_sync_instance(self, power_state, vm_state, task_state=None,
shutdown_terminate=False):
instance = objects.Instance()
instance.uuid = uuids.instance
instance.power_state = power_state
instance.vm_state = vm_state
instance.host = self.compute.host
instance.task_state = task_state
instance.shutdown_terminate = shutdown_terminate
return instance
@mock.patch.object(objects.Instance, 'refresh')
def test_sync_instance_power_state_match(self, mock_refresh):
instance = self._get_sync_instance(power_state.RUNNING,
vm_states.ACTIVE)
self.compute._sync_instance_power_state(self.context, instance,
power_state.RUNNING)
mock_refresh.assert_called_once_with(use_slave=False)
@mock.patch.object(objects.Instance, 'refresh')
@mock.patch.object(objects.Instance, 'save')
def test_sync_instance_power_state_running_stopped(self, mock_save,
mock_refresh):
instance = self._get_sync_instance(power_state.RUNNING,
vm_states.ACTIVE)
self.compute._sync_instance_power_state(self.context, instance,
power_state.SHUTDOWN)
self.assertEqual(instance.power_state, power_state.SHUTDOWN)
mock_refresh.assert_called_once_with(use_slave=False)
self.assertTrue(mock_save.called)
def _test_sync_to_stop(self, power_state, vm_state, driver_power_state,
stop=True, force=False, shutdown_terminate=False):
instance = self._get_sync_instance(
power_state, vm_state, shutdown_terminate=shutdown_terminate)
with test.nested(
mock.patch.object(objects.Instance, 'refresh'),
mock.patch.object(objects.Instance, 'save'),
mock.patch.object(self.compute.compute_api, 'stop'),
mock.patch.object(self.compute.compute_api, 'delete'),
mock.patch.object(self.compute.compute_api, 'force_stop'),
) as (mock_refresh, mock_save, mock_stop, mock_delete, mock_force):
self.compute._sync_instance_power_state(self.context, instance,
driver_power_state)
if shutdown_terminate:
mock_delete.assert_called_once_with(self.context, instance)
elif stop:
if force:
mock_force.assert_called_once_with(self.context, instance)
else:
mock_stop.assert_called_once_with(self.context, instance)
mock_refresh.assert_called_once_with(use_slave=False)
self.assertTrue(mock_save.called)
def test_sync_instance_power_state_to_stop(self):
for ps in (power_state.SHUTDOWN, power_state.CRASHED,
power_state.SUSPENDED):
self._test_sync_to_stop(power_state.RUNNING, vm_states.ACTIVE, ps)
for ps in (power_state.SHUTDOWN, power_state.CRASHED):
self._test_sync_to_stop(power_state.PAUSED, vm_states.PAUSED, ps,
force=True)
self._test_sync_to_stop(power_state.SHUTDOWN, vm_states.STOPPED,
power_state.RUNNING, force=True)
def test_sync_instance_power_state_to_terminate(self):
self._test_sync_to_stop(power_state.RUNNING, vm_states.ACTIVE,
power_state.SHUTDOWN,
force=False, shutdown_terminate=True)
def test_sync_instance_power_state_to_no_stop(self):
for ps in (power_state.PAUSED, power_state.NOSTATE):
self._test_sync_to_stop(power_state.RUNNING, vm_states.ACTIVE, ps,
stop=False)
for vs in (vm_states.SOFT_DELETED, vm_states.DELETED):
for ps in (power_state.NOSTATE, power_state.SHUTDOWN):
self._test_sync_to_stop(power_state.RUNNING, vs, ps,
stop=False)
@mock.patch('nova.compute.manager.ComputeManager.'
'_sync_instance_power_state')
def test_query_driver_power_state_and_sync_pending_task(
self, mock_sync_power_state):
with mock.patch.object(self.compute.driver,
'get_info') as mock_get_info:
db_instance = objects.Instance(uuid=uuids.db_instance,
task_state=task_states.POWERING_OFF)
self.compute._query_driver_power_state_and_sync(self.context,
db_instance)
self.assertFalse(mock_get_info.called)
self.assertFalse(mock_sync_power_state.called)
@mock.patch('nova.compute.manager.ComputeManager.'
'_sync_instance_power_state')
def test_query_driver_power_state_and_sync_not_found_driver(
self, mock_sync_power_state):
error = exception.InstanceNotFound(instance_id=1)
with mock.patch.object(self.compute.driver,
'get_info', side_effect=error) as mock_get_info:
db_instance = objects.Instance(uuid=uuids.db_instance,
task_state=None)
self.compute._query_driver_power_state_and_sync(self.context,
db_instance)
mock_get_info.assert_called_once_with(db_instance)
mock_sync_power_state.assert_called_once_with(self.context,
db_instance,
power_state.NOSTATE,
use_slave=True)
@mock.patch.object(virt_driver.ComputeDriver, 'delete_instance_files')
@mock.patch.object(objects.InstanceList, 'get_by_filters')
def test_run_pending_deletes(self, mock_get, mock_delete):
self.flags(instance_delete_interval=10)
class FakeInstance(object):
def __init__(self, uuid, name, smd):
self.uuid = uuid
self.name = name
self.system_metadata = smd
self.cleaned = False
def __getitem__(self, name):
return getattr(self, name)
def save(self):
pass
def _fake_get(ctx, filter, expected_attrs, use_slave):
mock_get.assert_called_once_with(
{'read_deleted': 'yes'},
{'deleted': True, 'soft_deleted': False, 'host': 'fake-mini',
'cleaned': False},
expected_attrs=['system_metadata'],
use_slave=True)
return [a, b, c]
a = FakeInstance('123', 'apple', {'clean_attempts': '100'})
b = FakeInstance('456', 'orange', {'clean_attempts': '3'})
c = FakeInstance('789', 'banana', {})
mock_get.side_effect = _fake_get
mock_delete.side_effect = [True, False]
self.compute._run_pending_deletes({})
self.assertFalse(a.cleaned)
self.assertEqual('100', a.system_metadata['clean_attempts'])
self.assertTrue(b.cleaned)
self.assertEqual('4', b.system_metadata['clean_attempts'])
self.assertFalse(c.cleaned)
self.assertEqual('1', c.system_metadata['clean_attempts'])
mock_delete.assert_has_calls([mock.call(mock.ANY),
mock.call(mock.ANY)])
@mock.patch.object(objects.Migration, 'obj_as_admin')
@mock.patch.object(objects.Migration, 'save')
@mock.patch.object(objects.MigrationList, 'get_by_filters')
@mock.patch.object(objects.InstanceList, 'get_by_filters')
def _test_cleanup_incomplete_migrations(self, inst_host,
mock_inst_get_by_filters,
mock_migration_get_by_filters,
mock_save, mock_obj_as_admin):
def fake_inst(context, uuid, host):
inst = objects.Instance(context)
inst.uuid = uuid
inst.host = host
return inst
def fake_migration(uuid, status, inst_uuid, src_host, dest_host):
migration = objects.Migration()
migration.uuid = uuid
migration.status = status
migration.instance_uuid = inst_uuid
migration.source_compute = src_host
migration.dest_compute = dest_host
return migration
fake_instances = [fake_inst(self.context, uuids.instance_1, inst_host),
fake_inst(self.context, uuids.instance_2, inst_host)]
fake_migrations = [fake_migration('123', 'error',
uuids.instance_1,
'fake-host', 'fake-mini'),
fake_migration('456', 'error',
uuids.instance_2,
'fake-host', 'fake-mini')]
mock_migration_get_by_filters.return_value = fake_migrations
mock_inst_get_by_filters.return_value = fake_instances
with mock.patch.object(self.compute.driver, 'delete_instance_files'):
self.compute._cleanup_incomplete_migrations(self.context)
# Ensure that migration status is set to 'failed' after instance
# files deletion for those instances whose instance.host is not
# same as compute host where periodic task is running.
for inst in fake_instances:
if inst.host != CONF.host:
for mig in fake_migrations:
if inst.uuid == mig.instance_uuid:
self.assertEqual('failed', mig.status)
def test_cleanup_incomplete_migrations_dest_node(self):
"""Test to ensure instance files are deleted from destination node.
If instance gets deleted during resizing/revert-resizing operation,
in that case instance files gets deleted from instance.host (source
host here), but there is possibility that instance files could be
present on destination node.
This test ensures that `_cleanup_incomplete_migration` periodic
task deletes orphaned instance files from destination compute node.
"""
self.flags(host='fake-mini')
self._test_cleanup_incomplete_migrations('fake-host')
def test_cleanup_incomplete_migrations_source_node(self):
"""Test to ensure instance files are deleted from source node.
If instance gets deleted during resizing/revert-resizing operation,
in that case instance files gets deleted from instance.host (dest
host here), but there is possibility that instance files could be
present on source node.
This test ensures that `_cleanup_incomplete_migration` periodic
task deletes orphaned instance files from source compute node.
"""
self.flags(host='fake-host')
self._test_cleanup_incomplete_migrations('fake-mini')
def test_attach_interface_failure(self):
# Test that the fault methods are invoked when an attach fails
db_instance = fake_instance.fake_db_instance()
f_instance = objects.Instance._from_db_object(self.context,
objects.Instance(),
db_instance)
e = exception.InterfaceAttachFailed(instance_uuid=f_instance.uuid)
@mock.patch.object(compute_utils, 'EventReporter')
@mock.patch.object(compute_utils, 'notify_about_instance_action')
@mock.patch.object(compute_utils, 'add_instance_fault_from_exc')
@mock.patch.object(self.compute.network_api,
'allocate_port_for_instance',
side_effect=e)
@mock.patch.object(self.compute, '_instance_update',
side_effect=lambda *a, **k: {})
def do_test(update, meth, add_fault, notify, event):
self.assertRaises(exception.InterfaceAttachFailed,
self.compute.attach_interface,
self.context, f_instance, 'net_id', 'port_id',
None)
add_fault.assert_has_calls([
mock.call(self.context, f_instance, e,
mock.ANY)])
event.assert_called_once_with(
self.context, 'compute_attach_interface',
f_instance.uuid)
with mock.patch.dict(self.compute.driver.capabilities,
supports_attach_interface=True):
do_test()
def test_detach_interface_failure(self):
# Test that the fault methods are invoked when a detach fails
# Build test data that will cause a PortNotFound exception
nw_info = network_model.NetworkInfo([])
info_cache = objects.InstanceInfoCache(network_info=nw_info,
instance_uuid=uuids.instance)
f_instance = objects.Instance(id=3, uuid=uuids.instance,
info_cache=info_cache)
@mock.patch.object(compute_utils, 'EventReporter')
@mock.patch.object(compute_utils, 'add_instance_fault_from_exc')
@mock.patch.object(self.compute, '_set_instance_obj_error_state')
def do_test(meth, add_fault, event):
self.assertRaises(exception.PortNotFound,
self.compute.detach_interface,
self.context, f_instance, 'port_id')
add_fault.assert_has_calls(
[mock.call(self.context, f_instance, mock.ANY, mock.ANY)])
event.assert_called_once_with(
self.context, 'compute_detach_interface',
f_instance.uuid)
do_test()
@mock.patch.object(compute_utils, 'EventReporter')
@mock.patch.object(virt_driver.ComputeDriver, 'get_volume_connector',
return_value={})
@mock.patch.object(manager.ComputeManager, '_instance_update',
return_value={})
@mock.patch.object(db, 'instance_fault_create')
@mock.patch.object(db, 'block_device_mapping_update')
@mock.patch.object(db,
'block_device_mapping_get_by_instance_and_volume_id')
@mock.patch.object(cinder.API, 'migrate_volume_completion')
@mock.patch.object(cinder.API, 'terminate_connection')
@mock.patch.object(cinder.API, 'unreserve_volume')
@mock.patch.object(cinder.API, 'get')
@mock.patch.object(cinder.API, 'roll_detaching')
@mock.patch.object(compute_utils, 'notify_about_volume_swap')
def _test_swap_volume(self, mock_notify, mock_roll_detaching,
mock_cinder_get, mock_unreserve_volume,
mock_terminate_connection,
mock_migrate_volume_completion,
mock_bdm_get, mock_bdm_update,
mock_instance_fault_create,
mock_instance_update,
mock_get_volume_connector,
mock_event,
expected_exception=None):
# This test ensures that volume_id arguments are passed to volume_api
# and that volume states are OK
volumes = {}
volumes[uuids.old_volume] = {'id': uuids.old_volume,
'display_name': 'old_volume',
'status': 'detaching',
'size': 1}
volumes[uuids.new_volume] = {'id': uuids.new_volume,
'display_name': 'new_volume',
'status': 'available',
'size': 2}
fake_bdm = fake_block_device.FakeDbBlockDeviceDict(
{'device_name': '/dev/vdb', 'source_type': 'volume',
'destination_type': 'volume',
'instance_uuid': uuids.instance,
'connection_info': '{"foo": "bar"}',
'volume_id': uuids.old_volume,
'attachment_id': None})
def fake_vol_api_roll_detaching(context, volume_id):
self.assertTrue(uuidutils.is_uuid_like(volume_id))
if volumes[volume_id]['status'] == 'detaching':
volumes[volume_id]['status'] = 'in-use'
def fake_vol_api_func(context, volume, *args):
self.assertTrue(uuidutils.is_uuid_like(volume))
return {}
def fake_vol_get(context, volume_id):
self.assertTrue(uuidutils.is_uuid_like(volume_id))
return volumes[volume_id]
def fake_vol_unreserve(context, volume_id):
self.assertTrue(uuidutils.is_uuid_like(volume_id))
if volumes[volume_id]['status'] == 'attaching':
volumes[volume_id]['status'] = 'available'
def fake_vol_migrate_volume_completion(context, old_volume_id,
new_volume_id, error=False):
self.assertTrue(uuidutils.is_uuid_like(old_volume_id))
self.assertTrue(uuidutils.is_uuid_like(new_volume_id))
volumes[old_volume_id]['status'] = 'in-use'
return {'save_volume_id': new_volume_id}
def fake_block_device_mapping_update(ctxt, id, updates, legacy):
self.assertEqual(2, updates['volume_size'])
return fake_bdm
mock_roll_detaching.side_effect = fake_vol_api_roll_detaching
mock_terminate_connection.side_effect = fake_vol_api_func
mock_cinder_get.side_effect = fake_vol_get
mock_migrate_volume_completion.side_effect = (
fake_vol_migrate_volume_completion)
mock_unreserve_volume.side_effect = fake_vol_unreserve
mock_bdm_get.return_value = fake_bdm
mock_bdm_update.side_effect = fake_block_device_mapping_update
mock_instance_fault_create.return_value = (
test_instance_fault.fake_faults['fake-uuid'][0])
instance1 = fake_instance.fake_instance_obj(
self.context, **{'uuid': uuids.instance})
if expected_exception:
volumes[uuids.old_volume]['status'] = 'detaching'
volumes[uuids.new_volume]['status'] = 'attaching'
self.assertRaises(expected_exception, self.compute.swap_volume,
self.context, uuids.old_volume, uuids.new_volume,
instance1)
self.assertEqual('in-use', volumes[uuids.old_volume]['status'])
self.assertEqual('available', volumes[uuids.new_volume]['status'])
self.assertEqual(2, mock_notify.call_count)
mock_notify.assert_any_call(
test.MatchType(context.RequestContext), instance1,
self.compute.host,
fields.NotificationAction.VOLUME_SWAP,
fields.NotificationPhase.START,
uuids.old_volume, uuids.new_volume)
mock_notify.assert_any_call(
test.MatchType(context.RequestContext), instance1,
self.compute.host,
fields.NotificationAction.VOLUME_SWAP,
fields.NotificationPhase.ERROR,
uuids.old_volume, uuids.new_volume,
test.MatchType(expected_exception))
else:
self.compute.swap_volume(self.context, uuids.old_volume,
uuids.new_volume, instance1)
self.assertEqual(volumes[uuids.old_volume]['status'], 'in-use')
self.assertEqual(2, mock_notify.call_count)
mock_notify.assert_any_call(test.MatchType(context.RequestContext),
instance1, self.compute.host,
fields.NotificationAction.VOLUME_SWAP,
fields.NotificationPhase.START,
uuids.old_volume, uuids.new_volume)
mock_notify.assert_any_call(test.MatchType(context.RequestContext),
instance1, self.compute.host,
fields.NotificationAction.VOLUME_SWAP,
fields.NotificationPhase.END,
uuids.old_volume, uuids.new_volume)
mock_event.assert_called_once_with(self.context,
'compute_swap_volume',
instance1.uuid)
def _assert_volume_api(self, context, volume, *args):
self.assertTrue(uuidutils.is_uuid_like(volume))
return {}
def _assert_swap_volume(self, context, old_connection_info,
new_connection_info, instance, mountpoint,
resize_to):
self.assertEqual(2, resize_to)
@mock.patch.object(cinder.API, 'initialize_connection')
@mock.patch.object(fake_driver.FakeDriver, 'swap_volume')
def test_swap_volume_volume_api_usage(self, mock_swap_volume,
mock_initialize_connection):
mock_initialize_connection.side_effect = self._assert_volume_api
mock_swap_volume.side_effect = self._assert_swap_volume
self._test_swap_volume()
@mock.patch.object(cinder.API, 'initialize_connection')
@mock.patch.object(fake_driver.FakeDriver, 'swap_volume',
side_effect=test.TestingException())
def test_swap_volume_with_compute_driver_exception(
self, mock_swap_volume, mock_initialize_connection):
mock_initialize_connection.side_effect = self._assert_volume_api
self._test_swap_volume(expected_exception=test.TestingException)
@mock.patch.object(cinder.API, 'initialize_connection',
side_effect=test.TestingException())
@mock.patch.object(fake_driver.FakeDriver, 'swap_volume')
def test_swap_volume_with_initialize_connection_exception(
self, mock_swap_volume, mock_initialize_connection):
self._test_swap_volume(expected_exception=test.TestingException)
@mock.patch('nova.compute.utils.notify_about_volume_swap')
@mock.patch('nova.db.block_device_mapping_get_by_instance_and_volume_id')
@mock.patch('nova.db.block_device_mapping_update')
@mock.patch('nova.volume.cinder.API.get')
@mock.patch('nova.virt.libvirt.LibvirtDriver.get_volume_connector')
@mock.patch('nova.compute.manager.ComputeManager._swap_volume')
def test_swap_volume_delete_on_termination_flag(self, swap_volume_mock,
volume_connector_mock,
get_volume_mock,
update_bdm_mock,
get_bdm_mock,
notify_mock):
# This test ensures that delete_on_termination flag arguments
# are reserved
volumes = {}
old_volume_id = uuids.fake
volumes[old_volume_id] = {'id': old_volume_id,
'display_name': 'old_volume',
'status': 'detaching',
'size': 2}
new_volume_id = uuids.fake_2
volumes[new_volume_id] = {'id': new_volume_id,
'display_name': 'new_volume',
'status': 'available',
'size': 2}
fake_bdm = fake_block_device.FakeDbBlockDeviceDict(
{'device_name': '/dev/vdb', 'source_type': 'volume',
'destination_type':