"Fossies" - the Fresh Open Source Software Archive

Member "nova-18.2.3/nova/tests/unit/virt/ironic/test_driver.py" (10 Oct 2019, 184240 Bytes) of package /linux/misc/openstack/nova-18.2.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "test_driver.py": 18.2.2_vs_18.2.3.

    1 # Copyright 2015 Red Hat, Inc.
    2 # Copyright 2013 Hewlett-Packard Development Company, L.P.
    3 #
    4 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    5 #    not use this file except in compliance with the License. You may obtain
    6 #    a copy of the License at
    7 #
    8 #         http://www.apache.org/licenses/LICENSE-2.0
    9 #
   10 #    Unless required by applicable law or agreed to in writing, software
   11 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   12 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   13 #    License for the specific language governing permissions and limitations
   14 #    under the License.
   15 
   16 """Tests for the ironic driver."""
   17 
   18 from ironicclient import exc as ironic_exception
   19 import mock
   20 from oslo_config import cfg
   21 from oslo_service import loopingcall
   22 from oslo_utils import uuidutils
   23 import six
   24 from testtools import matchers
   25 from tooz import hashring as hash_ring
   26 
   27 from nova.api.metadata import base as instance_metadata
   28 from nova import block_device
   29 from nova.compute import power_state as nova_states
   30 from nova.compute import provider_tree
   31 from nova.compute import task_states
   32 from nova.compute import vm_states
   33 from nova.console import type as console_type
   34 from nova import context as nova_context
   35 from nova import exception
   36 from nova.network import model as network_model
   37 from nova import objects
   38 from nova import rc_fields as fields
   39 from nova import servicegroup
   40 from nova import test
   41 from nova.tests import fixtures
   42 from nova.tests.unit import fake_block_device
   43 from nova.tests.unit import fake_instance
   44 from nova.tests.unit import matchers as nova_matchers
   45 from nova.tests.unit import utils
   46 from nova.tests.unit.virt.ironic import utils as ironic_utils
   47 from nova.tests import uuidsentinel as uuids
   48 from nova.virt import block_device as driver_block_device
   49 from nova.virt import configdrive
   50 from nova.virt import driver
   51 from nova.virt import fake
   52 from nova.virt import firewall
   53 from nova.virt import hardware
   54 from nova.virt.ironic import client_wrapper as cw
   55 from nova.virt.ironic import driver as ironic_driver
   56 from nova.virt.ironic import ironic_states
   57 
   58 
   59 CONF = cfg.CONF
   60 
   61 FAKE_CLIENT = ironic_utils.FakeClient()
   62 
   63 SENTINEL = object()
   64 
   65 
   66 class FakeClientWrapper(cw.IronicClientWrapper):
   67     def _get_client(self, retry_on_conflict=True):
   68         return FAKE_CLIENT
   69 
   70 
   71 class FakeLoopingCall(object):
   72     def __init__(self):
   73         self.wait = mock.MagicMock()
   74         self.start = mock.MagicMock()
   75         self.start.return_value = self
   76 
   77 
   78 def _get_properties():
   79     return {'cpus': 2,
   80             'memory_mb': 512,
   81             'local_gb': 10,
   82             'cpu_arch': 'x86_64',
   83             'capabilities': None}
   84 
   85 
   86 def _get_instance_info():
   87     return {'vcpus': 1,
   88             'memory_mb': 1024,
   89             'local_gb': 10}
   90 
   91 
   92 def _get_stats():
   93     return {'cpu_arch': 'x86_64'}
   94 
   95 
   96 def _get_cached_node(**kw):
   97     """Return a fake node object representative of objects in the cache."""
   98     return ironic_utils.get_test_node(fields=ironic_driver._NODE_FIELDS, **kw)
   99 
  100 
  101 def _make_compute_service(hostname):
  102     return objects.Service(host=hostname)
  103 
  104 
  105 FAKE_CLIENT_WRAPPER = FakeClientWrapper()
  106 
  107 
  108 @mock.patch.object(cw, 'IronicClientWrapper', lambda *_: FAKE_CLIENT_WRAPPER)
  109 class IronicDriverTestCase(test.NoDBTestCase):
  110 
  111     @mock.patch.object(cw, 'IronicClientWrapper',
  112                        lambda *_: FAKE_CLIENT_WRAPPER)
  113     @mock.patch.object(ironic_driver.IronicDriver, '_refresh_hash_ring')
  114     @mock.patch.object(servicegroup, 'API', autospec=True)
  115     def setUp(self, mock_sg, mock_hash):
  116         super(IronicDriverTestCase, self).setUp()
  117 
  118         self.driver = ironic_driver.IronicDriver(None)
  119         self.driver.virtapi = fake.FakeVirtAPI()
  120         self.ctx = nova_context.get_admin_context()
  121         self.instance_uuid = uuidutils.generate_uuid()
  122 
  123         self.ptree = provider_tree.ProviderTree()
  124         self.ptree.new_root(mock.sentinel.nodename, mock.sentinel.nodename)
  125 
  126         # mock retries configs to avoid sleeps and make tests run quicker
  127         CONF.set_default('api_max_retries', default=1, group='ironic')
  128         CONF.set_default('api_retry_interval', default=0, group='ironic')
  129 
  130     def test_public_api_signatures(self):
  131         self.assertPublicAPISignatures(driver.ComputeDriver(None), self.driver)
  132 
  133     def test_validate_driver_loading(self):
  134         self.assertIsInstance(self.driver, ironic_driver.IronicDriver)
  135 
  136     def test_driver_capabilities(self):
  137         self.assertFalse(self.driver.capabilities['has_imagecache'],
  138                          'Driver capabilities for \'has_imagecache\''
  139                          'is invalid')
  140         self.assertFalse(self.driver.capabilities['supports_evacuate'],
  141                          'Driver capabilities for \'supports_evacuate\''
  142                          'is invalid')
  143         self.assertFalse(self.driver.capabilities[
  144                              'supports_migrate_to_same_host'],
  145                          'Driver capabilities for '
  146                          '\'supports_migrate_to_same_host\' is invalid')
  147         self.assertTrue(self.driver.requires_allocation_refresh,
  148                         'Driver requires allocation refresh')
  149 
  150     def test__get_hypervisor_type(self):
  151         self.assertEqual('ironic', self.driver._get_hypervisor_type())
  152 
  153     def test__get_hypervisor_version(self):
  154         self.assertEqual(1, self.driver._get_hypervisor_version())
  155 
  156     @mock.patch.object(FAKE_CLIENT.node, 'get_by_instance_uuid')
  157     def test__validate_instance_and_node(self, mock_gbiui):
  158         node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
  159         node = _get_cached_node(
  160                 uuid=node_uuid, instance_uuid=self.instance_uuid)
  161         instance = fake_instance.fake_instance_obj(self.ctx,
  162                                                    uuid=self.instance_uuid)
  163         mock_gbiui.return_value = node
  164         result = self.driver._validate_instance_and_node(instance)
  165         self.assertEqual(result.uuid, node_uuid)
  166         mock_gbiui.assert_called_once_with(instance.uuid,
  167                                            fields=ironic_driver._NODE_FIELDS)
  168 
  169     @mock.patch.object(FAKE_CLIENT.node, 'get_by_instance_uuid')
  170     def test__validate_instance_and_node_failed(self, mock_gbiui):
  171         mock_gbiui.side_effect = ironic_exception.NotFound()
  172         instance = fake_instance.fake_instance_obj(self.ctx,
  173                                                    uuid=self.instance_uuid)
  174         self.assertRaises(exception.InstanceNotFound,
  175                           self.driver._validate_instance_and_node, instance)
  176         mock_gbiui.assert_called_once_with(instance.uuid,
  177                                            fields=ironic_driver._NODE_FIELDS)
  178 
  179     @mock.patch.object(objects.Instance, 'refresh')
  180     @mock.patch.object(ironic_driver.IronicDriver,
  181                        '_validate_instance_and_node')
  182     def test__wait_for_active_pass(self, fake_validate, fake_refresh):
  183         instance = fake_instance.fake_instance_obj(self.ctx,
  184                 uuid=uuidutils.generate_uuid())
  185         node = _get_cached_node(provision_state=ironic_states.DEPLOYING)
  186 
  187         fake_validate.return_value = node
  188         self.driver._wait_for_active(instance)
  189         fake_validate.assert_called_once_with(instance)
  190         fake_refresh.assert_called_once_with()
  191 
  192     @mock.patch.object(objects.Instance, 'refresh')
  193     @mock.patch.object(ironic_driver.IronicDriver,
  194                        '_validate_instance_and_node')
  195     def test__wait_for_active_done(self, fake_validate, fake_refresh):
  196         instance = fake_instance.fake_instance_obj(self.ctx,
  197                 uuid=uuidutils.generate_uuid())
  198         node = _get_cached_node(provision_state=ironic_states.ACTIVE)
  199 
  200         fake_validate.return_value = node
  201         self.assertRaises(loopingcall.LoopingCallDone,
  202                 self.driver._wait_for_active, instance)
  203         fake_validate.assert_called_once_with(instance)
  204         fake_refresh.assert_called_once_with()
  205 
  206     @mock.patch.object(objects.Instance, 'refresh')
  207     @mock.patch.object(ironic_driver.IronicDriver,
  208                        '_validate_instance_and_node')
  209     def test__wait_for_active_from_error(self, fake_validate, fake_refresh):
  210         instance = fake_instance.fake_instance_obj(self.ctx,
  211                 uuid=uuidutils.generate_uuid(),
  212                 vm_state=vm_states.ERROR,
  213                 task_state=task_states.REBUILD_SPAWNING)
  214         node = ironic_utils.get_test_node(
  215                 provision_state=ironic_states.ACTIVE)
  216 
  217         fake_validate.return_value = node
  218         self.assertRaises(loopingcall.LoopingCallDone,
  219                 self.driver._wait_for_active, instance)
  220         fake_validate.assert_called_once_with(instance)
  221         fake_refresh.assert_called_once_with()
  222 
  223     @mock.patch.object(objects.Instance, 'refresh')
  224     @mock.patch.object(ironic_driver.IronicDriver,
  225                        '_validate_instance_and_node')
  226     def test__wait_for_active_fail(self, fake_validate, fake_refresh):
  227         instance = fake_instance.fake_instance_obj(self.ctx,
  228                 uuid=uuidutils.generate_uuid())
  229         node = _get_cached_node(provision_state=ironic_states.DEPLOYFAIL)
  230 
  231         fake_validate.return_value = node
  232         self.assertRaises(exception.InstanceDeployFailure,
  233                 self.driver._wait_for_active, instance)
  234         fake_validate.assert_called_once_with(instance)
  235         fake_refresh.assert_called_once_with()
  236 
  237     @mock.patch.object(objects.Instance, 'refresh')
  238     @mock.patch.object(ironic_driver.IronicDriver,
  239                        '_validate_instance_and_node')
  240     def _wait_for_active_abort(self, instance_params, fake_validate,
  241                               fake_refresh):
  242         instance = fake_instance.fake_instance_obj(self.ctx,
  243                 uuid=uuidutils.generate_uuid(),
  244                 **instance_params)
  245         self.assertRaises(exception.InstanceDeployFailure,
  246                 self.driver._wait_for_active, instance)
  247         # Assert _validate_instance_and_node wasn't called
  248         self.assertFalse(fake_validate.called)
  249         fake_refresh.assert_called_once_with()
  250 
  251     def test__wait_for_active_abort_deleting(self):
  252         self._wait_for_active_abort({'task_state': task_states.DELETING})
  253 
  254     def test__wait_for_active_abort_deleted(self):
  255         self._wait_for_active_abort({'vm_state': vm_states.DELETED})
  256 
  257     def test__wait_for_active_abort_error(self):
  258         self._wait_for_active_abort({'task_state': task_states.SPAWNING,
  259                                      'vm_state': vm_states.ERROR})
  260 
  261     @mock.patch.object(ironic_driver.IronicDriver,
  262                        '_validate_instance_and_node')
  263     def test__wait_for_power_state_pass(self, fake_validate):
  264         instance = fake_instance.fake_instance_obj(self.ctx,
  265                 uuid=uuidutils.generate_uuid())
  266         node = _get_cached_node(target_power_state=ironic_states.POWER_OFF)
  267 
  268         fake_validate.return_value = node
  269         self.driver._wait_for_power_state(instance, 'fake message')
  270         self.assertTrue(fake_validate.called)
  271 
  272     @mock.patch.object(ironic_driver.IronicDriver,
  273                        '_validate_instance_and_node')
  274     def test__wait_for_power_state_ok(self, fake_validate):
  275         instance = fake_instance.fake_instance_obj(self.ctx,
  276                 uuid=uuidutils.generate_uuid())
  277         node = _get_cached_node(target_power_state=ironic_states.NOSTATE)
  278 
  279         fake_validate.return_value = node
  280         self.assertRaises(loopingcall.LoopingCallDone,
  281                 self.driver._wait_for_power_state, instance, 'fake message')
  282         self.assertTrue(fake_validate.called)
  283 
  284     def test__node_resource_with_instance_uuid(self):
  285         node_uuid = uuidutils.generate_uuid()
  286         props = _get_properties()
  287         stats = _get_stats()
  288         node = _get_cached_node(
  289                 uuid=node_uuid, instance_uuid=self.instance_uuid,
  290                 properties=props, resource_class='foo')
  291 
  292         result = self.driver._node_resource(node)
  293 
  294         wantkeys = ["uuid", "hypervisor_hostname", "hypervisor_type",
  295                     "hypervisor_version", "cpu_info",
  296                     "vcpus", "vcpus_used",
  297                     "memory_mb", "memory_mb_used",
  298                     "local_gb", "local_gb_used",
  299                     "disk_available_least",
  300                     "supported_instances",
  301                     "stats",
  302                     "numa_topology", "resource_class"]
  303         wantkeys.sort()
  304         gotkeys = sorted(result.keys())
  305         self.assertEqual(wantkeys, gotkeys)
  306 
  307         self.assertEqual(props['cpus'], result['vcpus'])
  308         self.assertEqual(result['vcpus'], result['vcpus_used'])
  309         self.assertEqual(props['memory_mb'], result['memory_mb'])
  310         self.assertEqual(result['memory_mb'], result['memory_mb_used'])
  311         self.assertEqual(props['local_gb'], result['local_gb'])
  312         self.assertEqual(result['local_gb'], result['local_gb_used'])
  313         self.assertEqual(node_uuid, result['uuid'])
  314         self.assertEqual(node_uuid, result['hypervisor_hostname'])
  315         self.assertEqual(stats, result['stats'])
  316         self.assertEqual('foo', result['resource_class'])
  317         self.assertIsNone(result['numa_topology'])
  318 
  319     def test__node_resource_canonicalizes_arch(self):
  320         node_uuid = uuidutils.generate_uuid()
  321         props = _get_properties()
  322         props['cpu_arch'] = 'i386'
  323         node = _get_cached_node(uuid=node_uuid, properties=props)
  324 
  325         result = self.driver._node_resource(node)
  326         self.assertEqual('i686', result['supported_instances'][0][0])
  327         self.assertEqual('i386', result['stats']['cpu_arch'])
  328 
  329     def test__node_resource_unknown_arch(self):
  330         node_uuid = uuidutils.generate_uuid()
  331         props = _get_properties()
  332         del props['cpu_arch']
  333         node = _get_cached_node(uuid=node_uuid, properties=props)
  334 
  335         result = self.driver._node_resource(node)
  336         self.assertEqual([], result['supported_instances'])
  337 
  338     def test__node_resource_exposes_capabilities(self):
  339         props = _get_properties()
  340         props['capabilities'] = 'test:capability, test2:value2'
  341         node = _get_cached_node(properties=props)
  342         result = self.driver._node_resource(node)
  343         stats = result['stats']
  344         self.assertIsNone(stats.get('capabilities'))
  345         self.assertEqual('capability', stats.get('test'))
  346         self.assertEqual('value2', stats.get('test2'))
  347 
  348     def test__node_resource_no_capabilities(self):
  349         props = _get_properties()
  350         props['capabilities'] = None
  351         node = _get_cached_node(properties=props)
  352         result = self.driver._node_resource(node)
  353         self.assertIsNone(result['stats'].get('capabilities'))
  354 
  355     def test__node_resource_malformed_capabilities(self):
  356         props = _get_properties()
  357         props['capabilities'] = 'test:capability,:no_key,no_val:'
  358         node = _get_cached_node(properties=props)
  359         result = self.driver._node_resource(node)
  360         stats = result['stats']
  361         self.assertEqual('capability', stats.get('test'))
  362 
  363     def test__node_resource_available(self):
  364         node_uuid = uuidutils.generate_uuid()
  365         props = _get_properties()
  366         stats = _get_stats()
  367         node = _get_cached_node(
  368             uuid=node_uuid,
  369             instance_uuid=None,
  370             power_state=ironic_states.POWER_OFF,
  371             properties=props,
  372             provision_state=ironic_states.AVAILABLE)
  373 
  374         result = self.driver._node_resource(node)
  375         self.assertEqual(props['cpus'], result['vcpus'])
  376         self.assertEqual(0, result['vcpus_used'])
  377         self.assertEqual(props['memory_mb'], result['memory_mb'])
  378         self.assertEqual(0, result['memory_mb_used'])
  379         self.assertEqual(props['local_gb'], result['local_gb'])
  380         self.assertEqual(0, result['local_gb_used'])
  381         self.assertEqual(node_uuid, result['hypervisor_hostname'])
  382         self.assertEqual(stats, result['stats'])
  383 
  384     @mock.patch.object(ironic_driver.IronicDriver,
  385                        '_node_resources_unavailable')
  386     def test__node_resource_unavailable_node_res(self, mock_res_unavail):
  387         mock_res_unavail.return_value = True
  388         node_uuid = uuidutils.generate_uuid()
  389         props = _get_properties()
  390         stats = _get_stats()
  391         node = _get_cached_node(
  392                 uuid=node_uuid, instance_uuid=None, properties=props)
  393 
  394         result = self.driver._node_resource(node)
  395         self.assertEqual(props['cpus'], result['vcpus'])
  396         self.assertEqual(result['vcpus'], result['vcpus_used'])
  397         self.assertEqual(props['memory_mb'], result['memory_mb'])
  398         self.assertEqual(result['memory_mb'], result['memory_mb_used'])
  399         self.assertEqual(props['local_gb'], result['local_gb'])
  400         self.assertEqual(result['local_gb'], result['local_gb_used'])
  401         self.assertEqual(node_uuid, result['hypervisor_hostname'])
  402         self.assertEqual(stats, result['stats'])
  403 
  404     @mock.patch.object(ironic_driver.IronicDriver,
  405                        '_node_resources_used')
  406     def test__node_resource_used_node_res(self, mock_res_used):
  407         mock_res_used.return_value = True
  408         node_uuid = uuidutils.generate_uuid()
  409         props = _get_properties()
  410         stats = _get_stats()
  411         instance_info = _get_instance_info()
  412         node = _get_cached_node(
  413             uuid=node_uuid,
  414             instance_uuid=uuidutils.generate_uuid(),
  415             provision_state=ironic_states.ACTIVE,
  416             properties=props,
  417             instance_info=instance_info)
  418 
  419         result = self.driver._node_resource(node)
  420         self.assertEqual(props['cpus'], result['vcpus'])
  421         self.assertEqual(result['vcpus'], result['vcpus_used'])
  422         self.assertEqual(props['memory_mb'], result['memory_mb'])
  423         self.assertEqual(result['memory_mb'], result['memory_mb_used'])
  424         self.assertEqual(props['local_gb'], result['local_gb'])
  425         self.assertEqual(result['local_gb'], result['local_gb_used'])
  426         self.assertEqual(node_uuid, result['hypervisor_hostname'])
  427         self.assertEqual(stats, result['stats'])
  428 
  429     @mock.patch.object(ironic_driver.LOG, 'warning')
  430     def test__parse_node_properties(self, mock_warning):
  431         props = _get_properties()
  432         node = _get_cached_node(
  433             uuid=uuidutils.generate_uuid(),
  434             properties=props)
  435         # raw_cpu_arch is included because extra_specs filters do not
  436         # canonicalized the arch
  437         props['raw_cpu_arch'] = props['cpu_arch']
  438         parsed = self.driver._parse_node_properties(node)
  439 
  440         self.assertEqual(props, parsed)
  441         # Assert we didn't log any warning since all properties are
  442         # correct
  443         self.assertFalse(mock_warning.called)
  444 
  445     @mock.patch.object(ironic_driver.LOG, 'warning')
  446     def test__parse_node_properties_bad_values(self, mock_warning):
  447         props = _get_properties()
  448         props['cpus'] = 'bad-value'
  449         props['memory_mb'] = 'bad-value'
  450         props['local_gb'] = 'bad-value'
  451         props['cpu_arch'] = 'bad-value'
  452         node = _get_cached_node(
  453             uuid=uuidutils.generate_uuid(),
  454             properties=props)
  455         # raw_cpu_arch is included because extra_specs filters do not
  456         # canonicalized the arch
  457         props['raw_cpu_arch'] = props['cpu_arch']
  458         parsed = self.driver._parse_node_properties(node)
  459 
  460         expected_props = props.copy()
  461         expected_props['cpus'] = 0
  462         expected_props['memory_mb'] = 0
  463         expected_props['local_gb'] = 0
  464         expected_props['cpu_arch'] = None
  465         self.assertEqual(expected_props, parsed)
  466         self.assertEqual(4, mock_warning.call_count)
  467 
  468     @mock.patch.object(ironic_driver.LOG, 'warning')
  469     def test__parse_node_properties_canonicalize_cpu_arch(self, mock_warning):
  470         props = _get_properties()
  471         props['cpu_arch'] = 'amd64'
  472         node = _get_cached_node(
  473             uuid=uuidutils.generate_uuid(),
  474             properties=props)
  475         # raw_cpu_arch is included because extra_specs filters do not
  476         # canonicalized the arch
  477         props['raw_cpu_arch'] = props['cpu_arch']
  478         parsed = self.driver._parse_node_properties(node)
  479 
  480         expected_props = props.copy()
  481         # Make sure it cpu_arch was canonicalized
  482         expected_props['cpu_arch'] = 'x86_64'
  483         self.assertEqual(expected_props, parsed)
  484         # Assert we didn't log any warning since all properties are
  485         # correct
  486         self.assertFalse(mock_warning.called)
  487 
  488     @mock.patch.object(firewall.NoopFirewallDriver, 'prepare_instance_filter',
  489                        create=True)
  490     @mock.patch.object(firewall.NoopFirewallDriver, 'setup_basic_filtering',
  491                        create=True)
  492     @mock.patch.object(firewall.NoopFirewallDriver, 'apply_instance_filter',
  493                        create=True)
  494     def test__start_firewall(self, mock_aif, mock_sbf, mock_pif):
  495         fake_inst = 'fake-inst'
  496         fake_net_info = utils.get_test_network_info()
  497         self.driver._start_firewall(fake_inst, fake_net_info)
  498 
  499         mock_aif.assert_called_once_with(fake_inst, fake_net_info)
  500         mock_sbf.assert_called_once_with(fake_inst, fake_net_info)
  501         mock_pif.assert_called_once_with(fake_inst, fake_net_info)
  502 
  503     @mock.patch.object(firewall.NoopFirewallDriver, 'unfilter_instance',
  504                        create=True)
  505     def test__stop_firewall(self, mock_ui):
  506         fake_inst = 'fake-inst'
  507         fake_net_info = utils.get_test_network_info()
  508         self.driver._stop_firewall(fake_inst, fake_net_info)
  509         mock_ui.assert_called_once_with(fake_inst, fake_net_info)
  510 
  511     @mock.patch.object(cw.IronicClientWrapper, 'call')
  512     def test_instance_exists(self, mock_call):
  513         instance = fake_instance.fake_instance_obj(self.ctx,
  514                                                    uuid=self.instance_uuid)
  515         self.assertTrue(self.driver.instance_exists(instance))
  516         mock_call.assert_called_once_with('node.get_by_instance_uuid',
  517                                           self.instance_uuid,
  518                                           fields=ironic_driver._NODE_FIELDS)
  519 
  520     @mock.patch.object(cw.IronicClientWrapper, 'call')
  521     def test_instance_exists_fail(self, mock_call):
  522         mock_call.side_effect = ironic_exception.NotFound
  523         instance = fake_instance.fake_instance_obj(self.ctx,
  524                                                    uuid=self.instance_uuid)
  525         self.assertFalse(self.driver.instance_exists(instance))
  526         mock_call.assert_called_once_with('node.get_by_instance_uuid',
  527                                           self.instance_uuid,
  528                                           fields=ironic_driver._NODE_FIELDS)
  529 
  530     @mock.patch.object(cw.IronicClientWrapper, 'call')
  531     @mock.patch.object(objects.Instance, 'get_by_uuid')
  532     def test_list_instances(self, mock_inst_by_uuid, mock_call):
  533         nodes = []
  534         instances = []
  535         for i in range(2):
  536             uuid = uuidutils.generate_uuid()
  537             instances.append(fake_instance.fake_instance_obj(self.ctx,
  538                                                              id=i,
  539                                                              uuid=uuid))
  540             nodes.append(ironic_utils.get_test_node(instance_uuid=uuid,
  541                                                     fields=['instance_uuid']))
  542 
  543         mock_inst_by_uuid.side_effect = instances
  544         mock_call.return_value = nodes
  545 
  546         response = self.driver.list_instances()
  547         mock_call.assert_called_with("node.list", associated=True,
  548                                      fields=['instance_uuid'], limit=0)
  549         expected_calls = [mock.call(mock.ANY, instances[0].uuid),
  550                           mock.call(mock.ANY, instances[1].uuid)]
  551         mock_inst_by_uuid.assert_has_calls(expected_calls)
  552         self.assertEqual(['instance-00000000', 'instance-00000001'],
  553                           sorted(response))
  554 
  555     @mock.patch.object(cw.IronicClientWrapper, 'call')
  556     @mock.patch.object(objects.Instance, 'get_by_uuid')
  557     def test_list_instances_fail(self, mock_inst_by_uuid, mock_call):
  558         mock_call.side_effect = exception.NovaException
  559         self.assertRaises(exception.VirtDriverNotReady,
  560                           self.driver.list_instances)
  561         mock_call.assert_called_with("node.list", associated=True,
  562                                      fields=['instance_uuid'], limit=0)
  563         self.assertFalse(mock_inst_by_uuid.called)
  564 
  565     @mock.patch.object(cw.IronicClientWrapper, 'call')
  566     def test_list_instance_uuids(self, mock_call):
  567         num_nodes = 2
  568         nodes = []
  569         for n in range(num_nodes):
  570             nodes.append(ironic_utils.get_test_node(
  571                                       instance_uuid=uuidutils.generate_uuid(),
  572                                       fields=['instance_uuid']))
  573 
  574         mock_call.return_value = nodes
  575         uuids = self.driver.list_instance_uuids()
  576         mock_call.assert_called_with('node.list', associated=True,
  577                                      fields=['instance_uuid'], limit=0)
  578         expected = [n.instance_uuid for n in nodes]
  579         self.assertEqual(sorted(expected), sorted(uuids))
  580 
  581     @mock.patch.object(FAKE_CLIENT.node, 'list')
  582     @mock.patch.object(FAKE_CLIENT.node, 'get')
  583     @mock.patch.object(objects.InstanceList, 'get_uuids_by_host')
  584     @mock.patch.object(objects.ServiceList, 'get_all_computes_by_hv_type')
  585     def test_node_is_available_empty_cache_empty_list(self, mock_services,
  586                                                       mock_instances, mock_get,
  587                                                       mock_list):
  588         node = _get_cached_node()
  589         mock_get.return_value = node
  590         mock_list.return_value = []
  591         self.assertTrue(self.driver.node_is_available(node.uuid))
  592         mock_get.assert_called_with(node.uuid,
  593                                     fields=ironic_driver._NODE_FIELDS)
  594         mock_list.assert_called_with(fields=ironic_driver._NODE_FIELDS,
  595                                      limit=0)
  596 
  597         mock_get.side_effect = ironic_exception.NotFound
  598         self.assertFalse(self.driver.node_is_available(node.uuid))
  599 
  600     @mock.patch.object(FAKE_CLIENT.node, 'list')
  601     @mock.patch.object(FAKE_CLIENT.node, 'get')
  602     @mock.patch.object(objects.InstanceList, 'get_uuids_by_host')
  603     @mock.patch.object(objects.ServiceList, 'get_all_computes_by_hv_type')
  604     def test_node_is_available_empty_cache(self, mock_services, mock_instances,
  605                                            mock_get, mock_list):
  606         node = _get_cached_node()
  607         mock_get.return_value = node
  608         mock_list.return_value = [node]
  609         self.assertTrue(self.driver.node_is_available(node.uuid))
  610         mock_list.assert_called_with(fields=ironic_driver._NODE_FIELDS,
  611                                      limit=0)
  612         self.assertEqual(0, mock_get.call_count)
  613 
  614     @mock.patch.object(FAKE_CLIENT.node, 'list')
  615     @mock.patch.object(FAKE_CLIENT.node, 'get')
  616     @mock.patch.object(objects.InstanceList, 'get_uuids_by_host')
  617     @mock.patch.object(objects.ServiceList, 'get_all_computes_by_hv_type')
  618     def test_node_is_available_with_cache(self, mock_services, mock_instances,
  619                                           mock_get, mock_list):
  620         node = _get_cached_node()
  621         mock_get.return_value = node
  622         mock_list.return_value = [node]
  623         # populate the cache
  624         self.driver.get_available_nodes(refresh=True)
  625         # prove that zero calls are made after populating cache
  626         mock_list.reset_mock()
  627         self.assertTrue(self.driver.node_is_available(node.uuid))
  628         self.assertEqual(0, mock_list.call_count)
  629         self.assertEqual(0, mock_get.call_count)
  630 
  631     def test__node_resources_unavailable(self):
  632         node_dicts = [
  633             # a node in maintenance /w no instance and power OFF
  634             {'uuid': uuidutils.generate_uuid(),
  635              'maintenance': True,
  636              'power_state': ironic_states.POWER_OFF,
  637              'provision_state': ironic_states.AVAILABLE},
  638             # a node in maintenance /w no instance and ERROR power state
  639             {'uuid': uuidutils.generate_uuid(),
  640              'maintenance': True,
  641              'power_state': ironic_states.ERROR,
  642              'provision_state': ironic_states.AVAILABLE},
  643             # a node not in maintenance /w no instance and bad power state
  644             {'uuid': uuidutils.generate_uuid(),
  645              'power_state': ironic_states.NOSTATE,
  646              'provision_state': ironic_states.AVAILABLE},
  647             # a node not in maintenance or bad power state, bad provision state
  648             {'uuid': uuidutils.generate_uuid(),
  649              'power_state': ironic_states.POWER_ON,
  650              'provision_state': ironic_states.MANAGEABLE},
  651             # a node in cleaning
  652             {'uuid': uuidutils.generate_uuid(),
  653              'power_state': ironic_states.POWER_ON,
  654              'provision_state': ironic_states.CLEANING},
  655             # a node in cleaning, waiting for a clean step to finish
  656             {'uuid': uuidutils.generate_uuid(),
  657              'power_state': ironic_states.POWER_ON,
  658              'provision_state': ironic_states.CLEANWAIT},
  659             # a node in deleting
  660             {'uuid': uuidutils.generate_uuid(),
  661              'power_state': ironic_states.POWER_ON,
  662              'provision_state': ironic_states.DELETING},
  663             # a node in deleted
  664             {'uuid': uuidutils.generate_uuid(),
  665              'power_state': ironic_states.POWER_ON,
  666              'provision_state': ironic_states.DELETED},
  667         ]
  668         for n in node_dicts:
  669             node = _get_cached_node(**n)
  670             self.assertTrue(self.driver._node_resources_unavailable(node))
  671 
  672         for ok_state in (ironic_states.AVAILABLE, ironic_states.NOSTATE):
  673             # these are both ok and should present as available as they
  674             # have no instance_uuid
  675             avail_node = _get_cached_node(
  676                             power_state=ironic_states.POWER_OFF,
  677                             provision_state=ok_state)
  678             unavailable = self.driver._node_resources_unavailable(avail_node)
  679             self.assertFalse(unavailable)
  680 
  681     def test__node_resources_used(self):
  682         node_dicts = [
  683             # a node in maintenance /w instance and active
  684             {'uuid': uuidutils.generate_uuid(),
  685              'instance_uuid': uuidutils.generate_uuid(),
  686              'provision_state': ironic_states.ACTIVE},
  687         ]
  688         for n in node_dicts:
  689             node = _get_cached_node(**n)
  690             self.assertTrue(self.driver._node_resources_used(node))
  691 
  692         unused_node = _get_cached_node(
  693             instance_uuid=None,
  694             provision_state=ironic_states.AVAILABLE)
  695         self.assertFalse(self.driver._node_resources_used(unused_node))
  696 
  697     @mock.patch.object(objects.ServiceList, 'get_all_computes_by_hv_type')
  698     @mock.patch.object(objects.InstanceList, 'get_uuids_by_host')
  699     @mock.patch.object(FAKE_CLIENT.node, 'list')
  700     def test_get_available_nodes(self, mock_list, mock_gi, mock_services):
  701         instance = fake_instance.fake_instance_obj(self.ctx,
  702                                                    uuid=self.instance_uuid)
  703         mock_gi.return_value = [instance.uuid]
  704         node_dicts = [
  705             # a node in maintenance /w no instance and power OFF
  706             {'uuid': uuidutils.generate_uuid(),
  707              'maintenance': True,
  708              'power_state': ironic_states.POWER_OFF,
  709              'expected': True},
  710             # a node /w instance on this compute daemon and power ON
  711             {'uuid': uuidutils.generate_uuid(),
  712              'instance_uuid': self.instance_uuid,
  713              'power_state': ironic_states.POWER_ON,
  714              'expected': True},
  715             # a node /w instance on another compute daemon and power ON
  716             {'uuid': uuidutils.generate_uuid(),
  717              'instance_uuid': uuidutils.generate_uuid(),
  718              'power_state': ironic_states.POWER_ON,
  719              'expected': False},
  720             # a node not in maintenance /w no instance and bad power state
  721             {'uuid': uuidutils.generate_uuid(),
  722              'power_state': ironic_states.ERROR,
  723              'expected': True},
  724         ]
  725         nodes = [_get_cached_node(**n)
  726                  for n in node_dicts]
  727         mock_list.return_value = nodes
  728         available_nodes = self.driver.get_available_nodes()
  729         mock_gi.assert_called_once_with(mock.ANY, CONF.host)
  730         expected_uuids = [n['uuid'] for n in node_dicts if n['expected']]
  731         self.assertEqual(sorted(expected_uuids), sorted(available_nodes))
  732 
  733     @mock.patch.object(ironic_driver.IronicDriver,
  734                        '_node_resources_used', return_value=False)
  735     @mock.patch.object(ironic_driver.IronicDriver,
  736                        '_node_resources_unavailable', return_value=False)
  737     @mock.patch.object(ironic_driver.IronicDriver, '_node_resource')
  738     @mock.patch.object(ironic_driver.IronicDriver, '_node_from_cache')
  739     def test_update_provider_tree_no_rc(self, mock_nfc, mock_nr,
  740                                         mock_res_unavail, mock_res_used):
  741         """Ensure that when node.resource_class is missing, that we return the
  742         legacy VCPU, MEMORY_MB and DISK_GB resources for inventory.
  743         """
  744         mock_nr.return_value = {
  745             'vcpus': 24,
  746             'vcpus_used': 0,
  747             'memory_mb': 1024,
  748             'memory_mb_used': 0,
  749             'local_gb': 100,
  750             'local_gb_used': 0,
  751             'resource_class': None,
  752         }
  753 
  754         self.driver.update_provider_tree(self.ptree, mock.sentinel.nodename)
  755 
  756         expected = {
  757             fields.ResourceClass.VCPU: {
  758                 'total': 24,
  759                 'reserved': 0,
  760                 'min_unit': 1,
  761                 'max_unit': 24,
  762                 'step_size': 1,
  763                 'allocation_ratio': 1.0,
  764             },
  765             fields.ResourceClass.MEMORY_MB: {
  766                 'total': 1024,
  767                 'reserved': 0,
  768                 'min_unit': 1,
  769                 'max_unit': 1024,
  770                 'step_size': 1,
  771                 'allocation_ratio': 1.0,
  772             },
  773             fields.ResourceClass.DISK_GB: {
  774                 'total': 100,
  775                 'reserved': 0,
  776                 'min_unit': 1,
  777                 'max_unit': 100,
  778                 'step_size': 1,
  779                 'allocation_ratio': 1.0,
  780             },
  781         }
  782         mock_nfc.assert_called_once_with(mock.sentinel.nodename)
  783         mock_nr.assert_called_once_with(mock_nfc.return_value)
  784         mock_res_used.assert_called_once_with(mock_nfc.return_value)
  785         mock_res_unavail.assert_called_once_with(mock_nfc.return_value)
  786         result = self.ptree.data(mock.sentinel.nodename).inventory
  787         self.assertEqual(expected, result)
  788 
  789     @mock.patch.object(ironic_driver.IronicDriver,
  790                        '_node_resources_used', return_value=False)
  791     @mock.patch.object(ironic_driver.IronicDriver,
  792                        '_node_resources_unavailable', return_value=False)
  793     @mock.patch.object(ironic_driver.IronicDriver, '_node_resource')
  794     @mock.patch.object(ironic_driver.IronicDriver, '_node_from_cache')
  795     def test_update_provider_tree_with_rc(self, mock_nfc, mock_nr,
  796                                           mock_res_unavail, mock_res_used):
  797         """Ensure that when node.resource_class is present, that we return the
  798         legacy VCPU, MEMORY_MB and DISK_GB resources for inventory in addition
  799         to the custom resource class inventory record.
  800         """
  801         mock_nr.return_value = {
  802             'vcpus': 24,
  803             'vcpus_used': 0,
  804             'memory_mb': 1024,
  805             'memory_mb_used': 0,
  806             'local_gb': 100,
  807             'local_gb_used': 0,
  808             'resource_class': 'iron-nfv',
  809         }
  810 
  811         self.driver.update_provider_tree(self.ptree, mock.sentinel.nodename)
  812 
  813         expected = {
  814             fields.ResourceClass.VCPU: {
  815                 'total': 24,
  816                 'reserved': 0,
  817                 'min_unit': 1,
  818                 'max_unit': 24,
  819                 'step_size': 1,
  820                 'allocation_ratio': 1.0,
  821             },
  822             fields.ResourceClass.MEMORY_MB: {
  823                 'total': 1024,
  824                 'reserved': 0,
  825                 'min_unit': 1,
  826                 'max_unit': 1024,
  827                 'step_size': 1,
  828                 'allocation_ratio': 1.0,
  829             },
  830             fields.ResourceClass.DISK_GB: {
  831                 'total': 100,
  832                 'reserved': 0,
  833                 'min_unit': 1,
  834                 'max_unit': 100,
  835                 'step_size': 1,
  836                 'allocation_ratio': 1.0,
  837             },
  838             'CUSTOM_IRON_NFV': {
  839                 'total': 1,
  840                 'reserved': 0,
  841                 'min_unit': 1,
  842                 'max_unit': 1,
  843                 'step_size': 1,
  844                 'allocation_ratio': 1.0,
  845             },
  846         }
  847         mock_nfc.assert_called_once_with(mock.sentinel.nodename)
  848         mock_nr.assert_called_once_with(mock_nfc.return_value)
  849         mock_res_used.assert_called_once_with(mock_nfc.return_value)
  850         mock_res_unavail.assert_called_once_with(mock_nfc.return_value)
  851         result = self.ptree.data(mock.sentinel.nodename).inventory
  852         self.assertEqual(expected, result)
  853 
  854     @mock.patch.object(ironic_driver.IronicDriver,
  855                        '_node_resources_used', return_value=False)
  856     @mock.patch.object(ironic_driver.IronicDriver,
  857                        '_node_resources_unavailable', return_value=False)
  858     @mock.patch.object(ironic_driver.IronicDriver, '_node_resource')
  859     @mock.patch.object(ironic_driver.IronicDriver, '_node_from_cache')
  860     def test_update_provider_tree_no_report_standard_res_classes(
  861             self, mock_nfc, mock_nr, mock_res_unavail, mock_res_used):
  862         """Ensures that if
  863         [workarounds]/report_ironic_standard_resource_class_inventory=False we
  864         only report the custom resource class inventory.
  865         """
  866         self.flags(report_ironic_standard_resource_class_inventory=False,
  867                    group='workarounds')
  868         mock_nr.return_value = {
  869             'vcpus': 24,
  870             'vcpus_used': 0,
  871             'memory_mb': 1024,
  872             'memory_mb_used': 0,
  873             'local_gb': 100,
  874             'local_gb_used': 0,
  875             'resource_class': 'iron-nfv',
  876         }
  877 
  878         self.driver.update_provider_tree(self.ptree, mock.sentinel.nodename)
  879 
  880         expected = {
  881             'CUSTOM_IRON_NFV': {
  882                 'total': 1,
  883                 'reserved': 0,
  884                 'min_unit': 1,
  885                 'max_unit': 1,
  886                 'step_size': 1,
  887                 'allocation_ratio': 1.0,
  888             },
  889         }
  890         mock_nfc.assert_called_once_with(mock.sentinel.nodename)
  891         mock_nr.assert_called_once_with(mock_nfc.return_value)
  892         mock_res_used.assert_called_once_with(mock_nfc.return_value)
  893         mock_res_unavail.assert_called_once_with(mock_nfc.return_value)
  894         result = self.ptree.data(mock.sentinel.nodename).inventory
  895         self.assertEqual(expected, result)
  896 
  897     @mock.patch.object(ironic_driver.IronicDriver,
  898                        '_node_resources_used', return_value=False)
  899     @mock.patch.object(ironic_driver.IronicDriver,
  900                        '_node_resources_unavailable', return_value=False)
  901     @mock.patch.object(ironic_driver.IronicDriver, '_node_resource')
  902     @mock.patch.object(ironic_driver.IronicDriver, '_node_from_cache')
  903     def test_update_provider_tree_only_rc(self, mock_nfc, mock_nr,
  904                                           mock_res_unavail, mock_res_used):
  905         """Ensure that when node.resource_class is present, that we return the
  906         legacy VCPU, MEMORY_MB and DISK_GB resources for inventory in addition
  907         to the custom resource class inventory record.
  908         """
  909         mock_nr.return_value = {
  910             'vcpus': 0,
  911             'vcpus_used': 0,
  912             'memory_mb': 0,
  913             'memory_mb_used': 0,
  914             'local_gb': 0,
  915             'local_gb_used': 0,
  916             'resource_class': 'iron-nfv',
  917         }
  918 
  919         self.driver.update_provider_tree(self.ptree, mock.sentinel.nodename)
  920 
  921         expected = {
  922             'CUSTOM_IRON_NFV': {
  923                 'total': 1,
  924                 'reserved': 0,
  925                 'min_unit': 1,
  926                 'max_unit': 1,
  927                 'step_size': 1,
  928                 'allocation_ratio': 1.0,
  929             },
  930         }
  931         mock_nfc.assert_called_once_with(mock.sentinel.nodename)
  932         mock_nr.assert_called_once_with(mock_nfc.return_value)
  933         mock_res_used.assert_called_once_with(mock_nfc.return_value)
  934         mock_res_unavail.assert_called_once_with(mock_nfc.return_value)
  935         result = self.ptree.data(mock.sentinel.nodename).inventory
  936         self.assertEqual(expected, result)
  937 
  938     @mock.patch.object(ironic_driver.IronicDriver,
  939                        '_node_resources_used', return_value=True)
  940     @mock.patch.object(ironic_driver.IronicDriver,
  941                        '_node_resources_unavailable', return_value=False)
  942     @mock.patch.object(ironic_driver.IronicDriver, '_node_resource')
  943     @mock.patch.object(ironic_driver.IronicDriver, '_node_from_cache')
  944     def test_update_provider_tree_with_rc_occupied(self, mock_nfc, mock_nr,
  945                                                    mock_res_unavail,
  946                                                    mock_res_used):
  947         """Ensure that when a node is used, we report the inventory matching
  948         the consumed resources.
  949         """
  950         mock_nr.return_value = {
  951             'vcpus': 24,
  952             'vcpus_used': 24,
  953             'memory_mb': 1024,
  954             'memory_mb_used': 1024,
  955             'local_gb': 100,
  956             'local_gb_used': 100,
  957             'resource_class': 'iron-nfv',
  958         }
  959 
  960         self.driver.update_provider_tree(self.ptree, mock.sentinel.nodename)
  961 
  962         expected = {
  963             fields.ResourceClass.VCPU: {
  964                 'total': 24,
  965                 'reserved': 0,
  966                 'min_unit': 1,
  967                 'max_unit': 24,
  968                 'step_size': 1,
  969                 'allocation_ratio': 1.0,
  970             },
  971             fields.ResourceClass.MEMORY_MB: {
  972                 'total': 1024,
  973                 'reserved': 0,
  974                 'min_unit': 1,
  975                 'max_unit': 1024,
  976                 'step_size': 1,
  977                 'allocation_ratio': 1.0,
  978             },
  979             fields.ResourceClass.DISK_GB: {
  980                 'total': 100,
  981                 'reserved': 0,
  982                 'min_unit': 1,
  983                 'max_unit': 100,
  984                 'step_size': 1,
  985                 'allocation_ratio': 1.0,
  986             },
  987             'CUSTOM_IRON_NFV': {
  988                 'total': 1,
  989                 'reserved': 0,
  990                 'min_unit': 1,
  991                 'max_unit': 1,
  992                 'step_size': 1,
  993                 'allocation_ratio': 1.0,
  994             },
  995         }
  996         mock_nfc.assert_called_once_with(mock.sentinel.nodename)
  997         mock_nr.assert_called_once_with(mock_nfc.return_value)
  998         mock_res_used.assert_called_once_with(mock_nfc.return_value)
  999         self.assertFalse(mock_res_unavail.called)
 1000         result = self.ptree.data(mock.sentinel.nodename).inventory
 1001         self.assertEqual(expected, result)
 1002 
 1003     @mock.patch.object(ironic_driver.IronicDriver,
 1004                        '_node_resources_used', return_value=False)
 1005     @mock.patch.object(ironic_driver.IronicDriver,
 1006                        '_node_resources_unavailable', return_value=True)
 1007     @mock.patch.object(ironic_driver.IronicDriver, '_node_resource')
 1008     @mock.patch.object(ironic_driver.IronicDriver, '_node_from_cache')
 1009     def test_update_provider_tree_disabled_node(self, mock_nfc, mock_nr,
 1010                                                 mock_res_unavail,
 1011                                                 mock_res_used):
 1012         """Ensure that when a node is disabled, that update_provider_tree()
 1013         sets inventory with reserved amounts equal to the total amounts.
 1014         """
 1015         mock_nr.return_value = {
 1016             'vcpus': 24,
 1017             'vcpus_used': 0,
 1018             'memory_mb': 1024,
 1019             'memory_mb_used': 0,
 1020             'local_gb': 100,
 1021             'local_gb_used': 0,
 1022             'resource_class': 'iron-nfv',
 1023         }
 1024 
 1025         self.driver.update_provider_tree(self.ptree, mock.sentinel.nodename)
 1026 
 1027         expected = {
 1028             fields.ResourceClass.VCPU: {
 1029                 'total': 24,
 1030                 'reserved': 24,
 1031                 'min_unit': 1,
 1032                 'max_unit': 24,
 1033                 'step_size': 1,
 1034                 'allocation_ratio': 1.0,
 1035             },
 1036             fields.ResourceClass.MEMORY_MB: {
 1037                 'total': 1024,
 1038                 'reserved': 1024,
 1039                 'min_unit': 1,
 1040                 'max_unit': 1024,
 1041                 'step_size': 1,
 1042                 'allocation_ratio': 1.0,
 1043             },
 1044             fields.ResourceClass.DISK_GB: {
 1045                 'total': 100,
 1046                 'reserved': 100,
 1047                 'min_unit': 1,
 1048                 'max_unit': 100,
 1049                 'step_size': 1,
 1050                 'allocation_ratio': 1.0,
 1051             },
 1052             'CUSTOM_IRON_NFV': {
 1053                 'total': 1,
 1054                 'reserved': 1,
 1055                 'min_unit': 1,
 1056                 'max_unit': 1,
 1057                 'step_size': 1,
 1058                 'allocation_ratio': 1.0,
 1059             },
 1060         }
 1061         mock_nfc.assert_called_once_with(mock.sentinel.nodename)
 1062         mock_nr.assert_called_once_with(mock_nfc.return_value)
 1063         mock_res_unavail.assert_called_once_with(mock_nfc.return_value)
 1064         mock_res_used.assert_called_once_with(mock_nfc.return_value)
 1065         result = self.ptree.data(mock.sentinel.nodename).inventory
 1066         self.assertEqual(expected, result)
 1067 
 1068     @mock.patch.object(ironic_driver.IronicDriver,
 1069                        '_node_resources_used', return_value=True)
 1070     @mock.patch.object(ironic_driver.IronicDriver,
 1071                        '_node_resources_unavailable', return_value=False)
 1072     @mock.patch.object(ironic_driver.IronicDriver, '_node_resource')
 1073     @mock.patch.object(ironic_driver.IronicDriver, '_node_from_cache')
 1074     def test_update_provider_tree_no_traits(self, mock_nfc, mock_nr,
 1075                                             mock_res_unavail, mock_res_used):
 1076         """Ensure that when the node has no traits, we set no traits."""
 1077         mock_nr.return_value = {
 1078             'vcpus': 24,
 1079             'vcpus_used': 24,
 1080             'memory_mb': 1024,
 1081             'memory_mb_used': 1024,
 1082             'local_gb': 100,
 1083             'local_gb_used': 100,
 1084             'resource_class': 'iron-nfv',
 1085         }
 1086 
 1087         mock_nfc.return_value = _get_cached_node(uuid=mock.sentinel.nodename)
 1088 
 1089         self.driver.update_provider_tree(self.ptree, mock.sentinel.nodename)
 1090 
 1091         mock_nfc.assert_called_once_with(mock.sentinel.nodename)
 1092         mock_nr.assert_called_once_with(mock_nfc.return_value)
 1093         mock_res_used.assert_called_once_with(mock_nfc.return_value)
 1094         self.assertFalse(mock_res_unavail.called)
 1095         result = self.ptree.data(mock.sentinel.nodename).traits
 1096         self.assertEqual(set(), result)
 1097 
 1098     @mock.patch.object(ironic_driver.IronicDriver,
 1099                        '_node_resources_used', return_value=True)
 1100     @mock.patch.object(ironic_driver.IronicDriver,
 1101                        '_node_resources_unavailable', return_value=False)
 1102     @mock.patch.object(ironic_driver.IronicDriver, '_node_resource')
 1103     @mock.patch.object(ironic_driver.IronicDriver, '_node_from_cache')
 1104     def test_update_provider_tree_with_traits(self, mock_nfc, mock_nr,
 1105                                               mock_res_unavail, mock_res_used):
 1106         """Ensure that when the node has traits, we set the traits."""
 1107         mock_nr.return_value = {
 1108             'vcpus': 24,
 1109             'vcpus_used': 24,
 1110             'memory_mb': 1024,
 1111             'memory_mb_used': 1024,
 1112             'local_gb': 100,
 1113             'local_gb_used': 100,
 1114             'resource_class': 'iron-nfv',
 1115         }
 1116 
 1117         traits = ['trait1', 'trait2']
 1118         mock_nfc.return_value = _get_cached_node(
 1119             uuid=mock.sentinel.nodename, traits=traits)
 1120 
 1121         self.driver.update_provider_tree(self.ptree, mock.sentinel.nodename)
 1122 
 1123         mock_nfc.assert_called_once_with(mock.sentinel.nodename)
 1124         mock_nr.assert_called_once_with(mock_nfc.return_value)
 1125         mock_res_used.assert_called_once_with(mock_nfc.return_value)
 1126         self.assertFalse(mock_res_unavail.called)
 1127         result = self.ptree.data(mock.sentinel.nodename).traits
 1128         self.assertEqual(set(traits), result)
 1129 
 1130         # A different set of traits - we should replace (for now).
 1131         traits = ['trait1', 'trait7', 'trait42']
 1132         mock_nfc.return_value = _get_cached_node(
 1133             uuid=mock.sentinel.nodename, traits=traits)
 1134         self.driver.update_provider_tree(self.ptree, mock.sentinel.nodename)
 1135         result = self.ptree.data(mock.sentinel.nodename).traits
 1136         self.assertEqual(set(traits), result)
 1137 
 1138     @mock.patch.object(FAKE_CLIENT.node, 'get')
 1139     @mock.patch.object(FAKE_CLIENT.node, 'list')
 1140     @mock.patch.object(objects.InstanceList, 'get_uuids_by_host')
 1141     @mock.patch.object(objects.ServiceList, 'get_all_computes_by_hv_type')
 1142     @mock.patch.object(ironic_driver.IronicDriver, '_node_resource')
 1143     def test_get_available_resource(self, mock_nr, mock_services,
 1144                                     mock_instances, mock_list, mock_get):
 1145         node = _get_cached_node()
 1146         node_2 = _get_cached_node(uuid=uuidutils.generate_uuid())
 1147         fake_resource = 'fake-resource'
 1148         mock_get.return_value = node
 1149         # ensure cache gets populated without the node we want
 1150         mock_list.return_value = [node_2]
 1151         mock_nr.return_value = fake_resource
 1152 
 1153         result = self.driver.get_available_resource(node.uuid)
 1154         self.assertEqual(fake_resource, result)
 1155         mock_nr.assert_called_once_with(node)
 1156         mock_get.assert_called_once_with(node.uuid,
 1157                                          fields=ironic_driver._NODE_FIELDS)
 1158 
 1159     @mock.patch.object(FAKE_CLIENT.node, 'get')
 1160     @mock.patch.object(FAKE_CLIENT.node, 'list')
 1161     @mock.patch.object(objects.InstanceList, 'get_uuids_by_host')
 1162     @mock.patch.object(objects.ServiceList, 'get_all_computes_by_hv_type')
 1163     @mock.patch.object(ironic_driver.IronicDriver, '_node_resource')
 1164     def test_get_available_resource_with_cache(self, mock_nr, mock_services,
 1165                                                mock_instances, mock_list,
 1166                                                mock_get):
 1167         node = _get_cached_node()
 1168         fake_resource = 'fake-resource'
 1169         mock_list.return_value = [node]
 1170         mock_nr.return_value = fake_resource
 1171         # populate the cache
 1172         self.driver.get_available_nodes(refresh=True)
 1173         mock_list.reset_mock()
 1174 
 1175         result = self.driver.get_available_resource(node.uuid)
 1176         self.assertEqual(fake_resource, result)
 1177         self.assertEqual(0, mock_list.call_count)
 1178         self.assertEqual(0, mock_get.call_count)
 1179         mock_nr.assert_called_once_with(node)
 1180 
 1181     @mock.patch.object(ironic_driver.IronicDriver, '_get_node_list')
 1182     @mock.patch.object(objects.InstanceList, 'get_uuids_by_host')
 1183     @mock.patch.object(objects.ServiceList, 'get_all_computes_by_hv_type')
 1184     @mock.patch.object(FAKE_CLIENT.node, 'get_by_instance_uuid')
 1185     def test_get_info(self, mock_gbiu, mock_svc_by_hv,
 1186                       mock_uuids_by_host, mock_get_node_list):
 1187         properties = {'memory_mb': 512, 'cpus': 2}
 1188         power_state = ironic_states.POWER_ON
 1189         node = _get_cached_node(
 1190                 instance_uuid=self.instance_uuid, properties=properties,
 1191                 power_state=power_state)
 1192 
 1193         mock_gbiu.return_value = node
 1194         mock_svc_by_hv.return_value = []
 1195         mock_get_node_list.return_value = []
 1196 
 1197         # ironic_states.POWER_ON should be mapped to
 1198         # nova_states.RUNNING
 1199         instance = fake_instance.fake_instance_obj('fake-context',
 1200                                                    uuid=self.instance_uuid)
 1201         mock_uuids_by_host.return_value = [instance.uuid]
 1202         result = self.driver.get_info(instance)
 1203         self.assertEqual(hardware.InstanceInfo(state=nova_states.RUNNING),
 1204                          result)
 1205         mock_gbiu.assert_called_once_with(instance.uuid,
 1206                                           fields=ironic_driver._NODE_FIELDS)
 1207 
 1208     @mock.patch.object(ironic_driver.IronicDriver, '_get_node_list')
 1209     @mock.patch.object(objects.InstanceList, 'get_uuids_by_host')
 1210     @mock.patch.object(objects.ServiceList, 'get_all_computes_by_hv_type')
 1211     @mock.patch.object(FAKE_CLIENT.node, 'get_by_instance_uuid')
 1212     def test_get_info_cached(self, mock_gbiu, mock_svc_by_hv,
 1213                              mock_uuids_by_host, mock_get_node_list):
 1214         properties = {'memory_mb': 512, 'cpus': 2}
 1215         power_state = ironic_states.POWER_ON
 1216         node = _get_cached_node(
 1217                 instance_uuid=self.instance_uuid, properties=properties,
 1218                 power_state=power_state)
 1219 
 1220         mock_gbiu.return_value = node
 1221         mock_svc_by_hv.return_value = []
 1222         mock_get_node_list.return_value = [node]
 1223 
 1224         # ironic_states.POWER_ON should be mapped to
 1225         # nova_states.RUNNING
 1226         instance = fake_instance.fake_instance_obj('fake-context',
 1227                                                    uuid=self.instance_uuid)
 1228         mock_uuids_by_host.return_value = [instance.uuid]
 1229         result = self.driver.get_info(instance)
 1230         self.assertEqual(hardware.InstanceInfo(state=nova_states.RUNNING),
 1231                          result)
 1232         mock_gbiu.assert_not_called()
 1233 
 1234     @mock.patch.object(ironic_driver.IronicDriver, '_get_node_list')
 1235     @mock.patch.object(objects.InstanceList, 'get_uuids_by_host')
 1236     @mock.patch.object(objects.ServiceList, 'get_all_computes_by_hv_type')
 1237     @mock.patch.object(FAKE_CLIENT.node, 'get_by_instance_uuid')
 1238     def test_get_info_not_found_in_cache(self, mock_gbiu, mock_svc_by_hv,
 1239                                          mock_uuids_by_host,
 1240                                          mock_get_node_list):
 1241         properties = {'memory_mb': 512, 'cpus': 2}
 1242         power_state = ironic_states.POWER_ON
 1243         node = _get_cached_node(
 1244                 instance_uuid=self.instance_uuid, properties=properties,
 1245                 power_state=power_state)
 1246         node2 = _get_cached_node()
 1247 
 1248         mock_gbiu.return_value = node
 1249         mock_svc_by_hv.return_value = []
 1250         mock_get_node_list.return_value = [node2]
 1251 
 1252         # ironic_states.POWER_ON should be mapped to
 1253         # nova_states.RUNNING
 1254         instance = fake_instance.fake_instance_obj('fake-context',
 1255                                                    uuid=self.instance_uuid)
 1256         mock_uuids_by_host.return_value = [instance.uuid]
 1257         result = self.driver.get_info(instance)
 1258         self.assertEqual(hardware.InstanceInfo(state=nova_states.RUNNING),
 1259                          result)
 1260         mock_gbiu.assert_called_once()
 1261         mock_gbiu.assert_called_once_with(instance.uuid,
 1262                                           fields=ironic_driver._NODE_FIELDS)
 1263 
 1264     @mock.patch.object(ironic_driver.IronicDriver, '_get_node_list')
 1265     @mock.patch.object(objects.InstanceList, 'get_uuids_by_host')
 1266     @mock.patch.object(objects.ServiceList, 'get_all_computes_by_hv_type')
 1267     @mock.patch.object(FAKE_CLIENT.node, 'get_by_instance_uuid')
 1268     def test_get_info_skip_cache(self, mock_gbiu, mock_svc_by_hv,
 1269                                  mock_uuids_by_host, mock_get_node_list):
 1270         properties = {'memory_mb': 512, 'cpus': 2}
 1271         power_state = ironic_states.POWER_ON
 1272         node = _get_cached_node(
 1273                 instance_uuid=self.instance_uuid, properties=properties,
 1274                 power_state=power_state)
 1275 
 1276         mock_gbiu.return_value = node
 1277         mock_svc_by_hv.return_value = []
 1278         mock_get_node_list.return_value = [node]
 1279 
 1280         # ironic_states.POWER_ON should be mapped to
 1281         # nova_states.RUNNING
 1282         instance = fake_instance.fake_instance_obj('fake-context',
 1283                                                    uuid=self.instance_uuid)
 1284         mock_uuids_by_host.return_value = [instance.uuid]
 1285         result = self.driver.get_info(instance, use_cache=False)
 1286         self.assertEqual(hardware.InstanceInfo(state=nova_states.RUNNING),
 1287                          result)
 1288         # verify we hit the ironic API for fresh data
 1289         mock_gbiu.assert_called_once_with(instance.uuid,
 1290                                           fields=ironic_driver._NODE_FIELDS)
 1291 
 1292     @mock.patch.object(ironic_driver.IronicDriver, '_get_node_list')
 1293     @mock.patch.object(objects.InstanceList, 'get_uuids_by_host')
 1294     @mock.patch.object(objects.ServiceList, 'get_all_computes_by_hv_type')
 1295     @mock.patch.object(FAKE_CLIENT.node, 'get_by_instance_uuid')
 1296     def test_get_info_http_not_found(self, mock_gbiu, mock_svc_by_hv,
 1297                                      mock_uuids_by_host, mock_get_node_list):
 1298         mock_gbiu.side_effect = ironic_exception.NotFound()
 1299         mock_svc_by_hv.return_value = []
 1300         mock_get_node_list.return_value = []
 1301 
 1302         instance = fake_instance.fake_instance_obj(
 1303                                   self.ctx, uuid=uuidutils.generate_uuid())
 1304         mock_uuids_by_host.return_value = [instance]
 1305         mock_uuids_by_host.return_value = [instance.uuid]
 1306         result = self.driver.get_info(instance)
 1307         self.assertEqual(hardware.InstanceInfo(state=nova_states.NOSTATE),
 1308                          result)
 1309         mock_gbiu.assert_called_once_with(instance.uuid,
 1310                                           fields=ironic_driver._NODE_FIELDS)
 1311 
 1312     @mock.patch.object(objects.Instance, 'save')
 1313     @mock.patch.object(loopingcall, 'FixedIntervalLoopingCall')
 1314     @mock.patch.object(FAKE_CLIENT, 'node')
 1315     @mock.patch.object(ironic_driver.IronicDriver, '_add_volume_target_info')
 1316     @mock.patch.object(ironic_driver.IronicDriver, '_wait_for_active')
 1317     @mock.patch.object(ironic_driver.IronicDriver,
 1318                        '_add_instance_info_to_node')
 1319     @mock.patch.object(ironic_driver.IronicDriver, '_start_firewall')
 1320     def _test_spawn(self, mock_sf, mock_aiitn, mock_wait_active,
 1321                     mock_avti, mock_node, mock_looping, mock_save):
 1322         node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
 1323         node = _get_cached_node(driver='fake', uuid=node_uuid)
 1324         instance = fake_instance.fake_instance_obj(self.ctx, node=node_uuid)
 1325         fake_flavor = objects.Flavor(ephemeral_gb=0)
 1326         instance.flavor = fake_flavor
 1327 
 1328         mock_node.get.return_value = node
 1329         mock_node.validate.return_value = ironic_utils.get_test_validation()
 1330         mock_node.get_by_instance_uuid.return_value = node
 1331         mock_node.set_provision_state.return_value = mock.MagicMock()
 1332 
 1333         fake_looping_call = FakeLoopingCall()
 1334         mock_looping.return_value = fake_looping_call
 1335 
 1336         image_meta = ironic_utils.get_test_image_meta()
 1337 
 1338         self.driver.spawn(self.ctx, instance, image_meta, [], None, {})
 1339 
 1340         mock_node.get.assert_called_once_with(
 1341             node_uuid, fields=ironic_driver._NODE_FIELDS)
 1342         mock_node.validate.assert_called_once_with(node_uuid)
 1343         mock_aiitn.assert_called_once_with(node, instance,
 1344                                          test.MatchType(objects.ImageMeta),
 1345                                          fake_flavor, block_device_info=None)
 1346         mock_avti.assert_called_once_with(self.ctx, instance, None)
 1347         mock_sf.assert_called_once_with(instance, None)
 1348         mock_node.set_provision_state.assert_called_once_with(node_uuid,
 1349                                                 'active', configdrive=mock.ANY)
 1350 
 1351         self.assertIsNone(instance.default_ephemeral_device)
 1352         self.assertFalse(mock_save.called)
 1353 
 1354         mock_looping.assert_called_once_with(mock_wait_active,
 1355                                              instance)
 1356         fake_looping_call.start.assert_called_once_with(
 1357             interval=CONF.ironic.api_retry_interval)
 1358         fake_looping_call.wait.assert_called_once_with()
 1359 
 1360     @mock.patch.object(ironic_driver.IronicDriver, '_generate_configdrive')
 1361     @mock.patch.object(configdrive, 'required_by')
 1362     def test_spawn(self, mock_required_by, mock_configdrive):
 1363         mock_required_by.return_value = False
 1364         self._test_spawn()
 1365         # assert configdrive was not generated
 1366         self.assertFalse(mock_configdrive.called)
 1367 
 1368     @mock.patch.object(ironic_driver.IronicDriver, '_generate_configdrive')
 1369     @mock.patch.object(configdrive, 'required_by')
 1370     def test_spawn_with_configdrive(self, mock_required_by, mock_configdrive):
 1371         mock_required_by.return_value = True
 1372         self._test_spawn()
 1373         # assert configdrive was generated
 1374         mock_configdrive.assert_called_once_with(mock.ANY, mock.ANY, mock.ANY,
 1375                                                  mock.ANY, extra_md={},
 1376                                                  files=[])
 1377 
 1378     @mock.patch.object(configdrive, 'required_by')
 1379     @mock.patch.object(loopingcall, 'FixedIntervalLoopingCall')
 1380     @mock.patch.object(FAKE_CLIENT, 'node')
 1381     @mock.patch.object(ironic_driver.IronicDriver, 'destroy')
 1382     @mock.patch.object(ironic_driver.IronicDriver, '_add_volume_target_info')
 1383     @mock.patch.object(ironic_driver.IronicDriver, '_wait_for_active')
 1384     @mock.patch.object(ironic_driver.IronicDriver,
 1385                        '_add_instance_info_to_node')
 1386     @mock.patch.object(ironic_driver.IronicDriver, '_start_firewall')
 1387     def test_spawn_destroyed_after_failure(self, mock_sf, mock_aiitn,
 1388                                            mock_wait_active, mock_avti,
 1389                                            mock_destroy, mock_node,
 1390                                            mock_looping, mock_required_by):
 1391         mock_required_by.return_value = False
 1392         node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
 1393         node = _get_cached_node(driver='fake', uuid=node_uuid)
 1394         fake_flavor = objects.Flavor(ephemeral_gb=0)
 1395         instance = fake_instance.fake_instance_obj(self.ctx, node=node_uuid)
 1396         instance.flavor = fake_flavor
 1397 
 1398         mock_node.get.return_value = node
 1399         mock_node.validate.return_value = ironic_utils.get_test_validation()
 1400         mock_node.get_by_instance_uuid.return_value = node
 1401         mock_node.set_provision_state.return_value = mock.MagicMock()
 1402 
 1403         fake_looping_call = FakeLoopingCall()
 1404         mock_looping.return_value = fake_looping_call
 1405 
 1406         deploy_exc = exception.InstanceDeployFailure('foo')
 1407         fake_looping_call.wait.side_effect = deploy_exc
 1408         self.assertRaises(
 1409             exception.InstanceDeployFailure,
 1410             self.driver.spawn, self.ctx, instance, None, [], None, {})
 1411         self.assertEqual(0, mock_destroy.call_count)
 1412 
 1413     def _test_add_instance_info_to_node(self, mock_update=None,
 1414                                         mock_call=None):
 1415         node = _get_cached_node(driver='fake')
 1416         instance = fake_instance.fake_instance_obj(self.ctx,
 1417                                                    node=node.uuid)
 1418         image_meta = ironic_utils.get_test_image_meta()
 1419         flavor = ironic_utils.get_test_flavor()
 1420         instance.flavor = flavor
 1421         self.driver._add_instance_info_to_node(node, instance, image_meta,
 1422                                                flavor)
 1423         expected_patch = [{'path': '/instance_info/image_source', 'op': 'add',
 1424                            'value': image_meta.id},
 1425                           {'path': '/instance_info/root_gb', 'op': 'add',
 1426                            'value': str(instance.flavor.root_gb)},
 1427                           {'path': '/instance_info/swap_mb', 'op': 'add',
 1428                            'value': str(flavor['swap'])},
 1429                           {'path': '/instance_info/display_name',
 1430                            'value': instance.display_name, 'op': 'add'},
 1431                           {'path': '/instance_info/vcpus', 'op': 'add',
 1432                            'value': str(instance.flavor.vcpus)},
 1433                           {'path': '/instance_info/nova_host_id', 'op': 'add',
 1434                            'value': instance.host},
 1435                           {'path': '/instance_info/memory_mb', 'op': 'add',
 1436                            'value': str(instance.flavor.memory_mb)},
 1437                           {'path': '/instance_info/local_gb', 'op': 'add',
 1438                            'value': str(node.properties.get('local_gb', 0))}]
 1439 
 1440         if mock_call is not None:
 1441             # assert call() is invoked with retry_on_conflict False to
 1442             # avoid bug #1341420
 1443             mock_call.assert_called_once_with('node.update', node.uuid,
 1444                                               expected_patch,
 1445                                               retry_on_conflict=False)
 1446         if mock_update is not None:
 1447             mock_update.assert_called_once_with(node.uuid, expected_patch)
 1448 
 1449     @mock.patch.object(FAKE_CLIENT.node, 'update')
 1450     def test__add_instance_info_to_node_mock_update(self, mock_update):
 1451         self._test_add_instance_info_to_node(mock_update=mock_update)
 1452 
 1453     @mock.patch.object(cw.IronicClientWrapper, 'call')
 1454     def test__add_instance_info_to_node_mock_call(self, mock_call):
 1455         self._test_add_instance_info_to_node(mock_call=mock_call)
 1456 
 1457     @mock.patch.object(FAKE_CLIENT.node, 'update')
 1458     def test__add_instance_info_to_node_fail(self, mock_update):
 1459         mock_update.side_effect = ironic_exception.BadRequest()
 1460         node = _get_cached_node(driver='fake')
 1461         instance = fake_instance.fake_instance_obj(self.ctx,
 1462                                                    node=node.uuid)
 1463         image_meta = ironic_utils.get_test_image_meta()
 1464         flavor = ironic_utils.get_test_flavor()
 1465         self.assertRaises(exception.InstanceDeployFailure,
 1466                           self.driver._add_instance_info_to_node,
 1467                           node, instance, image_meta, flavor)
 1468 
 1469     def _test_remove_instance_info_from_node(self, mock_update):
 1470         node = _get_cached_node(driver='fake')
 1471         instance = fake_instance.fake_instance_obj(self.ctx,
 1472                                                    node=node.uuid)
 1473         self.driver._remove_instance_info_from_node(node, instance)
 1474         expected_patch = [{'path': '/instance_info', 'op': 'remove'},
 1475                           {'path': '/instance_uuid', 'op': 'remove'}]
 1476         mock_update.assert_called_once_with(node.uuid, expected_patch)
 1477 
 1478     @mock.patch.object(FAKE_CLIENT.node, 'update')
 1479     def test_remove_instance_info_from_node(self, mock_update):
 1480         self._test_remove_instance_info_from_node(mock_update)
 1481 
 1482     @mock.patch.object(FAKE_CLIENT.node, 'update')
 1483     def test_remove_instance_info_from_node_fail(self, mock_update):
 1484         mock_update.side_effect = ironic_exception.BadRequest()
 1485         self._test_remove_instance_info_from_node(mock_update)
 1486 
 1487     def _create_fake_block_device_info(self):
 1488         bdm_dict = block_device.BlockDeviceDict({
 1489             'id': 1, 'instance_uuid': uuids.instance,
 1490             'device_name': '/dev/sda',
 1491             'source_type': 'volume',
 1492             'volume_id': 'fake-volume-id-1',
 1493             'connection_info':
 1494             '{"data":"fake_data",\
 1495               "driver_volume_type":"fake_type"}',
 1496             'boot_index': 0,
 1497             'destination_type': 'volume'
 1498         })
 1499         driver_bdm = driver_block_device.DriverVolumeBlockDevice(
 1500             fake_block_device.fake_bdm_object(self.ctx, bdm_dict))
 1501         return {
 1502             'block_device_mapping': [driver_bdm]
 1503         }
 1504 
 1505     @mock.patch.object(FAKE_CLIENT.volume_target, 'create')
 1506     def test__add_volume_target_info(self, mock_create):
 1507         node = ironic_utils.get_test_node(driver='fake')
 1508         instance = fake_instance.fake_instance_obj(self.ctx, node=node.uuid)
 1509 
 1510         block_device_info = self._create_fake_block_device_info()
 1511         self.driver._add_volume_target_info(self.ctx, instance,
 1512                                             block_device_info)
 1513 
 1514         expected_volume_type = 'fake_type'
 1515         expected_properties = 'fake_data'
 1516         expected_boot_index = 0
 1517 
 1518         mock_create.assert_called_once_with(node_uuid=instance.node,
 1519                                             volume_type=expected_volume_type,
 1520                                             properties=expected_properties,
 1521                                             boot_index=expected_boot_index,
 1522                                             volume_id='fake-volume-id-1')
 1523 
 1524     @mock.patch.object(FAKE_CLIENT.volume_target, 'create')
 1525     def test__add_volume_target_info_empty_bdms(self, mock_create):
 1526         node = ironic_utils.get_test_node(driver='fake')
 1527         instance = fake_instance.fake_instance_obj(self.ctx, node=node.uuid)
 1528 
 1529         self.driver._add_volume_target_info(self.ctx, instance, None)
 1530 
 1531         self.assertFalse(mock_create.called)
 1532 
 1533     @mock.patch.object(FAKE_CLIENT.volume_target, 'create')
 1534     def test__add_volume_target_info_failures(self, mock_create):
 1535         node = ironic_utils.get_test_node(driver='fake')
 1536         instance = fake_instance.fake_instance_obj(self.ctx, node=node.uuid)
 1537 
 1538         block_device_info = self._create_fake_block_device_info()
 1539 
 1540         exceptions = [
 1541             ironic_exception.BadRequest(),
 1542             ironic_exception.Conflict(),
 1543         ]
 1544         for e in exceptions:
 1545             mock_create.side_effect = e
 1546             self.assertRaises(exception.InstanceDeployFailure,
 1547                               self.driver._add_volume_target_info,
 1548                               self.ctx, instance, block_device_info)
 1549 
 1550     @mock.patch.object(FAKE_CLIENT.volume_target, 'delete')
 1551     @mock.patch.object(FAKE_CLIENT.node, 'list_volume_targets')
 1552     def test__cleanup_volume_target_info(self, mock_lvt, mock_delete):
 1553         node = ironic_utils.get_test_node(driver='fake')
 1554         instance = fake_instance.fake_instance_obj(self.ctx, node=node.uuid)
 1555         mock_lvt.return_value = [ironic_utils.get_test_volume_target(
 1556             uuid='fake_uuid')]
 1557 
 1558         self.driver._cleanup_volume_target_info(instance)
 1559         expected_volume_target_id = 'fake_uuid'
 1560 
 1561         mock_delete.assert_called_once_with(expected_volume_target_id)
 1562 
 1563     @mock.patch.object(FAKE_CLIENT.volume_target, 'delete')
 1564     @mock.patch.object(FAKE_CLIENT.node, 'list_volume_targets')
 1565     def test__cleanup_volume_target_info_empty_targets(self, mock_lvt,
 1566                                                        mock_delete):
 1567         node = ironic_utils.get_test_node(driver='fake')
 1568         instance = fake_instance.fake_instance_obj(self.ctx, node=node.uuid)
 1569         mock_lvt.return_value = []
 1570 
 1571         self.driver._cleanup_volume_target_info(instance)
 1572 
 1573         self.assertFalse(mock_delete.called)
 1574 
 1575     @mock.patch.object(FAKE_CLIENT.volume_target, 'delete')
 1576     @mock.patch.object(FAKE_CLIENT.node, 'list_volume_targets')
 1577     def test__cleanup_volume_target_info_not_found(self, mock_lvt,
 1578                                                    mock_delete):
 1579         node = ironic_utils.get_test_node(driver='fake')
 1580         instance = fake_instance.fake_instance_obj(self.ctx, node=node.uuid)
 1581         mock_lvt.return_value = [
 1582             ironic_utils.get_test_volume_target(uuid='fake_uuid1'),
 1583             ironic_utils.get_test_volume_target(uuid='fake_uuid2'),
 1584         ]
 1585         mock_delete.side_effect = [ironic_exception.NotFound('not found'),
 1586                                    None]
 1587 
 1588         self.driver._cleanup_volume_target_info(instance)
 1589 
 1590         self.assertEqual([mock.call('fake_uuid1'), mock.call('fake_uuid2')],
 1591                          mock_delete.call_args_list)
 1592 
 1593     @mock.patch.object(FAKE_CLIENT.volume_target, 'delete')
 1594     @mock.patch.object(FAKE_CLIENT.node, 'list_volume_targets')
 1595     def test__cleanup_volume_target_info_bad_request(self, mock_lvt,
 1596                                                      mock_delete):
 1597         node = ironic_utils.get_test_node(driver='fake')
 1598         instance = fake_instance.fake_instance_obj(self.ctx, node=node.uuid)
 1599         mock_lvt.return_value = [
 1600             ironic_utils.get_test_volume_target(uuid='fake_uuid1'),
 1601             ironic_utils.get_test_volume_target(uuid='fake_uuid2'),
 1602         ]
 1603         mock_delete.side_effect = [ironic_exception.BadRequest('error'),
 1604                                    None]
 1605 
 1606         self.driver._cleanup_volume_target_info(instance)
 1607 
 1608         self.assertEqual([mock.call('fake_uuid1'), mock.call('fake_uuid2')],
 1609                          mock_delete.call_args_list)
 1610 
 1611     @mock.patch.object(configdrive, 'required_by')
 1612     @mock.patch.object(FAKE_CLIENT, 'node')
 1613     @mock.patch.object(ironic_driver.IronicDriver, '_add_volume_target_info')
 1614     def test_spawn_node_driver_validation_fail(self, mock_avti, mock_node,
 1615                                                mock_required_by):
 1616         mock_required_by.return_value = False
 1617         node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
 1618         node = _get_cached_node(driver='fake', uuid=node_uuid)
 1619         flavor = ironic_utils.get_test_flavor()
 1620         instance = fake_instance.fake_instance_obj(self.ctx, node=node_uuid)
 1621         instance.flavor = flavor
 1622 
 1623         mock_node.validate.return_value = ironic_utils.get_test_validation(
 1624             power={'result': False}, deploy={'result': False},
 1625             storage={'result': False})
 1626         mock_node.get.return_value = node
 1627         image_meta = ironic_utils.get_test_image_meta()
 1628 
 1629         self.assertRaises(exception.ValidationError, self.driver.spawn,
 1630                           self.ctx, instance, image_meta, [], None, {})
 1631         self.assertEqual(1, mock_node.get.call_count)
 1632         mock_node.get.assert_called_once_with(
 1633             node_uuid, fields=ironic_driver._NODE_FIELDS)
 1634         mock_avti.assert_called_once_with(self.ctx, instance, None)
 1635         mock_node.validate.assert_called_once_with(node_uuid)
 1636 
 1637     @mock.patch.object(configdrive, 'required_by')
 1638     @mock.patch.object(FAKE_CLIENT, 'node')
 1639     @mock.patch.object(ironic_driver.IronicDriver, '_add_volume_target_info')
 1640     @mock.patch.object(ironic_driver.IronicDriver, '_start_firewall')
 1641     @mock.patch.object(ironic_driver.IronicDriver, '_cleanup_deploy')
 1642     def test_spawn_node_prepare_for_deploy_fail(self, mock_cleanup_deploy,
 1643                                                 mock_sf, mock_avti,
 1644                                                 mock_node, mock_required_by):
 1645         mock_required_by.return_value = False
 1646         node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
 1647         node = _get_cached_node(driver='fake', uuid=node_uuid)
 1648         flavor = ironic_utils.get_test_flavor()
 1649         instance = fake_instance.fake_instance_obj(self.ctx, node=node_uuid)
 1650         instance.flavor = flavor
 1651         mock_node.get.return_value = node
 1652         mock_node.validate.return_value = ironic_utils.get_test_validation()
 1653         image_meta = ironic_utils.get_test_image_meta()
 1654 
 1655         mock_sf.side_effect = test.TestingException()
 1656         self.assertRaises(test.TestingException, self.driver.spawn,
 1657                           self.ctx, instance, image_meta, [], None, {})
 1658 
 1659         mock_node.get.assert_called_once_with(
 1660             node_uuid, fields=ironic_driver._NODE_FIELDS)
 1661         mock_node.validate.assert_called_once_with(node_uuid)
 1662         mock_cleanup_deploy.assert_called_with(node, instance, None)
 1663 
 1664     @mock.patch.object(configdrive, 'required_by')
 1665     @mock.patch.object(objects.Instance, 'save')
 1666     @mock.patch.object(FAKE_CLIENT, 'node')
 1667     @mock.patch.object(ironic_driver.IronicDriver, '_add_volume_target_info')
 1668     @mock.patch.object(ironic_driver.IronicDriver, '_generate_configdrive')
 1669     @mock.patch.object(ironic_driver.IronicDriver, '_start_firewall')
 1670     def test_spawn_node_configdrive_fail(self,
 1671                                          mock_sf, mock_configdrive,
 1672                                          mock_avti, mock_node, mock_save,
 1673                                          mock_required_by):
 1674         mock_required_by.return_value = True
 1675         node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
 1676         node = _get_cached_node(driver='fake', uuid=node_uuid)
 1677         flavor = ironic_utils.get_test_flavor()
 1678         instance = fake_instance.fake_instance_obj(self.ctx, node=node_uuid)
 1679         instance.flavor = flavor
 1680         mock_node.get.return_value = node
 1681         mock_node.validate.return_value = ironic_utils.get_test_validation()
 1682         image_meta = ironic_utils.get_test_image_meta()
 1683 
 1684         mock_configdrive.side_effect = test.TestingException()
 1685         with mock.patch.object(self.driver, '_cleanup_deploy',
 1686                                autospec=True) as mock_cleanup_deploy:
 1687             self.assertRaises(test.TestingException, self.driver.spawn,
 1688                               self.ctx, instance, image_meta, [], None, {})
 1689 
 1690         mock_node.get.assert_called_once_with(
 1691                 node_uuid, fields=ironic_driver._NODE_FIELDS)
 1692         mock_node.validate.assert_called_once_with(node_uuid)
 1693         mock_cleanup_deploy.assert_called_with(node, instance, None)
 1694 
 1695     @mock.patch.object(configdrive, 'required_by')
 1696     @mock.patch.object(FAKE_CLIENT, 'node')
 1697     @mock.patch.object(ironic_driver.IronicDriver, '_add_volume_target_info')
 1698     @mock.patch.object(ironic_driver.IronicDriver, '_start_firewall')
 1699     @mock.patch.object(ironic_driver.IronicDriver, '_cleanup_deploy')
 1700     def test_spawn_node_trigger_deploy_fail(self, mock_cleanup_deploy,
 1701                                             mock_sf, mock_avti,
 1702                                             mock_node, mock_required_by):
 1703         mock_required_by.return_value = False
 1704         node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
 1705         node = _get_cached_node(driver='fake', uuid=node_uuid)
 1706         flavor = ironic_utils.get_test_flavor()
 1707         instance = fake_instance.fake_instance_obj(self.ctx, node=node_uuid)
 1708         instance.flavor = flavor
 1709         image_meta = ironic_utils.get_test_image_meta()
 1710 
 1711         mock_node.get.return_value = node
 1712         mock_node.validate.return_value = ironic_utils.get_test_validation()
 1713 
 1714         mock_node.set_provision_state.side_effect = exception.NovaException()
 1715         self.assertRaises(exception.NovaException, self.driver.spawn,
 1716                           self.ctx, instance, image_meta, [], None, {})
 1717 
 1718         mock_node.get.assert_called_once_with(
 1719             node_uuid, fields=ironic_driver._NODE_FIELDS)
 1720         mock_node.validate.assert_called_once_with(node_uuid)
 1721         mock_cleanup_deploy.assert_called_once_with(node, instance, None)
 1722 
 1723     @mock.patch.object(configdrive, 'required_by')
 1724     @mock.patch.object(FAKE_CLIENT, 'node')
 1725     @mock.patch.object(ironic_driver.IronicDriver, '_add_volume_target_info')
 1726     @mock.patch.object(ironic_driver.IronicDriver, '_start_firewall')
 1727     @mock.patch.object(ironic_driver.IronicDriver, '_cleanup_deploy')
 1728     def test_spawn_node_trigger_deploy_fail2(self, mock_cleanup_deploy,
 1729                                              mock_sf, mock_avti,
 1730                                              mock_node, mock_required_by):
 1731         mock_required_by.return_value = False
 1732         node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
 1733         node = _get_cached_node(driver='fake', uuid=node_uuid)
 1734         flavor = ironic_utils.get_test_flavor()
 1735         instance = fake_instance.fake_instance_obj(self.ctx, node=node_uuid)
 1736         instance.flavor = flavor
 1737         image_meta = ironic_utils.get_test_image_meta()
 1738 
 1739         mock_node.get.return_value = node
 1740         mock_node.validate.return_value = ironic_utils.get_test_validation()
 1741         mock_node.set_provision_state.side_effect = ironic_exception.BadRequest
 1742         self.assertRaises(ironic_exception.BadRequest,
 1743                           self.driver.spawn,
 1744                           self.ctx, instance, image_meta, [], None, {})
 1745 
 1746         mock_node.get.assert_called_once_with(
 1747             node_uuid, fields=ironic_driver._NODE_FIELDS)
 1748         mock_node.validate.assert_called_once_with(node_uuid)
 1749         mock_cleanup_deploy.assert_called_once_with(node, instance, None)
 1750 
 1751     @mock.patch.object(configdrive, 'required_by')
 1752     @mock.patch.object(loopingcall, 'FixedIntervalLoopingCall')
 1753     @mock.patch.object(FAKE_CLIENT, 'node')
 1754     @mock.patch.object(ironic_driver.IronicDriver, '_add_volume_target_info')
 1755     @mock.patch.object(ironic_driver.IronicDriver, '_start_firewall')
 1756     @mock.patch.object(ironic_driver.IronicDriver, 'destroy')
 1757     def test_spawn_node_trigger_deploy_fail3(self, mock_destroy,
 1758                                              mock_sf, mock_avti,
 1759                                              mock_node, mock_looping,
 1760                                              mock_required_by):
 1761         mock_required_by.return_value = False
 1762         node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
 1763         node = _get_cached_node(driver='fake', uuid=node_uuid)
 1764         flavor = ironic_utils.get_test_flavor()
 1765         instance = fake_instance.fake_instance_obj(self.ctx, node=node_uuid)
 1766         instance.flavor = flavor
 1767         image_meta = ironic_utils.get_test_image_meta()
 1768 
 1769         mock_node.get.return_value = node
 1770         mock_node.validate.return_value = ironic_utils.get_test_validation()
 1771 
 1772         fake_looping_call = FakeLoopingCall()
 1773         mock_looping.return_value = fake_looping_call
 1774 
 1775         fake_looping_call.wait.side_effect = ironic_exception.BadRequest
 1776         fake_net_info = utils.get_test_network_info()
 1777         self.assertRaises(ironic_exception.BadRequest,
 1778                           self.driver.spawn, self.ctx, instance,
 1779                           image_meta, [], None, {}, fake_net_info)
 1780         self.assertEqual(0, mock_destroy.call_count)
 1781 
 1782     @mock.patch.object(configdrive, 'required_by')
 1783     @mock.patch.object(loopingcall, 'FixedIntervalLoopingCall')
 1784     @mock.patch.object(objects.Instance, 'save')
 1785     @mock.patch.object(FAKE_CLIENT, 'node')
 1786     @mock.patch.object(ironic_driver.IronicDriver, '_add_volume_target_info')
 1787     @mock.patch.object(ironic_driver.IronicDriver, '_wait_for_active')
 1788     @mock.patch.object(ironic_driver.IronicDriver, '_start_firewall')
 1789     def test_spawn_sets_default_ephemeral_device(self, mock_sf,
 1790                                                  mock_wait, mock_avti,
 1791                                                  mock_node, mock_save,
 1792                                                  mock_looping,
 1793                                                  mock_required_by):
 1794         mock_required_by.return_value = False
 1795         node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
 1796         node = _get_cached_node(driver='fake', uuid=node_uuid)
 1797         flavor = ironic_utils.get_test_flavor(ephemeral_gb=1)
 1798         instance = fake_instance.fake_instance_obj(self.ctx, node=node_uuid)
 1799         instance.flavor = flavor
 1800         mock_node.get_by_instance_uuid.return_value = node
 1801         mock_node.set_provision_state.return_value = mock.MagicMock()
 1802         image_meta = ironic_utils.get_test_image_meta()
 1803 
 1804         self.driver.spawn(self.ctx, instance, image_meta, [], None, {})
 1805         self.assertTrue(mock_save.called)
 1806         self.assertEqual('/dev/sda1', instance.default_ephemeral_device)
 1807 
 1808     @mock.patch.object(FAKE_CLIENT, 'node')
 1809     @mock.patch.object(ironic_driver.IronicDriver,
 1810                        '_remove_instance_info_from_node')
 1811     @mock.patch.object(ironic_driver.IronicDriver, '_cleanup_deploy')
 1812     def _test_destroy(self, state, mock_cleanup_deploy,
 1813                       mock_remove_instance_info, mock_node):
 1814         node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
 1815         network_info = 'foo'
 1816 
 1817         node = _get_cached_node(
 1818                 driver='fake', uuid=node_uuid, provision_state=state)
 1819         instance = fake_instance.fake_instance_obj(self.ctx, node=node_uuid)
 1820 
 1821         def fake_set_provision_state(*_):
 1822             node.provision_state = None
 1823 
 1824         mock_node.get_by_instance_uuid.return_value = node
 1825         mock_node.set_provision_state.side_effect = fake_set_provision_state
 1826         self.driver.destroy(self.ctx, instance, network_info, None)
 1827 
 1828         mock_node.get_by_instance_uuid.assert_called_with(
 1829             instance.uuid, fields=ironic_driver._NODE_FIELDS)
 1830         mock_cleanup_deploy.assert_called_with(node, instance, network_info,
 1831                                                remove_instance_info=False)
 1832 
 1833         # For states that makes sense check if set_provision_state has
 1834         # been called
 1835         if state in ironic_driver._UNPROVISION_STATES:
 1836             mock_node.set_provision_state.assert_called_once_with(
 1837                 node_uuid, 'deleted')
 1838             self.assertFalse(mock_remove_instance_info.called)
 1839         else:
 1840             self.assertFalse(mock_node.set_provision_state.called)
 1841             mock_remove_instance_info.assert_called_once_with(node, instance)
 1842 
 1843     def test_destroy(self):
 1844         for state in ironic_states.PROVISION_STATE_LIST:
 1845             self._test_destroy(state)
 1846 
 1847     @mock.patch.object(FAKE_CLIENT.node, 'set_provision_state')
 1848     @mock.patch.object(ironic_driver.IronicDriver,
 1849                        '_validate_instance_and_node')
 1850     @mock.patch.object(ironic_driver.IronicDriver,
 1851                        '_cleanup_deploy')
 1852     def test_destroy_trigger_undeploy_fail(self, mock_clean, fake_validate,
 1853                                            mock_sps):
 1854         node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
 1855         node = _get_cached_node(
 1856                 driver='fake', uuid=node_uuid,
 1857                 provision_state=ironic_states.ACTIVE)
 1858         fake_validate.return_value = node
 1859         instance = fake_instance.fake_instance_obj(self.ctx,
 1860                                                    node=node_uuid)
 1861         mock_sps.side_effect = exception.NovaException()
 1862         self.assertRaises(exception.NovaException, self.driver.destroy,
 1863                           self.ctx, instance, None, None)
 1864         mock_clean.assert_called_once_with(node, instance, None,
 1865                                            remove_instance_info=False)
 1866 
 1867     @mock.patch.object(FAKE_CLIENT.node, 'update')
 1868     @mock.patch.object(ironic_driver.IronicDriver,
 1869                        '_validate_instance_and_node')
 1870     @mock.patch.object(ironic_driver.IronicDriver,
 1871                        '_cleanup_deploy')
 1872     def test_destroy_trigger_remove_info_fail(self, mock_clean, fake_validate,
 1873                                               mock_update):
 1874         node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
 1875         node = ironic_utils.get_test_node(
 1876             driver='fake', uuid=node_uuid,
 1877             provision_state=ironic_states.AVAILABLE)
 1878         fake_validate.return_value = node
 1879         instance = fake_instance.fake_instance_obj(self.ctx,
 1880                                                    node=node_uuid)
 1881         mock_update.side_effect = SystemError('unexpected error')
 1882         self.assertRaises(SystemError, self.driver.destroy,
 1883                           self.ctx, instance, None, None)
 1884         mock_clean.assert_called_once_with(node, instance, None,
 1885                                            remove_instance_info=False)
 1886 
 1887     @mock.patch.object(FAKE_CLIENT.node, 'set_provision_state')
 1888     @mock.patch.object(ironic_driver.IronicDriver,
 1889                        '_validate_instance_and_node')
 1890     def _test__unprovision_instance(self, mock_validate_inst, mock_set_pstate,
 1891                                     state=None):
 1892         node = _get_cached_node(driver='fake', provision_state=state)
 1893         instance = fake_instance.fake_instance_obj(self.ctx, node=node.uuid)
 1894         mock_validate_inst.return_value = node
 1895         with mock.patch.object(self.driver, 'node_cache') as cache_mock:
 1896             self.driver._unprovision(instance, node)
 1897         mock_validate_inst.assert_called_once_with(instance)
 1898         mock_set_pstate.assert_called_once_with(node.uuid, "deleted")
 1899         cache_mock.pop.assert_called_once_with(node.uuid, None)
 1900 
 1901     def test__unprovision_cleaning(self):
 1902         self._test__unprovision_instance(state=ironic_states.CLEANING)
 1903 
 1904     def test__unprovision_cleanwait(self):
 1905         self._test__unprovision_instance(state=ironic_states.CLEANWAIT)
 1906 
 1907     @mock.patch.object(FAKE_CLIENT.node, 'set_provision_state')
 1908     @mock.patch.object(ironic_driver.IronicDriver,
 1909                        '_validate_instance_and_node')
 1910     def test__unprovision_fail_max_retries(self, mock_validate_inst,
 1911                                            mock_set_pstate):
 1912         CONF.set_default('api_max_retries', default=2, group='ironic')
 1913         node = _get_cached_node(
 1914             driver='fake', provision_state=ironic_states.ACTIVE)
 1915         instance = fake_instance.fake_instance_obj(self.ctx, node=node.uuid)
 1916 
 1917         mock_validate_inst.return_value = node
 1918         self.assertRaises(exception.NovaException, self.driver._unprovision,
 1919                           instance, node)
 1920         expected_calls = (mock.call(instance),
 1921                           mock.call(instance))
 1922         mock_validate_inst.assert_has_calls(expected_calls)
 1923         mock_set_pstate.assert_called_once_with(node.uuid, "deleted")
 1924 
 1925     @mock.patch.object(FAKE_CLIENT.node, 'set_provision_state')
 1926     @mock.patch.object(ironic_driver.IronicDriver,
 1927                        '_validate_instance_and_node')
 1928     def test__unprovision_instance_not_found(self, mock_validate_inst,
 1929                                              mock_set_pstate):
 1930         node = _get_cached_node(
 1931             driver='fake', provision_state=ironic_states.DELETING)
 1932         instance = fake_instance.fake_instance_obj(self.ctx, node=node.uuid)
 1933 
 1934         mock_validate_inst.side_effect = exception.InstanceNotFound(
 1935             instance_id='fake')
 1936         self.driver._unprovision(instance, node)
 1937         mock_validate_inst.assert_called_once_with(instance)
 1938         mock_set_pstate.assert_called_once_with(node.uuid, "deleted")
 1939 
 1940     @mock.patch.object(FAKE_CLIENT, 'node')
 1941     def test_destroy_unassociate_fail(self, mock_node):
 1942         node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
 1943         node = _get_cached_node(
 1944                 driver='fake', uuid=node_uuid,
 1945                 provision_state=ironic_states.ACTIVE)
 1946         instance = fake_instance.fake_instance_obj(self.ctx, node=node_uuid)
 1947 
 1948         mock_node.get_by_instance_uuid.return_value = node
 1949         mock_node.update.side_effect = exception.NovaException()
 1950         self.assertRaises(exception.NovaException, self.driver.destroy,
 1951                           self.ctx, instance, None, None)
 1952         mock_node.set_provision_state.assert_called_once_with(node_uuid,
 1953                                                               'deleted')
 1954         mock_node.get_by_instance_uuid.assert_called_with(
 1955             instance.uuid, fields=ironic_driver._NODE_FIELDS)
 1956 
 1957     @mock.patch.object(loopingcall, 'FixedIntervalLoopingCall')
 1958     @mock.patch.object(ironic_driver.IronicDriver,
 1959                        '_validate_instance_and_node')
 1960     @mock.patch.object(FAKE_CLIENT.node, 'set_power_state')
 1961     def test_reboot(self, mock_sp, fake_validate, mock_looping):
 1962         node = _get_cached_node()
 1963         fake_validate.side_effect = [node, node]
 1964 
 1965         fake_looping_call = FakeLoopingCall()
 1966         mock_looping.return_value = fake_looping_call
 1967         instance = fake_instance.fake_instance_obj(self.ctx,
 1968                                                    node=node.uuid)
 1969         self.driver.reboot(self.ctx, instance, None, 'HARD')
 1970         mock_sp.assert_called_once_with(node.uuid, 'reboot')
 1971 
 1972     @mock.patch.object(ironic_driver.IronicDriver,
 1973                        '_validate_instance_and_node')
 1974     @mock.patch.object(FAKE_CLIENT.node, 'inject_nmi')
 1975     def test_trigger_crash_dump(self, mock_nmi, fake_validate):
 1976         node = _get_cached_node()
 1977         fake_validate.return_value = node
 1978         instance = fake_instance.fake_instance_obj(self.ctx,
 1979                                                    node=node.uuid)
 1980         self.driver.trigger_crash_dump(instance)
 1981         mock_nmi.assert_called_once_with(node.uuid)
 1982 
 1983     @mock.patch.object(ironic_driver.IronicDriver,
 1984                        '_validate_instance_and_node')
 1985     @mock.patch.object(FAKE_CLIENT.node, 'inject_nmi')
 1986     def test_trigger_crash_dump_error(self, mock_nmi, fake_validate):
 1987         node = _get_cached_node()
 1988         fake_validate.return_value = node
 1989         mock_nmi.side_effect = ironic_exception.BadRequest()
 1990         instance = fake_instance.fake_instance_obj(self.ctx,
 1991                                                    node=node.uuid)
 1992         self.assertRaises(ironic_exception.BadRequest,
 1993                           self.driver.trigger_crash_dump, instance)
 1994 
 1995     @mock.patch.object(loopingcall, 'FixedIntervalLoopingCall')
 1996     @mock.patch.object(ironic_driver.IronicDriver,
 1997                        '_validate_instance_and_node')
 1998     @mock.patch.object(FAKE_CLIENT.node, 'set_power_state')
 1999     def test_reboot_soft(self, mock_sp, fake_validate, mock_looping):
 2000         node = _get_cached_node()
 2001         fake_validate.side_effect = [node, node]
 2002 
 2003         fake_looping_call = FakeLoopingCall()
 2004         mock_looping.return_value = fake_looping_call
 2005         instance = fake_instance.fake_instance_obj(self.ctx,
 2006                                                    node=node.uuid)
 2007         self.driver.reboot(self.ctx, instance, None, 'SOFT')
 2008         mock_sp.assert_called_once_with(node.uuid, 'reboot', soft=True)
 2009 
 2010     @mock.patch.object(loopingcall, 'FixedIntervalLoopingCall')
 2011     @mock.patch.object(ironic_driver.IronicDriver,
 2012                        '_validate_instance_and_node')
 2013     @mock.patch.object(FAKE_CLIENT.node, 'set_power_state')
 2014     def test_reboot_soft_not_supported(self, mock_sp, fake_validate,
 2015                                        mock_looping):
 2016         node = _get_cached_node()
 2017         fake_validate.side_effect = [node, node]
 2018         mock_sp.side_effect = [ironic_exception.BadRequest(), None]
 2019 
 2020         fake_looping_call = FakeLoopingCall()
 2021         mock_looping.return_value = fake_looping_call
 2022         instance = fake_instance.fake_instance_obj(self.ctx,
 2023                                                    node=node.uuid)
 2024         self.driver.reboot(self.ctx, instance, None, 'SOFT')
 2025         mock_sp.assert_has_calls([mock.call(node.uuid, 'reboot', soft=True),
 2026                                   mock.call(node.uuid, 'reboot')])
 2027 
 2028     @mock.patch.object(loopingcall, 'FixedIntervalLoopingCall')
 2029     @mock.patch.object(ironic_driver.IronicDriver,
 2030                        '_validate_instance_and_node')
 2031     @mock.patch.object(FAKE_CLIENT.node, 'set_power_state')
 2032     def test_power_on(self, mock_sp, fake_validate, mock_looping):
 2033         node = _get_cached_node()
 2034         fake_validate.side_effect = [node, node]
 2035 
 2036         fake_looping_call = FakeLoopingCall()
 2037         mock_looping.return_value = fake_looping_call
 2038         instance = fake_instance.fake_instance_obj(self.ctx,
 2039                                                    node=self.instance_uuid)
 2040         self.driver.power_on(self.ctx, instance,
 2041                              utils.get_test_network_info())
 2042         mock_sp.assert_called_once_with(node.uuid, 'on')
 2043 
 2044     @mock.patch.object(loopingcall, 'FixedIntervalLoopingCall')
 2045     def _test_power_off(self, mock_looping, timeout=0):
 2046         fake_looping_call = FakeLoopingCall()
 2047         mock_looping.return_value = fake_looping_call
 2048         instance = fake_instance.fake_instance_obj(self.ctx,
 2049                                                    node=self.instance_uuid)
 2050         self.driver.power_off(instance, timeout)
 2051 
 2052     @mock.patch.object(ironic_driver.IronicDriver,
 2053                        '_validate_instance_and_node')
 2054     @mock.patch.object(FAKE_CLIENT.node, 'set_power_state')
 2055     def test_power_off(self, mock_sp, fake_validate):
 2056         node = _get_cached_node()
 2057         fake_validate.side_effect = [node, node]
 2058 
 2059         self._test_power_off()
 2060         mock_sp.assert_called_once_with(node.uuid, 'off')
 2061 
 2062     @mock.patch.object(ironic_driver.IronicDriver,
 2063                        '_validate_instance_and_node')
 2064     @mock.patch.object(FAKE_CLIENT.node, 'set_power_state')
 2065     def test_power_off_soft(self, mock_sp, fake_validate):
 2066         node = _get_cached_node()
 2067         power_off_node = _get_cached_node(power_state=ironic_states.POWER_OFF)
 2068         fake_validate.side_effect = [node, power_off_node]
 2069 
 2070         self._test_power_off(timeout=30)
 2071         mock_sp.assert_called_once_with(node.uuid, 'off', soft=True,
 2072                                         timeout=30)
 2073 
 2074     @mock.patch.object(ironic_driver.IronicDriver,
 2075                        '_validate_instance_and_node')
 2076     @mock.patch.object(FAKE_CLIENT.node, 'set_power_state')
 2077     def test_power_off_soft_exception(self, mock_sp, fake_validate):
 2078         node = _get_cached_node()
 2079         fake_validate.side_effect = [node, node]
 2080         mock_sp.side_effect = [ironic_exception.BadRequest(), None]
 2081 
 2082         self._test_power_off(timeout=30)
 2083         expected_calls = [mock.call(node.uuid, 'off', soft=True, timeout=30),
 2084                           mock.call(node.uuid, 'off')]
 2085         self.assertEqual(len(expected_calls), mock_sp.call_count)
 2086         mock_sp.assert_has_calls(expected_calls)
 2087 
 2088     @mock.patch.object(ironic_driver.IronicDriver,
 2089                        '_validate_instance_and_node')
 2090     @mock.patch.object(FAKE_CLIENT.node, 'set_power_state')
 2091     def test_power_off_soft_not_stopped(self, mock_sp, fake_validate):
 2092         node = _get_cached_node()
 2093         fake_validate.side_effect = [node, node]
 2094 
 2095         self._test_power_off(timeout=30)
 2096         expected_calls = [mock.call(node.uuid, 'off', soft=True, timeout=30),
 2097                           mock.call(node.uuid, 'off')]
 2098         self.assertEqual(len(expected_calls), mock_sp.call_count)
 2099         mock_sp.assert_has_calls(expected_calls)
 2100 
 2101     @mock.patch.object(FAKE_CLIENT.node, 'vif_attach')
 2102     def test_plug_vifs_with_port(self, mock_vatt):
 2103         node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
 2104         node = _get_cached_node(uuid=node_uuid)
 2105 
 2106         instance = fake_instance.fake_instance_obj(self.ctx,
 2107                                                    node=node_uuid)
 2108         network_info = utils.get_test_network_info()
 2109         vif_id = six.text_type(network_info[0]['id'])
 2110 
 2111         self.driver._plug_vifs(node, instance, network_info)
 2112 
 2113         # asserts
 2114         mock_vatt.assert_called_with(node.uuid, vif_id)
 2115 
 2116     @mock.patch.object(FAKE_CLIENT.node, 'get')
 2117     @mock.patch.object(ironic_driver.IronicDriver, '_plug_vifs')
 2118     def test_plug_vifs(self, mock__plug_vifs, mock_get):
 2119         node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
 2120         node = _get_cached_node(uuid=node_uuid)
 2121 
 2122         mock_get.return_value = node
 2123         instance = fake_instance.fake_instance_obj(self.ctx,
 2124                                                    node=node_uuid)
 2125         network_info = utils.get_test_network_info()
 2126         self.driver.plug_vifs(instance, network_info)
 2127 
 2128         mock_get.assert_called_once_with(node_uuid,
 2129                                          fields=ironic_driver._NODE_FIELDS)
 2130         mock__plug_vifs.assert_called_once_with(node, instance, network_info)
 2131 
 2132     @mock.patch.object(FAKE_CLIENT.node, 'vif_attach')
 2133     def test_plug_vifs_multiple_ports(self, mock_vatt):
 2134         node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
 2135         node = _get_cached_node(uuid=node_uuid)
 2136         instance = fake_instance.fake_instance_obj(self.ctx,
 2137                                                    node=node_uuid)
 2138         first_vif_id = 'aaaaaaaa-vv11-cccc-dddd-eeeeeeeeeeee'
 2139         second_vif_id = 'aaaaaaaa-vv22-cccc-dddd-eeeeeeeeeeee'
 2140         first_vif = ironic_utils.get_test_vif(address='22:FF:FF:FF:FF:FF',
 2141                                               id=first_vif_id)
 2142         second_vif = ironic_utils.get_test_vif(address='11:FF:FF:FF:FF:FF',
 2143                                                id=second_vif_id)
 2144         network_info = [first_vif, second_vif]
 2145         self.driver._plug_vifs(node, instance, network_info)
 2146 
 2147         # asserts
 2148         calls = (mock.call(node.uuid, first_vif_id),
 2149                  mock.call(node.uuid, second_vif_id))
 2150         mock_vatt.assert_has_calls(calls, any_order=True)
 2151 
 2152     @mock.patch.object(FAKE_CLIENT, 'node')
 2153     def test_plug_vifs_failure(self, mock_node):
 2154         node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
 2155         node = _get_cached_node(uuid=node_uuid)
 2156         instance = fake_instance.fake_instance_obj(self.ctx,
 2157                                                    node=node_uuid)
 2158         first_vif_id = 'aaaaaaaa-vv11-cccc-dddd-eeeeeeeeeeee'
 2159         second_vif_id = 'aaaaaaaa-vv22-cccc-dddd-eeeeeeeeeeee'
 2160         first_vif = ironic_utils.get_test_vif(address='22:FF:FF:FF:FF:FF',
 2161                                               id=first_vif_id)
 2162         second_vif = ironic_utils.get_test_vif(address='11:FF:FF:FF:FF:FF',
 2163                                                id=second_vif_id)
 2164         mock_node.vif_attach.side_effect = [None,
 2165                                             ironic_exception.BadRequest()]
 2166         network_info = [first_vif, second_vif]
 2167         self.assertRaises(exception.VirtualInterfacePlugException,
 2168                           self.driver._plug_vifs, node, instance,
 2169                           network_info)
 2170 
 2171     @mock.patch('time.sleep')
 2172     @mock.patch.object(FAKE_CLIENT, 'node')
 2173     def test_plug_vifs_failure_no_conductor(self, mock_node, mock_sleep):
 2174         node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
 2175         node = _get_cached_node(uuid=node_uuid)
 2176         instance = fake_instance.fake_instance_obj(self.ctx,
 2177                                                    node=node_uuid)
 2178         first_vif_id = 'aaaaaaaa-vv11-cccc-dddd-eeeeeeeeeeee'
 2179         second_vif_id = 'aaaaaaaa-vv22-cccc-dddd-eeeeeeeeeeee'
 2180         first_vif = ironic_utils.get_test_vif(address='22:FF:FF:FF:FF:FF',
 2181                                               id=first_vif_id)
 2182         second_vif = ironic_utils.get_test_vif(address='11:FF:FF:FF:FF:FF',
 2183                                                id=second_vif_id)
 2184         msg = 'No conductor service registered which supports driver ipmi.'
 2185         mock_node.vif_attach.side_effect = [None,
 2186                                             ironic_exception.BadRequest(msg),
 2187                                             None]
 2188         network_info = [first_vif, second_vif]
 2189         self.driver._plug_vifs(node, instance, network_info)
 2190         calls = [mock.call(node.uuid, first_vif_id),
 2191                  mock.call(node.uuid, second_vif_id),
 2192                  mock.call(node.uuid, second_vif_id)]
 2193         mock_node.vif_attach.assert_has_calls(calls, any_order=True)
 2194 
 2195     @mock.patch.object(FAKE_CLIENT, 'node')
 2196     def test_plug_vifs_already_attached(self, mock_node):
 2197         node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
 2198         node = _get_cached_node(uuid=node_uuid)
 2199         instance = fake_instance.fake_instance_obj(self.ctx,
 2200                                                    node=node_uuid)
 2201         first_vif_id = 'aaaaaaaa-vv11-cccc-dddd-eeeeeeeeeeee'
 2202         second_vif_id = 'aaaaaaaa-vv22-cccc-dddd-eeeeeeeeeeee'
 2203         first_vif = ironic_utils.get_test_vif(address='22:FF:FF:FF:FF:FF',
 2204                                               id=first_vif_id)
 2205         second_vif = ironic_utils.get_test_vif(address='11:FF:FF:FF:FF:FF',
 2206                                                id=second_vif_id)
 2207         mock_node.vif_attach.side_effect = [ironic_exception.Conflict(),
 2208                                             None]
 2209         network_info = [first_vif, second_vif]
 2210         self.driver._plug_vifs(node, instance, network_info)
 2211         self.assertEqual(2, mock_node.vif_attach.call_count)
 2212 
 2213     @mock.patch.object(FAKE_CLIENT.node, 'vif_attach')
 2214     def test_plug_vifs_no_network_info(self, mock_vatt):
 2215         node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
 2216         node = _get_cached_node(uuid=node_uuid)
 2217 
 2218         instance = fake_instance.fake_instance_obj(self.ctx,
 2219                                                    node=node_uuid)
 2220         network_info = []
 2221         self.driver._plug_vifs(node, instance, network_info)
 2222 
 2223         # asserts
 2224         self.assertFalse(mock_vatt.called)
 2225 
 2226     @mock.patch.object(FAKE_CLIENT, 'node')
 2227     def test_unplug_vifs(self, mock_node):
 2228         node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
 2229         node = _get_cached_node(uuid=node_uuid)
 2230         mock_node.get.return_value = node
 2231 
 2232         instance = fake_instance.fake_instance_obj(self.ctx,
 2233                                                    node=node_uuid)
 2234         network_info = utils.get_test_network_info()
 2235         vif_id = six.text_type(network_info[0]['id'])
 2236         self.driver.unplug_vifs(instance, network_info)
 2237 
 2238         # asserts
 2239         mock_node.get.assert_called_once_with(
 2240             node_uuid, fields=ironic_driver._NODE_FIELDS)
 2241         mock_node.vif_detach.assert_called_once_with(node.uuid, vif_id)
 2242 
 2243     @mock.patch.object(FAKE_CLIENT, 'node')
 2244     def test_unplug_vifs_port_not_associated(self, mock_node):
 2245         node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
 2246         node = _get_cached_node(uuid=node_uuid)
 2247 
 2248         mock_node.get.return_value = node
 2249         instance = fake_instance.fake_instance_obj(self.ctx, node=node_uuid)
 2250         network_info = utils.get_test_network_info()
 2251         self.driver.unplug_vifs(instance, network_info)
 2252 
 2253         mock_node.get.assert_called_once_with(
 2254             node_uuid, fields=ironic_driver._NODE_FIELDS)
 2255         self.assertEqual(len(network_info), mock_node.vif_detach.call_count)
 2256 
 2257     @mock.patch.object(FAKE_CLIENT.node, 'vif_detach')
 2258     def test_unplug_vifs_no_network_info(self, mock_vdet):
 2259         instance = fake_instance.fake_instance_obj(self.ctx)
 2260         network_info = []
 2261         self.driver.unplug_vifs(instance, network_info)
 2262         self.assertFalse(mock_vdet.called)
 2263 
 2264     @mock.patch.object(ironic_driver.IronicDriver, 'plug_vifs')
 2265     def test_attach_interface(self, mock_pv):
 2266         self.driver.attach_interface('fake_context', 'fake_instance',
 2267                                      'fake_image_meta', 'fake_vif')
 2268         mock_pv.assert_called_once_with('fake_instance', ['fake_vif'])
 2269 
 2270     @mock.patch.object(ironic_driver.IronicDriver, 'unplug_vifs')
 2271     def test_detach_interface(self, mock_uv):
 2272         self.driver.detach_interface('fake_context', 'fake_instance',
 2273                                      'fake_vif')
 2274         mock_uv.assert_called_once_with('fake_instance', ['fake_vif'])
 2275 
 2276     @mock.patch.object(firewall.NoopFirewallDriver, 'unfilter_instance',
 2277                        create=True)
 2278     def test_unfilter_instance(self, mock_ui):
 2279         instance = fake_instance.fake_instance_obj(self.ctx)
 2280         network_info = utils.get_test_network_info()
 2281         self.driver.unfilter_instance(instance, network_info)
 2282         mock_ui.assert_called_once_with(instance, network_info)
 2283 
 2284     @mock.patch.object(firewall.NoopFirewallDriver, 'setup_basic_filtering',
 2285                        create=True)
 2286     @mock.patch.object(firewall.NoopFirewallDriver, 'prepare_instance_filter',
 2287                        create=True)
 2288     def test_ensure_filtering_rules_for_instance(self, mock_pif, mock_sbf):
 2289         instance = fake_instance.fake_instance_obj(self.ctx)
 2290         network_info = utils.get_test_network_info()
 2291         self.driver.ensure_filtering_rules_for_instance(instance,
 2292                                                         network_info)
 2293         mock_sbf.assert_called_once_with(instance, network_info)
 2294         mock_pif.assert_called_once_with(instance, network_info)
 2295 
 2296     @mock.patch.object(firewall.NoopFirewallDriver,
 2297                        'refresh_instance_security_rules', create=True)
 2298     def test_refresh_instance_security_rules(self, mock_risr):
 2299         instance = fake_instance.fake_instance_obj(self.ctx)
 2300         self.driver.refresh_instance_security_rules(instance)
 2301         mock_risr.assert_called_once_with(instance)
 2302 
 2303     @mock.patch.object(firewall.NoopFirewallDriver,
 2304                       'refresh_instance_security_rules', create=True)
 2305     def test_refresh_security_group_rules(self, mock_risr):
 2306         fake_group = 'fake-security-group-members'
 2307         self.driver.refresh_instance_security_rules(fake_group)
 2308         mock_risr.assert_called_once_with(fake_group)
 2309 
 2310     @mock.patch.object(ironic_driver.IronicDriver, '_wait_for_active')
 2311     @mock.patch.object(loopingcall, 'FixedIntervalLoopingCall')
 2312     @mock.patch.object(FAKE_CLIENT.node, 'set_provision_state')
 2313     @mock.patch.object(ironic_driver.IronicDriver,
 2314                        '_add_instance_info_to_node')
 2315     @mock.patch.object(FAKE_CLIENT.node, 'get')
 2316     @mock.patch.object(objects.Instance, 'save')
 2317     def _test_rebuild(self, mock_save, mock_get, mock_add_instance_info,
 2318                       mock_set_pstate, mock_looping, mock_wait_active,
 2319                       preserve=False):
 2320         node_uuid = uuidutils.generate_uuid()
 2321         node = _get_cached_node(
 2322                 uuid=node_uuid, instance_uuid=self.instance_uuid,
 2323                 instance_type_id=5)
 2324         mock_get.return_value = node
 2325 
 2326         image_meta = ironic_utils.get_test_image_meta()
 2327         flavor_id = 5
 2328         flavor = objects.Flavor(flavor_id=flavor_id, name='baremetal')
 2329 
 2330         instance = fake_instance.fake_instance_obj(self.ctx,
 2331                                                    uuid=self.instance_uuid,
 2332                                                    node=node_uuid,
 2333                                                    instance_type_id=flavor_id)
 2334         instance.flavor = flavor
 2335 
 2336         fake_looping_call = FakeLoopingCall()
 2337         mock_looping.return_value = fake_looping_call
 2338 
 2339         self.driver.rebuild(
 2340             context=self.ctx, instance=instance, image_meta=image_meta,
 2341             injected_files=None, admin_password=None, allocations={},
 2342             bdms=None, detach_block_devices=None, attach_block_devices=None,
 2343             preserve_ephemeral=preserve)
 2344 
 2345         mock_save.assert_called_once_with(
 2346             expected_task_state=[task_states.REBUILDING])
 2347         mock_add_instance_info.assert_called_once_with(
 2348             node, instance,
 2349             test.MatchType(objects.ImageMeta),
 2350             flavor, preserve)
 2351         mock_set_pstate.assert_called_once_with(node_uuid,
 2352                                                 ironic_states.REBUILD,
 2353                                                 configdrive=mock.ANY)
 2354         mock_looping.assert_called_once_with(mock_wait_active, instance)
 2355         fake_looping_call.start.assert_called_once_with(
 2356             interval=CONF.ironic.api_retry_interval)
 2357         fake_looping_call.wait.assert_called_once_with()
 2358 
 2359     @mock.patch.object(ironic_driver.IronicDriver, '_generate_configdrive')
 2360     @mock.patch.object(configdrive, 'required_by')
 2361     def test_rebuild_preserve_ephemeral(self, mock_required_by,
 2362                                         mock_configdrive):
 2363         mock_required_by.return_value = False
 2364         self._test_rebuild(preserve=True)
 2365         # assert configdrive was not generated
 2366         mock_configdrive.assert_not_called()
 2367 
 2368     @mock.patch.object(ironic_driver.IronicDriver, '_generate_configdrive')
 2369     @mock.patch.object(configdrive, 'required_by')
 2370     def test_rebuild_no_preserve_ephemeral(self, mock_required_by,
 2371                                            mock_configdrive):
 2372         mock_required_by.return_value = False
 2373         self._test_rebuild(preserve=False)
 2374 
 2375     @mock.patch.object(ironic_driver.IronicDriver, '_generate_configdrive')
 2376     @mock.patch.object(configdrive, 'required_by')
 2377     def test_rebuild_with_configdrive(self, mock_required_by,
 2378                                       mock_configdrive):
 2379         mock_required_by.return_value = True
 2380         self._test_rebuild()
 2381         # assert configdrive was generated
 2382         mock_configdrive.assert_called_once_with(
 2383             self.ctx, mock.ANY, mock.ANY, mock.ANY, extra_md={}, files=None)
 2384 
 2385     @mock.patch.object(ironic_driver.IronicDriver, '_generate_configdrive')
 2386     @mock.patch.object(configdrive, 'required_by')
 2387     @mock.patch.object(ironic_driver.IronicDriver,
 2388                        '_add_instance_info_to_node')
 2389     @mock.patch.object(FAKE_CLIENT.node, 'get')
 2390     @mock.patch.object(objects.Instance, 'save')
 2391     def test_rebuild_with_configdrive_failure(self, mock_save, mock_get,
 2392                                               mock_add_instance_info,
 2393                                               mock_required_by,
 2394                                               mock_configdrive):
 2395         node_uuid = uuidutils.generate_uuid()
 2396         node = _get_cached_node(
 2397                 uuid=node_uuid, instance_uuid=self.instance_uuid,
 2398                 instance_type_id=5)
 2399         mock_get.return_value = node
 2400         mock_required_by.return_value = True
 2401         mock_configdrive.side_effect = exception.NovaException()
 2402 
 2403         image_meta = ironic_utils.get_test_image_meta()
 2404         flavor_id = 5
 2405         flavor = objects.Flavor(flavor_id=flavor_id, name='baremetal')
 2406 
 2407         instance = fake_instance.fake_instance_obj(self.ctx,
 2408                                                    uuid=self.instance_uuid,
 2409                                                    node=node_uuid,
 2410                                                    instance_type_id=flavor_id)
 2411         instance.flavor = flavor
 2412 
 2413         self.assertRaises(exception.InstanceDeployFailure,
 2414             self.driver.rebuild,
 2415             context=self.ctx, instance=instance, image_meta=image_meta,
 2416             injected_files=None, admin_password=None, allocations={},
 2417             bdms=None, detach_block_devices=None,
 2418             attach_block_devices=None)
 2419 
 2420     @mock.patch.object(ironic_driver.IronicDriver, '_generate_configdrive')
 2421     @mock.patch.object(configdrive, 'required_by')
 2422     @mock.patch.object(FAKE_CLIENT.node, 'set_provision_state')
 2423     @mock.patch.object(ironic_driver.IronicDriver,
 2424                        '_add_instance_info_to_node')
 2425     @mock.patch.object(FAKE_CLIENT.node, 'get')
 2426     @mock.patch.object(objects.Instance, 'save')
 2427     def test_rebuild_failures(self, mock_save, mock_get,
 2428                               mock_add_instance_info, mock_set_pstate,
 2429                               mock_required_by, mock_configdrive):
 2430         node_uuid = uuidutils.generate_uuid()
 2431         node = _get_cached_node(
 2432                 uuid=node_uuid, instance_uuid=self.instance_uuid,
 2433                 instance_type_id=5)
 2434         mock_get.return_value = node
 2435         mock_required_by.return_value = False
 2436 
 2437         image_meta = ironic_utils.get_test_image_meta()
 2438         flavor_id = 5
 2439         flavor = objects.Flavor(flavor_id=flavor_id, name='baremetal')
 2440 
 2441         instance = fake_instance.fake_instance_obj(self.ctx,
 2442                                                    uuid=self.instance_uuid,
 2443                                                    node=node_uuid,
 2444                                                    instance_type_id=flavor_id)
 2445         instance.flavor = flavor
 2446 
 2447         exceptions = [
 2448             exception.NovaException(),
 2449             ironic_exception.BadRequest(),
 2450             ironic_exception.InternalServerError(),
 2451         ]
 2452         for e in exceptions:
 2453             mock_set_pstate.side_effect = e
 2454             self.assertRaises(exception.InstanceDeployFailure,
 2455                 self.driver.rebuild,
 2456                 context=self.ctx, instance=instance, image_meta=image_meta,
 2457                 injected_files=None, admin_password=None, allocations={},
 2458                 bdms=None, detach_block_devices=None,
 2459                 attach_block_devices=None)
 2460 
 2461     @mock.patch.object(FAKE_CLIENT.node, 'get')
 2462     def test_network_binding_host_id(self, mock_get):
 2463         node_uuid = uuidutils.generate_uuid()
 2464         hostname = 'ironic-compute'
 2465         instance = fake_instance.fake_instance_obj(self.ctx,
 2466                                                    node=node_uuid,
 2467                                                    host=hostname)
 2468         node = ironic_utils.get_test_node(uuid=node_uuid,
 2469                                           instance_uuid=self.instance_uuid,
 2470                                           instance_type_id=5,
 2471                                           network_interface='flat')
 2472         mock_get.return_value = node
 2473         host_id = self.driver.network_binding_host_id(self.ctx, instance)
 2474         self.assertIsNone(host_id)
 2475 
 2476     @mock.patch.object(FAKE_CLIENT, 'node')
 2477     def test_get_volume_connector(self, mock_node):
 2478         node_uuid = uuids.node_uuid
 2479         node_props = {'cpu_arch': 'x86_64'}
 2480         node = ironic_utils.get_test_node(uuid=node_uuid,
 2481                                           properties=node_props)
 2482         connectors = [ironic_utils.get_test_volume_connector(
 2483                           node_uuid=node_uuid, type='iqn',
 2484                           connector_id='iqn.test'),
 2485                       ironic_utils.get_test_volume_connector(
 2486                           node_uuid=node_uuid, type='ip',
 2487                           connector_id='1.2.3.4'),
 2488                       ironic_utils.get_test_volume_connector(
 2489                           node_uuid=node_uuid, type='wwnn',
 2490                           connector_id='200010601'),
 2491                       ironic_utils.get_test_volume_connector(
 2492                           node_uuid=node_uuid, type='wwpn',
 2493                           connector_id='200010605'),
 2494                       ironic_utils.get_test_volume_connector(
 2495                           node_uuid=node_uuid, type='wwpn',
 2496                           connector_id='200010606')]
 2497 
 2498         expected_props = {'initiator': 'iqn.test',
 2499                           'ip': '1.2.3.4',
 2500                           'host': '1.2.3.4',
 2501                           'multipath': False,
 2502                           'wwnns': ['200010601'],
 2503                           'wwpns': ['200010605', '200010606'],
 2504                           'os_type': 'baremetal',
 2505                           'platform': 'x86_64'}
 2506 
 2507         mock_node.get.return_value = node
 2508         mock_node.list_volume_connectors.return_value = connectors
 2509         instance = fake_instance.fake_instance_obj(self.ctx, node=node_uuid)
 2510         props = self.driver.get_volume_connector(instance)
 2511 
 2512         self.assertEqual(expected_props, props)
 2513         mock_node.get.assert_called_once_with(node_uuid)
 2514         mock_node.list_volume_connectors.assert_called_once_with(
 2515             node_uuid, detail=True)
 2516 
 2517     @mock.patch.object(objects.instance.Instance, 'get_network_info')
 2518     @mock.patch.object(FAKE_CLIENT, 'node')
 2519     @mock.patch.object(FAKE_CLIENT.port, 'list')
 2520     @mock.patch.object(FAKE_CLIENT.portgroup, 'list')
 2521     def _test_get_volume_connector_no_ip(
 2522             self, mac_specified, mock_pgroup, mock_port, mock_node,
 2523             mock_nw_info, portgroup_exist=False, no_fixed_ip=False):
 2524         node_uuid = uuids.node_uuid
 2525         node_props = {'cpu_arch': 'x86_64'}
 2526         node = ironic_utils.get_test_node(uuid=node_uuid,
 2527                                           properties=node_props)
 2528         connectors = [ironic_utils.get_test_volume_connector(
 2529                           node_uuid=node_uuid, type='iqn',
 2530                           connector_id='iqn.test')]
 2531         if mac_specified:
 2532             connectors.append(ironic_utils.get_test_volume_connector(
 2533                 node_uuid=node_uuid, type='mac',
 2534                 connector_id='11:22:33:44:55:66'))
 2535         fixed_ip = network_model.FixedIP(address='1.2.3.4', version=4)
 2536         subnet = network_model.Subnet(ips=[fixed_ip])
 2537         network = network_model.Network(subnets=[subnet])
 2538         vif = network_model.VIF(
 2539             id='aaaaaaaa-vv11-cccc-dddd-eeeeeeeeeeee', network=network)
 2540 
 2541         expected_props = {'initiator': 'iqn.test',
 2542                           'ip': '1.2.3.4',
 2543                           'host': '1.2.3.4',
 2544                           'multipath': False,
 2545                           'os_type': 'baremetal',
 2546                           'platform': 'x86_64'}
 2547 
 2548         mock_node.get.return_value = node
 2549         mock_node.list_volume_connectors.return_value = connectors
 2550         instance = fake_instance.fake_instance_obj(self.ctx, node=node_uuid)
 2551         port = ironic_utils.get_test_port(
 2552             node_uuid=node_uuid, address='11:22:33:44:55:66',
 2553             internal_info={'tenant_vif_port_id': vif['id']})
 2554         mock_port.return_value = [port]
 2555         if no_fixed_ip:
 2556             mock_nw_info.return_value = []
 2557             expected_props.pop('ip')
 2558             expected_props['host'] = instance.hostname
 2559         else:
 2560             mock_nw_info.return_value = [vif]
 2561         if portgroup_exist:
 2562             portgroup = ironic_utils.get_test_portgroup(
 2563                 node_uuid=node_uuid, address='11:22:33:44:55:66',
 2564                 extra={'vif_port_id': vif['id']})
 2565             mock_pgroup.return_value = [portgroup]
 2566         else:
 2567             mock_pgroup.return_value = []
 2568         props = self.driver.get_volume_connector(instance)
 2569 
 2570         self.assertEqual(expected_props, props)
 2571         mock_node.get.assert_called_once_with(node_uuid)
 2572         mock_node.list_volume_connectors.assert_called_once_with(
 2573             node_uuid, detail=True)
 2574         if mac_specified:
 2575             mock_pgroup.assert_called_once_with(
 2576                 node=node_uuid, address='11:22:33:44:55:66', detail=True)
 2577             if not portgroup_exist:
 2578                 mock_port.assert_called_once_with(
 2579                     node=node_uuid, address='11:22:33:44:55:66', detail=True)
 2580             else:
 2581                 mock_port.assert_not_called()
 2582         else:
 2583             mock_pgroup.assert_not_called()
 2584             mock_port.assert_not_called()
 2585 
 2586     def test_get_volume_connector_no_ip_with_mac(self):
 2587         self._test_get_volume_connector_no_ip(True)
 2588 
 2589     def test_get_volume_connector_no_ip_with_mac_with_portgroup(self):
 2590         self._test_get_volume_connector_no_ip(True, portgroup_exist=True)
 2591 
 2592     def test_get_volume_connector_no_ip_without_mac(self):
 2593         self._test_get_volume_connector_no_ip(False)
 2594 
 2595     def test_get_volume_connector_no_ip_no_fixed_ip(self):
 2596         self._test_get_volume_connector_no_ip(False, no_fixed_ip=True)
 2597 
 2598     @mock.patch.object(ironic_driver.IronicDriver, 'plug_vifs')
 2599     def test_prepare_networks_before_block_device_mapping(self, mock_pvifs):
 2600         instance = fake_instance.fake_instance_obj(self.ctx)
 2601         network_info = utils.get_test_network_info()
 2602         self.driver.prepare_networks_before_block_device_mapping(instance,
 2603                                                                  network_info)
 2604         mock_pvifs.assert_called_once_with(instance, network_info)
 2605 
 2606     @mock.patch.object(ironic_driver.IronicDriver, 'plug_vifs')
 2607     def test_prepare_networks_before_block_device_mapping_error(self,
 2608                                                                 mock_pvifs):
 2609         instance = fake_instance.fake_instance_obj(self.ctx)
 2610         network_info = utils.get_test_network_info()
 2611         mock_pvifs.side_effect = ironic_exception.BadRequest('fake error')
 2612         self.assertRaises(
 2613             ironic_exception.BadRequest,
 2614             self.driver.prepare_networks_before_block_device_mapping,
 2615             instance, network_info)
 2616         mock_pvifs.assert_called_once_with(instance, network_info)
 2617 
 2618     @mock.patch.object(ironic_driver.IronicDriver, 'unplug_vifs')
 2619     def test_clean_networks_preparation(self, mock_upvifs):
 2620         instance = fake_instance.fake_instance_obj(self.ctx)
 2621         network_info = utils.get_test_network_info()
 2622         self.driver.clean_networks_preparation(instance, network_info)
 2623         mock_upvifs.assert_called_once_with(instance, network_info)
 2624 
 2625     @mock.patch.object(ironic_driver.IronicDriver, 'unplug_vifs')
 2626     def test_clean_networks_preparation_error(self, mock_upvifs):
 2627         instance = fake_instance.fake_instance_obj(self.ctx)
 2628         network_info = utils.get_test_network_info()
 2629         mock_upvifs.side_effect = ironic_exception.BadRequest('fake error')
 2630         self.driver.clean_networks_preparation(instance, network_info)
 2631         mock_upvifs.assert_called_once_with(instance, network_info)
 2632 
 2633     @mock.patch.object(FAKE_CLIENT, 'node')
 2634     @mock.patch.object(ironic_driver.LOG, 'error')
 2635     def test_ironicclient_bad_response(self, mock_error, mock_node):
 2636         mock_node.list.side_effect = [["node1", "node2"], Exception()]
 2637         result = self.driver._get_node_list()
 2638         mock_error.assert_not_called()
 2639         self.assertEqual(["node1", "node2"], result)
 2640         self.assertRaises(exception.VirtDriverNotReady,
 2641                           self.driver._get_node_list)
 2642         mock_error.assert_called_once()
 2643 
 2644     @mock.patch.object(cw.IronicClientWrapper, 'call')
 2645     def test_prepare_for_spawn(self, mock_call):
 2646         node = ironic_utils.get_test_node(driver='fake')
 2647         mock_call.side_effect = [node, None]
 2648         instance = fake_instance.fake_instance_obj(self.ctx,
 2649                                                    node=node.uuid)
 2650         self.driver.prepare_for_spawn(instance)
 2651         expected_patch = [{'path': '/instance_uuid', 'op': 'add',
 2652                            'value': instance.uuid}]
 2653         self.assertEqual(2, mock_call.call_count)
 2654         mock_call.assert_has_calls(
 2655             [mock.call('node.get', node.uuid,
 2656                        fields=('uuid', 'power_state', 'target_power_state',
 2657                                'provision_state', 'target_provision_state',
 2658                                'last_error', 'maintenance', 'properties',
 2659                                'instance_uuid', 'traits', 'resource_class')),
 2660              mock.call('node.update', node.uuid,
 2661                       expected_patch, retry_on_conflict=False)])
 2662 
 2663     @mock.patch.object(cw.IronicClientWrapper, 'call')
 2664     def test__set_instance_uuid(self, mock_call):
 2665         node = ironic_utils.get_test_node(driver='fake')
 2666         instance = fake_instance.fake_instance_obj(self.ctx,
 2667                                                    node=node.uuid)
 2668         expected_patch = [{'path': '/instance_uuid', 'op': 'add',
 2669                            'value': instance.uuid}]
 2670         self.driver._set_instance_uuid(node, instance)
 2671         mock_call.assert_called_once_with('node.update', node.uuid,
 2672                                           expected_patch,
 2673                                           retry_on_conflict=False)
 2674 
 2675     def test_prepare_for_spawn_invalid_instance(self):
 2676         instance = fake_instance.fake_instance_obj(self.ctx,
 2677                                                    node=None)
 2678         self.assertRaises(ironic_exception.BadRequest,
 2679                           self.driver.prepare_for_spawn,
 2680                           instance)
 2681 
 2682     @mock.patch.object(cw.IronicClientWrapper, 'call')
 2683     def test_prepare_for_spawn_conflict(self, mock_call):
 2684         node = ironic_utils.get_test_node(driver='fake')
 2685         mock_call.side_effect = [node, ironic_exception.BadRequest]
 2686         instance = fake_instance.fake_instance_obj(self.ctx,
 2687                                                    node=node.uuid)
 2688         self.assertRaises(exception.InstanceDeployFailure,
 2689                           self.driver.prepare_for_spawn,
 2690                           instance)
 2691 
 2692     @mock.patch.object(ironic_driver.IronicDriver, '_cleanup_deploy')
 2693     @mock.patch.object(cw.IronicClientWrapper, 'call')
 2694     def test_failed_spawn_cleanup(self, mock_call, mock_cleanup):
 2695         node = ironic_utils.get_test_node(driver='fake')
 2696         instance = fake_instance.fake_instance_obj(self.ctx,
 2697                                                    node=node.uuid)
 2698         self.driver.failed_spawn_cleanup(instance)
 2699         mock_call.assert_called_once_with('node.get_by_instance_uuid',
 2700                                           instance.uuid,
 2701                                           fields=ironic_driver._NODE_FIELDS)
 2702         self.assertEqual(1, mock_cleanup.call_count)
 2703 
 2704     @mock.patch.object(ironic_driver.IronicDriver, '_stop_firewall')
 2705     @mock.patch.object(ironic_driver.IronicDriver, '_unplug_vifs')
 2706     @mock.patch.object(ironic_driver.IronicDriver,
 2707                        '_cleanup_volume_target_info')
 2708     @mock.patch.object(cw.IronicClientWrapper, 'call')
 2709     def test__cleanup_deploy(self, mock_call, mock_vol, mock_unvif,
 2710                               mock_stop_fw):
 2711         # TODO(TheJulia): This REALLY should be updated to cover all of the
 2712         # calls that take place.
 2713         node = ironic_utils.get_test_node(driver='fake')
 2714         instance = fake_instance.fake_instance_obj(self.ctx,
 2715                                                    node=node.uuid)
 2716         self.driver._cleanup_deploy(node, instance)
 2717         mock_vol.assert_called_once_with(instance)
 2718         mock_unvif.assert_called_once_with(node, instance, None)
 2719         mock_stop_fw.assert_called_once_with(instance, None)
 2720         expected_patch = [{'path': '/instance_info', 'op': 'remove'},
 2721                           {'path': '/instance_uuid', 'op': 'remove'}]
 2722         mock_call.assert_called_once_with('node.update', node.uuid,
 2723                                           expected_patch)
 2724 
 2725     @mock.patch.object(ironic_driver.IronicDriver, '_stop_firewall')
 2726     @mock.patch.object(ironic_driver.IronicDriver, '_unplug_vifs')
 2727     @mock.patch.object(ironic_driver.IronicDriver,
 2728                        '_cleanup_volume_target_info')
 2729     @mock.patch.object(cw.IronicClientWrapper, 'call')
 2730     def test__cleanup_deploy_no_remove_ii(self, mock_call, mock_vol,
 2731                                           mock_unvif, mock_stop_fw):
 2732         # TODO(TheJulia): This REALLY should be updated to cover all of the
 2733         # calls that take place.
 2734         node = ironic_utils.get_test_node(driver='fake')
 2735         instance = fake_instance.fake_instance_obj(self.ctx,
 2736                                                    node=node.uuid)
 2737         self.driver._cleanup_deploy(node, instance, remove_instance_info=False)
 2738         mock_vol.assert_called_once_with(instance)
 2739         mock_unvif.assert_called_once_with(node, instance, None)
 2740         mock_stop_fw.assert_called_once_with(instance, None)
 2741         self.assertFalse(mock_call.called)
 2742 
 2743 
 2744 class IronicDriverSyncTestCase(IronicDriverTestCase):
 2745 
 2746     def setUp(self):
 2747         super(IronicDriverSyncTestCase, self).setUp()
 2748         self.driver.node_cache = {}
 2749         # Since the code we're testing runs in a spawn_n green thread, ensure
 2750         # that the thread completes.
 2751         self.useFixture(fixtures.SpawnIsSynchronousFixture())
 2752 
 2753     @mock.patch.object(ironic_driver.IronicDriver, '_get_node_list')
 2754     @mock.patch.object(objects.ServiceList, 'get_all_computes_by_hv_type')
 2755     @mock.patch.object(objects.InstanceList, 'get_uuids_by_host')
 2756     @mock.patch.object(objects.Instance, 'get_by_uuid')
 2757     @mock.patch.object(objects.Instance, 'save')
 2758     def test_pike_flavor_migration(self, mock_save, mock_get_by_uuid,
 2759             mock_get_uuids_by_host, mock_svc_by_hv, mock_get_node_list):
 2760         node1_uuid = uuidutils.generate_uuid()
 2761         node2_uuid = uuidutils.generate_uuid()
 2762         hostname = "ironic-compute"
 2763         fake_flavor1 = objects.Flavor()
 2764         fake_flavor1.extra_specs = {}
 2765         fake_flavor2 = objects.Flavor()
 2766         fake_flavor2.extra_specs = {}
 2767         inst1 = fake_instance.fake_instance_obj(self.ctx,
 2768                 node=node1_uuid,
 2769                 host=hostname,
 2770                 flavor=fake_flavor1)
 2771         inst2 = fake_instance.fake_instance_obj(self.ctx,
 2772                 node=node2_uuid,
 2773                 host=hostname,
 2774                 flavor=fake_flavor2)
 2775         node1 = _get_cached_node(
 2776                 uuid=node1_uuid,
 2777                 instance_uuid=inst1.uuid,
 2778                 instance_type_id=1,
 2779                 resource_class="first",
 2780                 network_interface="flat")
 2781         node2 = _get_cached_node(
 2782                 uuid=node2_uuid,
 2783                 instance_uuid=inst2.uuid,
 2784                 instance_type_id=2,
 2785                 resource_class="second",
 2786                 network_interface="flat")
 2787         inst_dict = {inst1.uuid: inst1, inst2.uuid: inst2}
 2788         mock_get_uuids_by_host.return_value = [inst1.uuid, inst2.uuid]
 2789         mock_svc_by_hv.return_value = []
 2790         self.driver.node_cache = {}
 2791         mock_get_node_list.return_value = [node1, node2]
 2792 
 2793         def fake_inst_by_uuid(ctx, uuid, expected_attrs=None):
 2794             return inst_dict.get(uuid)
 2795 
 2796         mock_get_by_uuid.side_effect = fake_inst_by_uuid
 2797 
 2798         self.assertEqual({}, inst1.flavor.extra_specs)
 2799         self.assertEqual({}, inst2.flavor.extra_specs)
 2800 
 2801         self.driver._refresh_cache()
 2802         self.assertEqual(2, mock_save.call_count)
 2803         expected_specs = {"resources:CUSTOM_FIRST": "1"}
 2804         self.assertEqual(expected_specs, inst1.flavor.extra_specs)
 2805         expected_specs = {"resources:CUSTOM_SECOND": "1"}
 2806         self.assertEqual(expected_specs, inst2.flavor.extra_specs)
 2807 
 2808     @mock.patch.object(ironic_driver.IronicDriver, '_get_node_list')
 2809     @mock.patch.object(objects.ServiceList, 'get_all_computes_by_hv_type')
 2810     @mock.patch.object(objects.InstanceList, 'get_uuids_by_host')
 2811     @mock.patch.object(objects.Instance, 'get_by_uuid')
 2812     @mock.patch.object(objects.Instance, 'save')
 2813     def test_pike_flavor_migration_instance_migrated(self, mock_save,
 2814             mock_get_by_uuid, mock_get_uuids_by_host, mock_svc_by_hv,
 2815             mock_get_node_list):
 2816         node1_uuid = uuidutils.generate_uuid()
 2817         node2_uuid = uuidutils.generate_uuid()
 2818         hostname = "ironic-compute"
 2819         fake_flavor1 = objects.Flavor()
 2820         fake_flavor1.extra_specs = {"resources:CUSTOM_FIRST": "1"}
 2821         fake_flavor2 = objects.Flavor()
 2822         fake_flavor2.extra_specs = {}
 2823         inst1 = fake_instance.fake_instance_obj(self.ctx,
 2824                 node=node1_uuid,
 2825                 host=hostname,
 2826                 flavor=fake_flavor1)
 2827         inst2 = fake_instance.fake_instance_obj(self.ctx,
 2828                 node=node2_uuid,
 2829                 host=hostname,
 2830                 flavor=fake_flavor2)
 2831         node1 = _get_cached_node(
 2832                 uuid=node1_uuid,
 2833                 instance_uuid=inst1.uuid,
 2834                 instance_type_id=1,
 2835                 resource_class="first",
 2836                 network_interface="flat")
 2837         node2 = _get_cached_node(
 2838                 uuid=node2_uuid,
 2839                 instance_uuid=inst2.uuid,
 2840                 instance_type_id=2,
 2841                 resource_class="second",
 2842                 network_interface="flat")
 2843         inst_dict = {inst1.uuid: inst1, inst2.uuid: inst2}
 2844         mock_get_uuids_by_host.return_value = [inst1.uuid, inst2.uuid]
 2845         self.driver.node_cache = {}
 2846         mock_get_node_list.return_value = [node1, node2]
 2847         mock_svc_by_hv.return_value = []
 2848 
 2849         def fake_inst_by_uuid(ctx, uuid, expected_attrs=None):
 2850             return inst_dict.get(uuid)
 2851 
 2852         mock_get_by_uuid.side_effect = fake_inst_by_uuid
 2853 
 2854         self.driver._refresh_cache()
 2855         # Since one instance already had its extra_specs updated with the
 2856         # custom resource_class, only the other one should be updated and
 2857         # saved.
 2858         self.assertEqual(1, mock_save.call_count)
 2859         expected_specs = {"resources:CUSTOM_FIRST": "1"}
 2860         self.assertEqual(expected_specs, inst1.flavor.extra_specs)
 2861         expected_specs = {"resources:CUSTOM_SECOND": "1"}
 2862         self.assertEqual(expected_specs, inst2.flavor.extra_specs)
 2863 
 2864     @mock.patch.object(ironic_driver.LOG, 'warning')
 2865     @mock.patch.object(ironic_driver.IronicDriver, '_get_node_list')
 2866     @mock.patch.object(objects.ServiceList, 'get_all_computes_by_hv_type')
 2867     @mock.patch.object(objects.InstanceList, 'get_uuids_by_host')
 2868     @mock.patch.object(objects.Instance, 'get_by_uuid')
 2869     @mock.patch.object(objects.Instance, 'save')
 2870     def test_pike_flavor_migration_missing_rc(self, mock_save,
 2871             mock_get_by_uuid, mock_get_uuids_by_host, mock_svc_by_hv,
 2872             mock_get_node_list, mock_warning):
 2873         node1_uuid = uuidutils.generate_uuid()
 2874         node2_uuid = uuidutils.generate_uuid()
 2875         hostname = "ironic-compute"
 2876         fake_flavor1 = objects.Flavor()
 2877         fake_flavor1.extra_specs = {}
 2878         fake_flavor2 = objects.Flavor()
 2879         fake_flavor2.extra_specs = {}
 2880         inst1 = fake_instance.fake_instance_obj(self.ctx,
 2881                 node=node1_uuid,
 2882                 host=hostname,
 2883                 flavor=fake_flavor1)
 2884         inst2 = fake_instance.fake_instance_obj(self.ctx,
 2885                 node=node2_uuid,
 2886                 host=hostname,
 2887                 flavor=fake_flavor2)
 2888         node1 = _get_cached_node(
 2889                 uuid=node1_uuid,
 2890                 instance_uuid=inst1.uuid,
 2891                 instance_type_id=1,
 2892                 resource_class=None,
 2893                 network_interface="flat")
 2894         node2 = _get_cached_node(
 2895                 uuid=node2_uuid,
 2896                 instance_uuid=inst2.uuid,
 2897                 instance_type_id=2,
 2898                 resource_class="second",
 2899                 network_interface="flat")
 2900         inst_dict = {inst1.uuid: inst1, inst2.uuid: inst2}
 2901         mock_get_uuids_by_host.return_value = [inst1.uuid, inst2.uuid]
 2902         mock_svc_by_hv.return_value = []
 2903         self.driver.node_cache = {}
 2904         mock_get_node_list.return_value = [node1, node2]
 2905 
 2906         def fake_inst_by_uuid(ctx, uuid, expected_attrs=None):
 2907             return inst_dict.get(uuid)
 2908 
 2909         mock_get_by_uuid.side_effect = fake_inst_by_uuid
 2910 
 2911         self.driver._refresh_cache()
 2912         # Since one instance was on a node with no resource class set,
 2913         # only the other one should be updated and saved.
 2914         self.assertEqual(1, mock_save.call_count)
 2915         expected_specs = {}
 2916         self.assertEqual(expected_specs, inst1.flavor.extra_specs)
 2917         expected_specs = {"resources:CUSTOM_SECOND": "1"}
 2918         self.assertEqual(expected_specs, inst2.flavor.extra_specs)
 2919         # Verify that the LOG.warning was called correctly
 2920         self.assertEqual(1, mock_warning.call_count)
 2921         self.assertIn("does not have its resource_class set.",
 2922                 mock_warning.call_args[0][0])
 2923         self.assertEqual({"node": node1.uuid}, mock_warning.call_args[0][1])
 2924 
 2925     @mock.patch.object(ironic_driver.IronicDriver, '_get_node_list')
 2926     @mock.patch.object(objects.ServiceList, 'get_all_computes_by_hv_type')
 2927     @mock.patch.object(objects.InstanceList, 'get_uuids_by_host')
 2928     @mock.patch.object(objects.Instance, 'get_by_uuid')
 2929     @mock.patch.object(objects.Instance, 'save')
 2930     def test_pike_flavor_migration_refresh_called_again(self, mock_save,
 2931             mock_get_by_uuid, mock_get_uuids_by_host, mock_svc_by_hv,
 2932             mock_get_node_list):
 2933         node1_uuid = uuidutils.generate_uuid()
 2934         node2_uuid = uuidutils.generate_uuid()
 2935         hostname = "ironic-compute"
 2936         fake_flavor1 = objects.Flavor()
 2937         fake_flavor1.extra_specs = {}
 2938         fake_flavor2 = objects.Flavor()
 2939         fake_flavor2.extra_specs = {}
 2940         inst1 = fake_instance.fake_instance_obj(self.ctx,
 2941                 node=node1_uuid,
 2942                 host=hostname,
 2943                 flavor=fake_flavor1)
 2944         inst2 = fake_instance.fake_instance_obj(self.ctx,
 2945                 node=node2_uuid,
 2946                 host=hostname,
 2947                 flavor=fake_flavor2)
 2948         node1 = _get_cached_node(
 2949                 uuid=node1_uuid,
 2950                 instance_uuid=inst1.uuid,
 2951                 instance_type_id=1,
 2952                 resource_class="first",
 2953                 network_interface="flat")
 2954         node2 = _get_cached_node(
 2955                 uuid=node2_uuid,
 2956                 instance_uuid=inst2.uuid,
 2957                 instance_type_id=2,
 2958                 resource_class="second",
 2959                 network_interface="flat")
 2960         inst_dict = {inst1.uuid: inst1, inst2.uuid: inst2}
 2961         mock_get_uuids_by_host.return_value = [inst1.uuid, inst2.uuid]
 2962         mock_svc_by_hv.return_value = []
 2963         self.driver.node_cache = {}
 2964         mock_get_node_list.return_value = [node1, node2]
 2965 
 2966         def fake_inst_by_uuid(ctx, uuid, expected_attrs=None):
 2967             return inst_dict.get(uuid)
 2968 
 2969         mock_get_by_uuid.side_effect = fake_inst_by_uuid
 2970 
 2971         self.driver._refresh_cache()
 2972         self.assertEqual(2, mock_get_by_uuid.call_count)
 2973         # Refresh the cache again. The mock for getting an instance by uuid
 2974         # should not be called again.
 2975         mock_get_by_uuid.reset_mock()
 2976         self.driver._refresh_cache()
 2977         mock_get_by_uuid.assert_not_called()
 2978 
 2979     @mock.patch.object(ironic_driver.IronicDriver, '_get_node_list')
 2980     @mock.patch.object(objects.ServiceList, 'get_all_computes_by_hv_type')
 2981     @mock.patch.object(objects.InstanceList, 'get_uuids_by_host')
 2982     @mock.patch.object(objects.Instance, 'get_by_uuid')
 2983     @mock.patch.object(objects.Instance, 'save')
 2984     def test_pike_flavor_migration_no_node_change(self, mock_save,
 2985             mock_get_by_uuid, mock_get_uuids_by_host, mock_svc_by_hv,
 2986             mock_get_node_list):
 2987         node1_uuid = uuidutils.generate_uuid()
 2988         node2_uuid = uuidutils.generate_uuid()
 2989         hostname = "ironic-compute"
 2990         fake_flavor1 = objects.Flavor()
 2991         fake_flavor1.extra_specs = {"resources:CUSTOM_FIRST": "1"}
 2992         fake_flavor2 = objects.Flavor()
 2993         fake_flavor2.extra_specs = {"resources:CUSTOM_SECOND": "1"}
 2994         inst1 = fake_instance.fake_instance_obj(self.ctx,
 2995                 node=node1_uuid,
 2996                 host=hostname,
 2997                 flavor=fake_flavor1)
 2998         inst2 = fake_instance.fake_instance_obj(self.ctx,
 2999                 node=node2_uuid,
 3000                 host=hostname,
 3001                 flavor=fake_flavor2)
 3002         node1 = _get_cached_node(
 3003                 uuid=node1_uuid,
 3004                 instance_uuid=inst1.uuid,
 3005                 instance_type_id=1,
 3006                 resource_class="first",
 3007                 network_interface="flat")
 3008         node2 = _get_cached_node(
 3009                 uuid=node2_uuid,
 3010                 instance_uuid=inst2.uuid,
 3011                 instance_type_id=2,
 3012                 resource_class="second",
 3013                 network_interface="flat")
 3014         inst_dict = {inst1.uuid: inst1, inst2.uuid: inst2}
 3015         mock_get_uuids_by_host.return_value = [inst1.uuid, inst2.uuid]
 3016         self.driver.node_cache = {node1_uuid: node1, node2_uuid: node2}
 3017         self.driver._migrated_instance_uuids = set([inst1.uuid, inst2.uuid])
 3018         mock_get_node_list.return_value = [node1, node2]
 3019         mock_svc_by_hv.return_value = []
 3020 
 3021         def fake_inst_by_uuid(ctx, uuid, expected_attrs=None):
 3022             return inst_dict.get(uuid)
 3023 
 3024         mock_get_by_uuid.side_effect = fake_inst_by_uuid
 3025 
 3026         self.driver._refresh_cache()
 3027         # Since the nodes did not change in the call to _refresh_cache(), and
 3028         # their instance_uuids were in the cache, none of the mocks in the
 3029         # migration script should have been called.
 3030         self.assertFalse(mock_get_by_uuid.called)
 3031         self.assertFalse(mock_save.called)
 3032 
 3033     @mock.patch.object(ironic_driver.IronicDriver, '_get_node_list')
 3034     @mock.patch.object(objects.ServiceList, 'get_all_computes_by_hv_type')
 3035     @mock.patch.object(objects.InstanceList, 'get_uuids_by_host')
 3036     @mock.patch.object(objects.Instance, 'get_by_uuid')
 3037     @mock.patch.object(objects.Instance, 'save')
 3038     def test_pike_flavor_migration_just_instance_change(self, mock_save,
 3039             mock_get_by_uuid, mock_get_uuids_by_host, mock_svc_by_hv,
 3040             mock_get_node_list):
 3041         node1_uuid = uuidutils.generate_uuid()
 3042         node2_uuid = uuidutils.generate_uuid()
 3043         node3_uuid = uuidutils.generate_uuid()
 3044         hostname = "ironic-compute"
 3045         fake_flavor1 = objects.Flavor()
 3046         fake_flavor1.extra_specs = {}
 3047         fake_flavor2 = objects.Flavor()
 3048         fake_flavor2.extra_specs = {}
 3049         fake_flavor3 = objects.Flavor()
 3050         fake_flavor3.extra_specs = {}
 3051         inst1 = fake_instance.fake_instance_obj(self.ctx,
 3052                 node=node1_uuid,
 3053                 host=hostname,
 3054                 flavor=fake_flavor1)
 3055         inst2 = fake_instance.fake_instance_obj(self.ctx,
 3056                 node=node2_uuid,
 3057                 host=hostname,
 3058                 flavor=fake_flavor2)
 3059         inst3 = fake_instance.fake_instance_obj(self.ctx,
 3060                 node=node3_uuid,
 3061                 host=hostname,
 3062                 flavor=fake_flavor3)
 3063         node1 = _get_cached_node(
 3064                 uuid=node1_uuid,
 3065                 instance_uuid=inst1.uuid,
 3066                 instance_type_id=1,
 3067                 resource_class="first",
 3068                 network_interface="flat")
 3069         node2 = _get_cached_node(
 3070                 uuid=node2_uuid,
 3071                 instance_uuid=inst2.uuid,
 3072                 instance_type_id=2,
 3073                 resource_class="second",
 3074                 network_interface="flat")
 3075         inst_dict = {inst1.uuid: inst1, inst2.uuid: inst2, inst3.uuid: inst3}
 3076         mock_get_uuids_by_host.return_value = [inst1.uuid, inst2.uuid]
 3077         self.driver.node_cache = {node1_uuid: node1, node2_uuid: node2}
 3078         mock_get_node_list.return_value = [node1, node2]
 3079         mock_svc_by_hv.return_value = []
 3080 
 3081         def fake_inst_by_uuid(ctx, uuid, expected_attrs=None):
 3082             return inst_dict.get(uuid)
 3083 
 3084         mock_get_by_uuid.side_effect = fake_inst_by_uuid
 3085 
 3086         self.driver._refresh_cache()
 3087         # Since this is a fresh driver, neither will be in the migration cache,
 3088         # so the migration mocks should have been called.
 3089         self.assertTrue(mock_get_by_uuid.called)
 3090         self.assertTrue(mock_save.called)
 3091 
 3092         # Now call _refresh_cache() again.  Since neither the nodes nor their
 3093         # instances change, none of the mocks in the migration script should
 3094         # have been called.
 3095         mock_get_by_uuid.reset_mock()
 3096         mock_save.reset_mock()
 3097         self.driver._refresh_cache()
 3098         self.assertFalse(mock_get_by_uuid.called)
 3099         self.assertFalse(mock_save.called)
 3100 
 3101         # Now change the node on node2 to inst3
 3102         node2.instance_uuid = inst3.uuid
 3103         mock_get_uuids_by_host.return_value = [inst1.uuid, inst3.uuid]
 3104         # Call _refresh_cache() again. Since the instance on node2 changed, the
 3105         # migration mocks should have been called.
 3106         mock_get_by_uuid.reset_mock()
 3107         mock_save.reset_mock()
 3108         self.driver._refresh_cache()
 3109         self.assertTrue(mock_get_by_uuid.called)
 3110         self.assertTrue(mock_save.called)
 3111 
 3112     @mock.patch.object(fields.ResourceClass, 'normalize_name')
 3113     @mock.patch.object(ironic_driver.IronicDriver, '_node_from_cache')
 3114     def test_pike_flavor_migration_empty_node(self, mock_node_from_cache,
 3115             mock_normalize):
 3116         mock_node_from_cache.return_value = None
 3117         self.driver._pike_flavor_migration([uuids.node])
 3118         mock_normalize.assert_not_called()
 3119 
 3120     @mock.patch.object(fields.ResourceClass, 'normalize_name')
 3121     @mock.patch.object(ironic_driver.IronicDriver, '_node_from_cache')
 3122     def test_pike_flavor_migration_already_migrated(self, mock_node_from_cache,
 3123             mock_normalize):
 3124         node1 = _get_cached_node(
 3125                 uuid=uuids.node1,
 3126                 instance_uuid=uuids.instance,
 3127                 instance_type_id=1,
 3128                 resource_class="first",
 3129                 network_interface="flat")
 3130         mock_node_from_cache.return_value = node1
 3131         self.driver._migrated_instance_uuids = set([uuids.instance])
 3132         self.driver._pike_flavor_migration([uuids.node1])
 3133         mock_normalize.assert_not_called()
 3134 
 3135     @mock.patch.object(loopingcall, 'FixedIntervalLoopingCall')
 3136     @mock.patch.object(FAKE_CLIENT.node, 'set_provision_state')
 3137     def test_rescue(self, mock_sps, mock_looping):
 3138         node = ironic_utils.get_test_node()
 3139 
 3140         fake_looping_call = FakeLoopingCall()
 3141         mock_looping.return_value = fake_looping_call
 3142         instance = fake_instance.fake_instance_obj(self.ctx,
 3143                                                    node=node.uuid)
 3144 
 3145         self.driver.rescue(self.ctx, instance, None, None, 'xyz')
 3146         mock_sps.assert_called_once_with(node.uuid, 'rescue',
 3147                                          rescue_password='xyz')
 3148 
 3149     @mock.patch.object(loopingcall, 'FixedIntervalLoopingCall')
 3150     @mock.patch.object(FAKE_CLIENT.node, 'set_provision_state')
 3151     def test_rescue_provision_state_fail(self, mock_sps, mock_looping):
 3152         node = ironic_utils.get_test_node()
 3153 
 3154         fake_looping_call = FakeLoopingCall()
 3155         mock_looping.return_value = fake_looping_call
 3156         mock_sps.side_effect = ironic_exception.BadRequest()
 3157         instance = fake_instance.fake_instance_obj(self.ctx,
 3158                                                    node=node.uuid)
 3159 
 3160         self.assertRaises(exception.InstanceRescueFailure,
 3161                           self.driver.rescue,
 3162                           self.ctx, instance, None, None, 'xyz')
 3163 
 3164     @mock.patch.object(ironic_driver.IronicDriver,
 3165                        '_validate_instance_and_node')
 3166     @mock.patch.object(FAKE_CLIENT.node, 'set_provision_state')
 3167     def test_rescue_instance_not_found(self, mock_sps, fake_validate):
 3168         node = ironic_utils.get_test_node(driver='fake')
 3169 
 3170         instance = fake_instance.fake_instance_obj(self.ctx, node=node.uuid)
 3171         fake_validate.side_effect = exception.InstanceNotFound(
 3172             instance_id='fake')
 3173 
 3174         self.assertRaises(exception.InstanceRescueFailure,
 3175                           self.driver.rescue,
 3176                           self.ctx, instance, None, None, 'xyz')
 3177 
 3178     @mock.patch.object(ironic_driver.IronicDriver,
 3179                        '_validate_instance_and_node')
 3180     @mock.patch.object(FAKE_CLIENT.node, 'set_provision_state')
 3181     def test_rescue_rescue_fail(self, mock_sps, fake_validate):
 3182         node = ironic_utils.get_test_node(
 3183                    provision_state=ironic_states.RESCUEFAIL,
 3184                    last_error='rescue failed')
 3185 
 3186         fake_validate.return_value = node
 3187         instance = fake_instance.fake_instance_obj(self.ctx,
 3188                                                    node=node.uuid)
 3189 
 3190         self.assertRaises(exception.InstanceRescueFailure,
 3191                           self.driver.rescue,
 3192                           self.ctx, instance, None, None, 'xyz')
 3193 
 3194     @mock.patch.object(ironic_driver.IronicDriver, '_can_send_version')
 3195     @mock.patch.object(ironic_driver, 'LOG', autospec=True)
 3196     def test_rescue_api_unavailable(self, mock_log, mock_csv):
 3197         node = ironic_utils.get_test_node()
 3198         instance = fake_instance.fake_instance_obj(self.ctx,
 3199                                                    node=node.uuid)
 3200         mock_csv.side_effect = exception.IronicAPIVersionNotAvailable(
 3201             version='1.38')
 3202 
 3203         def _fake_log_error(msg, *args, **kwargs):
 3204             regex = r'Required Ironic API version.*for rescuing.'
 3205             self.assertThat(msg, matchers.MatchesRegex(regex))
 3206         mock_log.error.side_effect = _fake_log_error
 3207 
 3208         self.assertRaises(exception.InstanceRescueFailure,
 3209                           self.driver.rescue,
 3210                           self.ctx, instance, None, None, 'xyz')
 3211         self.assertTrue(mock_log.error.called)
 3212 
 3213     @mock.patch.object(loopingcall, 'FixedIntervalLoopingCall')
 3214     @mock.patch.object(FAKE_CLIENT.node, 'set_provision_state')
 3215     def test_unrescue(self, mock_sps, mock_looping):
 3216         node = ironic_utils.get_test_node()
 3217 
 3218         fake_looping_call = FakeLoopingCall()
 3219         mock_looping.return_value = fake_looping_call
 3220         instance = fake_instance.fake_instance_obj(self.ctx,
 3221                                                    node=node.uuid)
 3222 
 3223         self.driver.unrescue(instance, None)
 3224         mock_sps.assert_called_once_with(node.uuid, 'unrescue')
 3225 
 3226     @mock.patch.object(loopingcall, 'FixedIntervalLoopingCall')
 3227     @mock.patch.object(FAKE_CLIENT.node, 'set_provision_state')
 3228     def test_unrescue_provision_state_fail(self, mock_sps, mock_looping):
 3229         node = ironic_utils.get_test_node()
 3230 
 3231         fake_looping_call = FakeLoopingCall()
 3232         mock_looping.return_value = fake_looping_call
 3233         mock_sps.side_effect = ironic_exception.BadRequest()
 3234 
 3235         instance = fake_instance.fake_instance_obj(self.ctx,
 3236                                                    node=node.uuid)
 3237         self.assertRaises(exception.InstanceUnRescueFailure,
 3238                           self.driver.unrescue,
 3239                           instance, None)
 3240 
 3241     @mock.patch.object(ironic_driver.IronicDriver,
 3242                        '_validate_instance_and_node')
 3243     @mock.patch.object(FAKE_CLIENT.node, 'set_provision_state')
 3244     def test_unrescue_instance_not_found(self, mock_sps, fake_validate):
 3245         node = ironic_utils.get_test_node(driver='fake')
 3246 
 3247         instance = fake_instance.fake_instance_obj(self.ctx, node=node.uuid)
 3248         fake_validate.side_effect = exception.InstanceNotFound(
 3249             instance_id='fake')
 3250 
 3251         self.assertRaises(exception.InstanceUnRescueFailure,
 3252                           self.driver.unrescue,
 3253                           instance, None)
 3254 
 3255     @mock.patch.object(ironic_driver.IronicDriver,
 3256                        '_validate_instance_and_node')
 3257     @mock.patch.object(FAKE_CLIENT.node, 'set_provision_state')
 3258     def test_unrescue_unrescue_fail(self, mock_sps, fake_validate):
 3259         node = ironic_utils.get_test_node(
 3260                    provision_state=ironic_states.UNRESCUEFAIL,
 3261                    last_error='unrescue failed')
 3262 
 3263         fake_validate.return_value = node
 3264         instance = fake_instance.fake_instance_obj(self.ctx,
 3265                                                    node=node.uuid)
 3266 
 3267         self.assertRaises(exception.InstanceUnRescueFailure,
 3268                           self.driver.unrescue,
 3269                           instance, None)
 3270 
 3271     @mock.patch.object(ironic_driver.IronicDriver, '_can_send_version')
 3272     @mock.patch.object(ironic_driver, 'LOG', autospec=True)
 3273     def test_unrescue_api_unavailable(self, mock_log, mock_csv):
 3274         node = ironic_utils.get_test_node()
 3275         instance = fake_instance.fake_instance_obj(self.ctx,
 3276                                                    node=node.uuid)
 3277 
 3278         mock_csv.side_effect = exception.IronicAPIVersionNotAvailable(
 3279             version='1.38')
 3280 
 3281         def _fake_log_error(msg, *args, **kwargs):
 3282             regex = r'Required Ironic API version.*for unrescuing.'
 3283             self.assertThat(msg, matchers.MatchesRegex(regex))
 3284         mock_log.error.side_effect = _fake_log_error
 3285 
 3286         self.assertRaises(exception.InstanceUnRescueFailure,
 3287                           self.driver.unrescue,
 3288                           instance, None)
 3289         self.assertTrue(mock_log.error.called)
 3290 
 3291     def test__can_send_version(self):
 3292         self.assertIsNone(
 3293             self.driver._can_send_version(
 3294                 min_version='%d.%d' % cw.IRONIC_API_VERSION))
 3295 
 3296     def test__can_send_version_too_new(self):
 3297         self.assertRaises(exception.IronicAPIVersionNotAvailable,
 3298                           self.driver._can_send_version,
 3299                           min_version='%d.%d' % (cw.IRONIC_API_VERSION[0],
 3300                                                  cw.IRONIC_API_VERSION[1] + 1))
 3301 
 3302     def test__can_send_version_too_old(self):
 3303         self.assertRaises(
 3304             exception.IronicAPIVersionNotAvailable,
 3305             self.driver._can_send_version,
 3306             max_version='%d.%d' % (cw.PRIOR_IRONIC_API_VERSION[0],
 3307                                    cw.PRIOR_IRONIC_API_VERSION[1] - 1))
 3308 
 3309     @mock.patch.object(cw.IronicClientWrapper, 'current_api_version',
 3310                        autospec=True)
 3311     @mock.patch.object(cw.IronicClientWrapper, 'is_api_version_negotiated',
 3312                        autospec=True)
 3313     def test__can_send_version_not_negotiated(self, mock_is_negotiated,
 3314                                               mock_api_version):
 3315         mock_is_negotiated.return_value = False
 3316         self.assertIsNone(self.driver._can_send_version())
 3317         self.assertFalse(mock_api_version.called)
 3318 
 3319 
 3320 @mock.patch.object(instance_metadata, 'InstanceMetadata')
 3321 @mock.patch.object(configdrive, 'ConfigDriveBuilder')
 3322 class IronicDriverGenerateConfigDriveTestCase(test.NoDBTestCase):
 3323 
 3324     @mock.patch.object(objects.ServiceList, 'get_all_computes_by_hv_type')
 3325     @mock.patch.object(cw, 'IronicClientWrapper',
 3326                        lambda *_: FAKE_CLIENT_WRAPPER)
 3327     def setUp(self, mock_services):
 3328         super(IronicDriverGenerateConfigDriveTestCase, self).setUp()
 3329         self.driver = ironic_driver.IronicDriver(None)
 3330         self.driver.virtapi = fake.FakeVirtAPI()
 3331         self.ctx = nova_context.get_admin_context()
 3332         node_uuid = uuidutils.generate_uuid()
 3333         self.node = _get_cached_node(driver='fake', uuid=node_uuid)
 3334         self.instance = fake_instance.fake_instance_obj(self.ctx,
 3335                                                         node=node_uuid)
 3336         self.network_info = utils.get_test_network_info()
 3337 
 3338     def test_generate_configdrive(self, mock_cd_builder, mock_instance_meta):
 3339         mock_instance_meta.return_value = 'fake-instance'
 3340         mock_make_drive = mock.MagicMock(make_drive=lambda *_: None)
 3341         mock_cd_builder.return_value.__enter__.return_value = mock_make_drive
 3342         network_metadata_mock = mock.Mock()
 3343         self.driver._get_network_metadata = network_metadata_mock
 3344         self.driver._generate_configdrive(None, self.instance,
 3345                                           self.node, self.network_info)
 3346         mock_cd_builder.assert_called_once_with(instance_md='fake-instance')
 3347         mock_instance_meta.assert_called_once_with(
 3348             self.instance, content=None, extra_md={},
 3349             network_info=self.network_info,
 3350             network_metadata=network_metadata_mock.return_value,
 3351             request_context=None)
 3352 
 3353     def test_generate_configdrive_fail(self, mock_cd_builder,
 3354                                        mock_instance_meta):
 3355         mock_cd_builder.side_effect = exception.ConfigDriveMountFailed(
 3356             operation='foo', error='error')
 3357         mock_instance_meta.return_value = 'fake-instance'
 3358         mock_make_drive = mock.MagicMock(make_drive=lambda *_: None)
 3359         mock_cd_builder.return_value.__enter__.return_value = mock_make_drive
 3360         network_metadata_mock = mock.Mock()
 3361         self.driver._get_network_metadata = network_metadata_mock
 3362 
 3363         self.assertRaises(exception.ConfigDriveMountFailed,
 3364                           self.driver._generate_configdrive, None,
 3365                           self.instance, self.node, self.network_info)
 3366 
 3367         mock_cd_builder.assert_called_once_with(instance_md='fake-instance')
 3368         mock_instance_meta.assert_called_once_with(
 3369             self.instance, content=None, extra_md={},
 3370             network_info=self.network_info,
 3371             network_metadata=network_metadata_mock.return_value,
 3372             request_context=None)
 3373 
 3374     @mock.patch.object(FAKE_CLIENT.node, 'list_ports')
 3375     @mock.patch.object(FAKE_CLIENT.portgroup, 'list')
 3376     def _test_generate_network_metadata(self, mock_portgroups, mock_ports,
 3377                                         address=None, vif_internal_info=True):
 3378         internal_info = ({'tenant_vif_port_id': utils.FAKE_VIF_UUID}
 3379                          if vif_internal_info else {})
 3380         extra = ({'vif_port_id': utils.FAKE_VIF_UUID}
 3381                  if not vif_internal_info else {})
 3382         portgroup = ironic_utils.get_test_portgroup(
 3383             node_uuid=self.node.uuid, address=address,
 3384             extra=extra, internal_info=internal_info,
 3385             properties={'bond_miimon': 100, 'xmit_hash_policy': 'layer3+4'}
 3386         )
 3387         port1 = ironic_utils.get_test_port(uuid=uuidutils.generate_uuid(),
 3388                                            node_uuid=self.node.uuid,
 3389                                            address='00:00:00:00:00:01',
 3390                                            portgroup_uuid=portgroup.uuid)
 3391         port2 = ironic_utils.get_test_port(uuid=uuidutils.generate_uuid(),
 3392                                            node_uuid=self.node.uuid,
 3393                                            address='00:00:00:00:00:02',
 3394                                            portgroup_uuid=portgroup.uuid)
 3395         mock_ports.return_value = [port1, port2]
 3396         mock_portgroups.return_value = [portgroup]
 3397 
 3398         metadata = self.driver._get_network_metadata(self.node,
 3399                                                      self.network_info)
 3400 
 3401         pg_vif = metadata['links'][0]
 3402         self.assertEqual('bond', pg_vif['type'])
 3403         self.assertEqual('active-backup', pg_vif['bond_mode'])
 3404         self.assertEqual(address if address else utils.FAKE_VIF_MAC,
 3405                          pg_vif['ethernet_mac_address'])
 3406         self.assertEqual('layer3+4',
 3407                          pg_vif['bond_xmit_hash_policy'])
 3408         self.assertEqual(100, pg_vif['bond_miimon'])
 3409         self.assertEqual([port1.uuid, port2.uuid],
 3410                          pg_vif['bond_links'])
 3411         self.assertEqual([{'id': port1.uuid, 'type': 'phy',
 3412                            'ethernet_mac_address': port1.address},
 3413                           {'id': port2.uuid, 'type': 'phy',
 3414                            'ethernet_mac_address': port2.address}],
 3415                          metadata['links'][1:])
 3416         # assert there are no duplicate links
 3417         link_ids = [link['id'] for link in metadata['links']]
 3418         self.assertEqual(len(set(link_ids)), len(link_ids),
 3419                          'There are duplicate link IDs: %s' % link_ids)
 3420 
 3421     def test_generate_network_metadata_with_pg_address(self, mock_cd_builder,
 3422                                        mock_instance_meta):
 3423         self._test_generate_network_metadata(address='00:00:00:00:00:00')
 3424 
 3425     def test_generate_network_metadata_no_pg_address(self, mock_cd_builder,
 3426                                                      mock_instance_meta):
 3427         self._test_generate_network_metadata()
 3428 
 3429     def test_generate_network_metadata_vif_in_extra(self, mock_cd_builder,
 3430                                                     mock_instance_meta):
 3431         self._test_generate_network_metadata(vif_internal_info=False)
 3432 
 3433     @mock.patch.object(FAKE_CLIENT.node, 'list_ports')
 3434     @mock.patch.object(FAKE_CLIENT.portgroup, 'list')
 3435     def test_generate_network_metadata_ports_only(self, mock_portgroups,
 3436                                                   mock_ports, mock_cd_builder,
 3437                                                   mock_instance_meta):
 3438         address = self.network_info[0]['address']
 3439         port = ironic_utils.get_test_port(
 3440             node_uuid=self.node.uuid, address=address,
 3441             internal_info={'tenant_vif_port_id': utils.FAKE_VIF_UUID})
 3442         mock_ports.return_value = [port]
 3443         mock_portgroups.return_value = []
 3444 
 3445         metadata = self.driver._get_network_metadata(self.node,
 3446                                                      self.network_info)
 3447 
 3448         self.assertEqual(port.address,
 3449                          metadata['links'][0]['ethernet_mac_address'])
 3450         self.assertEqual('phy', metadata['links'][0]['type'])
 3451 
 3452 
 3453 class HashRingTestCase(test.NoDBTestCase):
 3454 
 3455     @mock.patch.object(objects.ServiceList, 'get_all_computes_by_hv_type')
 3456     @mock.patch.object(servicegroup, 'API', autospec=True)
 3457     def setUp(self, mock_sg, mock_services):
 3458         super(HashRingTestCase, self).setUp()
 3459 
 3460         self.driver = ironic_driver.IronicDriver(None)
 3461         self.driver.virtapi = fake.FakeVirtAPI()
 3462         self.ctx = nova_context.get_admin_context()
 3463         self.mock_is_up = (
 3464             self.driver.servicegroup_api.service_is_up)
 3465 
 3466     @mock.patch.object(ironic_driver.IronicDriver, '_refresh_hash_ring')
 3467     def test_hash_ring_refreshed_on_init(self, mock_hr):
 3468         d = ironic_driver.IronicDriver(None)
 3469         self.assertFalse(mock_hr.called)
 3470         d.init_host('foo')
 3471         mock_hr.assert_called_once_with(mock.ANY)
 3472 
 3473     @mock.patch.object(hash_ring, 'HashRing')
 3474     @mock.patch.object(objects.ServiceList, 'get_all_computes_by_hv_type')
 3475     def _test__refresh_hash_ring(self, services, expected_hosts, mock_services,
 3476                                  mock_hash_ring):
 3477         services = [_make_compute_service(host) for host in services]
 3478         is_up_calls = [mock.call(svc) for svc in services]
 3479         self.flags(host='host1')
 3480         mock_services.return_value = services
 3481         mock_hash_ring.return_value = SENTINEL
 3482 
 3483         self.driver._refresh_hash_ring(self.ctx)
 3484 
 3485         mock_services.assert_called_once_with(
 3486             mock.ANY, self.driver._get_hypervisor_type())
 3487         mock_hash_ring.assert_called_once_with(expected_hosts, partitions=32)
 3488         self.assertEqual(SENTINEL, self.driver.hash_ring)
 3489         self.mock_is_up.assert_has_calls(is_up_calls)
 3490 
 3491     def test__refresh_hash_ring_one_compute(self):
 3492         services = ['host1']
 3493         expected_hosts = {'host1'}
 3494         self.mock_is_up.return_value = True
 3495         self._test__refresh_hash_ring(services, expected_hosts)
 3496 
 3497     def test__refresh_hash_ring_many_computes(self):
 3498         services = ['host1', 'host2', 'host3']
 3499         expected_hosts = {'host1', 'host2', 'host3'}
 3500         self.mock_is_up.return_value = True
 3501         self._test__refresh_hash_ring(services, expected_hosts)
 3502 
 3503     def test__refresh_hash_ring_one_compute_new_compute(self):
 3504         services = []
 3505         expected_hosts = {'host1'}
 3506         self.mock_is_up.return_value = True
 3507         self._test__refresh_hash_ring(services, expected_hosts)
 3508 
 3509     def test__refresh_hash_ring_many_computes_new_compute(self):
 3510         services = ['host2', 'host3']
 3511         expected_hosts = {'host1', 'host2', 'host3'}
 3512         self.mock_is_up.return_value = True
 3513         self._test__refresh_hash_ring(services, expected_hosts)
 3514 
 3515     def test__refresh_hash_ring_some_computes_down(self):
 3516         services = ['host1', 'host2', 'host3', 'host4']
 3517         expected_hosts = {'host1', 'host2', 'host4'}
 3518         self.mock_is_up.side_effect = [True, True, False, True]
 3519         self._test__refresh_hash_ring(services, expected_hosts)
 3520 
 3521 
 3522 class NodeCacheTestCase(test.NoDBTestCase):
 3523 
 3524     @mock.patch.object(objects.ServiceList, 'get_all_computes_by_hv_type')
 3525     def setUp(self, mock_services):
 3526         super(NodeCacheTestCase, self).setUp()
 3527 
 3528         self.driver = ironic_driver.IronicDriver(None)
 3529         self.driver.init_host('foo')
 3530         self.driver.virtapi = fake.FakeVirtAPI()
 3531         self.ctx = nova_context.get_admin_context()
 3532 
 3533         self.host = 'host1'
 3534         self.flags(host=self.host)
 3535 
 3536     @mock.patch.object(ironic_driver.IronicDriver, '_refresh_hash_ring')
 3537     @mock.patch.object(hash_ring.HashRing, 'get_nodes')
 3538     @mock.patch.object(ironic_driver.IronicDriver, '_get_node_list')
 3539     @mock.patch.object(objects.InstanceList, 'get_uuids_by_host')
 3540     def _test__refresh_cache(self, instances, nodes, hosts, mock_instances,
 3541                              mock_nodes, mock_hosts, mock_hash_ring):
 3542         mock_instances.return_value = instances
 3543         mock_nodes.return_value = nodes
 3544         mock_hosts.side_effect = hosts
 3545         self.driver.node_cache = {}
 3546         self.driver.node_cache_time = None
 3547 
 3548         self.driver._refresh_cache()
 3549 
 3550         mock_hash_ring.assert_called_once_with(mock.ANY)
 3551         mock_instances.assert_called_once_with(mock.ANY, self.host)
 3552         mock_nodes.assert_called_once_with(fields=ironic_driver._NODE_FIELDS,
 3553                                            limit=0)
 3554         self.assertIsNotNone(self.driver.node_cache_time)
 3555 
 3556     def test__refresh_cache(self):
 3557         # normal operation, one compute service
 3558         instances = []
 3559         nodes = [
 3560             _get_cached_node(
 3561                 uuid=uuidutils.generate_uuid(), instance_uuid=None),
 3562             _get_cached_node(
 3563                 uuid=uuidutils.generate_uuid(), instance_uuid=None),
 3564             _get_cached_node(
 3565                 uuid=uuidutils.generate_uuid(), instance_uuid=None),
 3566         ]
 3567         hosts = [self.host, self.host, self.host]
 3568 
 3569         self._test__refresh_cache(instances, nodes, hosts)
 3570 
 3571         expected_cache = {n.uuid: n for n in nodes}
 3572         self.assertEqual(expected_cache, self.driver.node_cache)
 3573 
 3574     def test__refresh_cache_multiple_services(self):
 3575         # normal operation, many compute services
 3576         instances = []
 3577         nodes = [
 3578             _get_cached_node(
 3579                 uuid=uuidutils.generate_uuid(), instance_uuid=None),
 3580             _get_cached_node(
 3581                 uuid=uuidutils.generate_uuid(), instance_uuid=None),
 3582             _get_cached_node(
 3583                 uuid=uuidutils.generate_uuid(), instance_uuid=None),
 3584         ]
 3585         hosts = [self.host, 'host2', 'host3']
 3586 
 3587         self._test__refresh_cache(instances, nodes, hosts)
 3588 
 3589         expected_cache = {n.uuid: n for n in nodes[0:1]}
 3590         self.assertEqual(expected_cache, self.driver.node_cache)
 3591 
 3592     def test__refresh_cache_our_instances(self):
 3593         # we should manage a node we have an instance for, even if it doesn't
 3594         # map to us
 3595         instances = [uuidutils.generate_uuid()]
 3596         nodes = [
 3597             _get_cached_node(
 3598                 uuid=uuidutils.generate_uuid(), instance_uuid=instances[0]),
 3599             _get_cached_node(
 3600                 uuid=uuidutils.generate_uuid(), instance_uuid=None),
 3601             _get_cached_node(
 3602                 uuid=uuidutils.generate_uuid(), instance_uuid=None),
 3603         ]
 3604         # only two calls, having the instance will short-circuit the first node
 3605         hosts = [{self.host}, {self.host}]
 3606 
 3607         self._test__refresh_cache(instances, nodes, hosts)
 3608 
 3609         expected_cache = {n.uuid: n for n in nodes}
 3610         self.assertEqual(expected_cache, self.driver.node_cache)
 3611 
 3612     def test__refresh_cache_their_instances(self):
 3613         # we should never manage a node that another compute service has
 3614         # an instance for, even if it maps to us
 3615         instances = []
 3616         nodes = [
 3617             _get_cached_node(
 3618                 uuid=uuidutils.generate_uuid(),
 3619                 instance_uuid=uuidutils.generate_uuid()),
 3620             _get_cached_node(
 3621                 uuid=uuidutils.generate_uuid(), instance_uuid=None),
 3622             _get_cached_node(
 3623                 uuid=uuidutils.generate_uuid(), instance_uuid=None),
 3624         ]
 3625         hosts = [self.host, self.host]
 3626 
 3627         # only two calls, having the instance will short-circuit the first node
 3628         self._test__refresh_cache(instances, nodes, hosts)
 3629 
 3630         expected_cache = {n.uuid: n for n in nodes[1:]}
 3631         self.assertEqual(expected_cache, self.driver.node_cache)
 3632 
 3633 
 3634 @mock.patch.object(FAKE_CLIENT, 'node')
 3635 class IronicDriverConsoleTestCase(test.NoDBTestCase):
 3636     @mock.patch.object(cw, 'IronicClientWrapper',
 3637                        lambda *_: FAKE_CLIENT_WRAPPER)
 3638     @mock.patch.object(objects.ServiceList, 'get_all_computes_by_hv_type')
 3639     def setUp(self, mock_services):
 3640         super(IronicDriverConsoleTestCase, self).setUp()
 3641 
 3642         self.driver = ironic_driver.IronicDriver(fake.FakeVirtAPI())
 3643         self.ctx = nova_context.get_admin_context()
 3644         node_uuid = uuidutils.generate_uuid()
 3645         self.node = _get_cached_node(driver='fake', uuid=node_uuid)
 3646         self.instance = fake_instance.fake_instance_obj(self.ctx,
 3647                                                         node=node_uuid)
 3648 
 3649         # mock retries configs to avoid sleeps and make tests run quicker
 3650         CONF.set_default('api_max_retries', default=1, group='ironic')
 3651         CONF.set_default('api_retry_interval', default=0, group='ironic')
 3652 
 3653         self.stub_out('nova.virt.ironic.driver.IronicDriver.'
 3654                       '_validate_instance_and_node',
 3655                       lambda _, inst: self.node)
 3656 
 3657     def _create_console_data(self, enabled=True, console_type='socat',
 3658                              url='tcp://127.0.0.1:10000'):
 3659         return {
 3660             'console_enabled': enabled,
 3661             'console_info': {
 3662                 'type': console_type,
 3663                 'url': url
 3664             }
 3665         }
 3666 
 3667     def test__get_node_console_with_reset_success(self, mock_node):
 3668         temp_data = {'target_mode': True}
 3669 
 3670         def _fake_get_console(node_uuid):
 3671             return self._create_console_data(enabled=temp_data['target_mode'])
 3672 
 3673         def _fake_set_console_mode(node_uuid, mode):
 3674             # Set it up so that _fake_get_console() returns 'mode'
 3675             temp_data['target_mode'] = mode
 3676 
 3677         mock_node.get_console.side_effect = _fake_get_console
 3678         mock_node.set_console_mode.side_effect = _fake_set_console_mode
 3679 
 3680         expected = self._create_console_data()['console_info']
 3681 
 3682         result = self.driver._get_node_console_with_reset(self.instance)
 3683 
 3684         self.assertGreater(mock_node.get_console.call_count, 1)
 3685         self.assertEqual(2, mock_node.set_console_mode.call_count)
 3686         self.assertEqual(self.node.uuid, result['node'].uuid)
 3687         self.assertThat(result['console_info'],
 3688                         nova_matchers.DictMatches(expected))
 3689 
 3690     @mock.patch.object(ironic_driver, 'LOG', autospec=True)
 3691     def test__get_node_console_with_reset_console_disabled(self, mock_log,
 3692                                                            mock_node):
 3693         def _fake_log_debug(msg, *args, **kwargs):
 3694             regex = r'Console is disabled for instance .*'
 3695             self.assertThat(msg, matchers.MatchesRegex(regex))
 3696 
 3697         mock_node.get_console.return_value = \
 3698             self._create_console_data(enabled=False)
 3699         mock_log.debug.side_effect = _fake_log_debug
 3700 
 3701         self.assertRaises(exception.ConsoleNotAvailable,
 3702                           self.driver._get_node_console_with_reset,
 3703                           self.instance)
 3704 
 3705         mock_node.get_console.assert_called_once_with(self.node.uuid)
 3706         mock_node.set_console_mode.assert_not_called()
 3707         self.assertTrue(mock_log.debug.called)
 3708 
 3709     @mock.patch.object(ironic_driver, 'LOG', autospec=True)
 3710     def test__get_node_console_with_reset_set_mode_failed(self, mock_log,
 3711                                                           mock_node):
 3712         def _fake_log_error(msg, *args, **kwargs):
 3713             regex = r'Failed to set console mode .*'
 3714             self.assertThat(msg, matchers.MatchesRegex(regex))
 3715 
 3716         mock_node.get_console.return_value = self._create_console_data()
 3717         mock_node.set_console_mode.side_effect = exception.NovaException()
 3718         mock_log.error.side_effect = _fake_log_error
 3719 
 3720         self.assertRaises(exception.ConsoleNotAvailable,
 3721                           self.driver._get_node_console_with_reset,
 3722                           self.instance)
 3723 
 3724         mock_node.get_console.assert_called_once_with(self.node.uuid)
 3725         self.assertEqual(2, mock_node.set_console_mode.call_count)
 3726         self.assertTrue(mock_log.error.called)
 3727 
 3728     @mock.patch.object(ironic_driver, 'LOG', autospec=True)
 3729     def test__get_node_console_with_reset_wait_failed(self, mock_log,
 3730                                                       mock_node):
 3731         def _fake_get_console(node_uuid):
 3732             if mock_node.set_console_mode.called:
 3733                 # After the call to set_console_mode(), then _wait_state()
 3734                 # will call _get_console() to check the result.
 3735                 raise exception.NovaException()
 3736             else:
 3737                 return self._create_console_data()
 3738 
 3739         def _fake_log_error(msg, *args, **kwargs):
 3740             regex = r'Failed to acquire console information for instance .*'
 3741             self.assertThat(msg, matchers.MatchesRegex(regex))
 3742 
 3743         mock_node.get_console.side_effect = _fake_get_console
 3744         mock_log.error.side_effect = _fake_log_error
 3745 
 3746         self.assertRaises(exception.ConsoleNotAvailable,
 3747                           self.driver._get_node_console_with_reset,
 3748                           self.instance)
 3749 
 3750         self.assertGreater(mock_node.get_console.call_count, 1)
 3751         self.assertEqual(2, mock_node.set_console_mode.call_count)
 3752         self.assertTrue(mock_log.error.called)
 3753 
 3754     @mock.patch.object(ironic_driver, '_CONSOLE_STATE_CHECKING_INTERVAL', 0.05)
 3755     @mock.patch.object(loopingcall, 'BackOffLoopingCall')
 3756     @mock.patch.object(ironic_driver, 'LOG', autospec=True)
 3757     def test__get_node_console_with_reset_wait_timeout(self, mock_log,
 3758                                                        mock_looping,
 3759                                                        mock_node):
 3760         CONF.set_override('serial_console_state_timeout', 1, group='ironic')
 3761         temp_data = {'target_mode': True}
 3762 
 3763         def _fake_get_console(node_uuid):
 3764             return self._create_console_data(enabled=temp_data['target_mode'])
 3765 
 3766         def _fake_set_console_mode(node_uuid, mode):
 3767             temp_data['target_mode'] = not mode
 3768 
 3769         def _fake_log_error(msg, *args, **kwargs):
 3770             regex = r'Timeout while waiting for console mode to be set .*'
 3771             self.assertThat(msg, matchers.MatchesRegex(regex))
 3772 
 3773         mock_node.get_console.side_effect = _fake_get_console
 3774         mock_node.set_console_mode.side_effect = _fake_set_console_mode
 3775         mock_log.error.side_effect = _fake_log_error
 3776 
 3777         mock_timer = mock_looping.return_value
 3778         mock_event = mock_timer.start.return_value
 3779         mock_event.wait.side_effect = loopingcall.LoopingCallTimeOut
 3780 
 3781         self.assertRaises(exception.ConsoleNotAvailable,
 3782                           self.driver._get_node_console_with_reset,
 3783                           self.instance)
 3784 
 3785         self.assertEqual(mock_node.get_console.call_count, 1)
 3786         self.assertEqual(2, mock_node.set_console_mode.call_count)
 3787         self.assertTrue(mock_log.error.called)
 3788 
 3789         mock_timer.start.assert_called_with(starting_interval=0.05, timeout=1,
 3790                                             jitter=0.5)
 3791 
 3792     def test_get_serial_console_socat(self, mock_node):
 3793         temp_data = {'target_mode': True}
 3794 
 3795         def _fake_get_console(node_uuid):
 3796             return self._create_console_data(enabled=temp_data['target_mode'])
 3797 
 3798         def _fake_set_console_mode(node_uuid, mode):
 3799             temp_data['target_mode'] = mode
 3800 
 3801         mock_node.get_console.side_effect = _fake_get_console
 3802         mock_node.set_console_mode.side_effect = _fake_set_console_mode
 3803 
 3804         result = self.driver.get_serial_console(self.ctx, self.instance)
 3805 
 3806         self.assertGreater(mock_node.get_console.call_count, 1)
 3807         self.assertEqual(2, mock_node.set_console_mode.call_count)
 3808         self.assertIsInstance(result, console_type.ConsoleSerial)
 3809         self.assertEqual('127.0.0.1', result.host)
 3810         self.assertEqual(10000, result.port)
 3811 
 3812     def test_get_serial_console_socat_disabled(self, mock_node):
 3813         mock_node.get_console.return_value = \
 3814             self._create_console_data(enabled=False)
 3815 
 3816         self.assertRaises(exception.ConsoleTypeUnavailable,
 3817                           self.driver.get_serial_console,
 3818                           self.ctx, self.instance)
 3819         mock_node.get_console.assert_called_once_with(self.node.uuid)
 3820         mock_node.set_console_mode.assert_not_called()
 3821 
 3822     @mock.patch.object(ironic_driver, 'LOG', autospec=True)
 3823     def test_get_serial_console_socat_invalid_url(self, mock_log, mock_node):
 3824         temp_data = {'target_mode': True}
 3825 
 3826         def _fake_get_console(node_uuid):
 3827             return self._create_console_data(enabled=temp_data['target_mode'],
 3828                                              url='an invalid url')
 3829 
 3830         def _fake_set_console_mode(node_uuid, mode):
 3831             temp_data['target_mode'] = mode
 3832 
 3833         def _fake_log_error(msg, *args, **kwargs):
 3834             regex = r'Invalid Socat console URL .*'
 3835             self.assertThat(msg, matchers.MatchesRegex(regex))
 3836 
 3837         mock_node.get_console.side_effect = _fake_get_console
 3838         mock_node.set_console_mode.side_effect = _fake_set_console_mode
 3839         mock_log.error.side_effect = _fake_log_error
 3840 
 3841         self.assertRaises(exception.ConsoleTypeUnavailable,
 3842                           self.driver.get_serial_console,
 3843                           self.ctx, self.instance)
 3844 
 3845         self.assertGreater(mock_node.get_console.call_count, 1)
 3846         self.assertEqual(2, mock_node.set_console_mode.call_count)
 3847         self.assertTrue(mock_log.error.called)
 3848 
 3849     @mock.patch.object(ironic_driver, 'LOG', autospec=True)
 3850     def test_get_serial_console_socat_invalid_url_2(self, mock_log, mock_node):
 3851         temp_data = {'target_mode': True}
 3852 
 3853         def _fake_get_console(node_uuid):
 3854             return self._create_console_data(enabled=temp_data['target_mode'],
 3855                                              url='http://abcxyz:1a1b')
 3856 
 3857         def _fake_set_console_mode(node_uuid, mode):
 3858             temp_data['target_mode'] = mode
 3859 
 3860         def _fake_log_error(msg, *args, **kwargs):
 3861             regex = r'Invalid Socat console URL .*'
 3862             self.assertThat(msg, matchers.MatchesRegex(regex))
 3863 
 3864         mock_node.get_console.side_effect = _fake_get_console
 3865         mock_node.set_console_mode.side_effect = _fake_set_console_mode
 3866         mock_log.error.side_effect = _fake_log_error
 3867 
 3868         self.assertRaises(exception.ConsoleTypeUnavailable,
 3869                           self.driver.get_serial_console,
 3870                           self.ctx, self.instance)
 3871 
 3872         self.assertGreater(mock_node.get_console.call_count, 1)
 3873         self.assertEqual(2, mock_node.set_console_mode.call_count)
 3874         self.assertTrue(mock_log.error.called)
 3875 
 3876     @mock.patch.object(ironic_driver, 'LOG', autospec=True)
 3877     def test_get_serial_console_socat_unsupported_scheme(self, mock_log,
 3878                                                          mock_node):
 3879         temp_data = {'target_mode': True}
 3880 
 3881         def _fake_get_console(node_uuid):
 3882             return self._create_console_data(enabled=temp_data['target_mode'],
 3883                                              url='ssl://127.0.0.1:10000')
 3884 
 3885         def _fake_set_console_mode(node_uuid, mode):
 3886             temp_data['target_mode'] = mode
 3887 
 3888         def _fake_log_warning(msg, *args, **kwargs):
 3889             regex = r'Socat serial console only supports \"tcp\".*'
 3890             self.assertThat(msg, matchers.MatchesRegex(regex))
 3891 
 3892         mock_node.get_console.side_effect = _fake_get_console
 3893         mock_node.set_console_mode.side_effect = _fake_set_console_mode
 3894         mock_log.warning.side_effect = _fake_log_warning
 3895 
 3896         self.assertRaises(exception.ConsoleTypeUnavailable,
 3897                           self.driver.get_serial_console,
 3898                           self.ctx, self.instance)
 3899 
 3900         self.assertGreater(mock_node.get_console.call_count, 1)
 3901         self.assertEqual(2, mock_node.set_console_mode.call_count)
 3902         self.assertTrue(mock_log.warning.called)
 3903 
 3904     def test_get_serial_console_socat_tcp6(self, mock_node):
 3905         temp_data = {'target_mode': True}
 3906 
 3907         def _fake_get_console(node_uuid):
 3908             return self._create_console_data(enabled=temp_data['target_mode'],
 3909                                              url='tcp://[::1]:10000')
 3910 
 3911         def _fake_set_console_mode(node_uuid, mode):
 3912             temp_data['target_mode'] = mode
 3913 
 3914         mock_node.get_console.side_effect = _fake_get_console
 3915         mock_node.set_console_mode.side_effect = _fake_set_console_mode
 3916 
 3917         result = self.driver.get_serial_console(self.ctx, self.instance)
 3918 
 3919         self.assertGreater(mock_node.get_console.call_count, 1)
 3920         self.assertEqual(2, mock_node.set_console_mode.call_count)
 3921         self.assertIsInstance(result, console_type.ConsoleSerial)
 3922         self.assertEqual('::1', result.host)
 3923         self.assertEqual(10000, result.port)
 3924 
 3925     def test_get_serial_console_shellinabox(self, mock_node):
 3926         temp_data = {'target_mode': True}
 3927 
 3928         def _fake_get_console(node_uuid):
 3929             return self._create_console_data(enabled=temp_data['target_mode'],
 3930                                              console_type='shellinabox')
 3931 
 3932         def _fake_set_console_mode(node_uuid, mode):
 3933             temp_data['target_mode'] = mode
 3934 
 3935         mock_node.get_console.side_effect = _fake_get_console
 3936         mock_node.set_console_mode.side_effect = _fake_set_console_mode
 3937 
 3938         self.assertRaises(exception.ConsoleTypeUnavailable,
 3939                           self.driver.get_serial_console,
 3940                           self.ctx, self.instance)
 3941 
 3942         self.assertGreater(mock_node.get_console.call_count, 1)
 3943         self.assertEqual(2, mock_node.set_console_mode.call_count)