
Currently ironic explicitly or implicitly sets the API urls for most services in the config. This is quite fragile and we should move to discovery from the keystone catalog eventually. To support this, this patch registers `keystoneauth1.adapter.Adapter` options to all config sections for service clients auth. Among others it exports `interfaces` option that we set to ['internal', 'public'] by default. Other exported options are `service_type`, `service_name`, `region_name` and `endpoint_override`. The latter will eventually be used by all clients to specify a specific endpoint to use (for example in noauth mode). Effectively this patch starts to move all clients code to load client configuration from config for all of auth, session and adapter. The first to move is [service_catalog] section, with [conductor]api_url option being deprecated in favor of [service_catalog]endpoint_override. A sane default of 'service_type' = 'baremetal' is set for this config section as well. More patches moving other clients to consume these new options and deprecate some other options will follow. Change-Id: I1283ef3b4d736ac089df0cc74a5850a93b24b6ab Partial-Bug: #1699547 Related-Bug: #1699542
999 lines
50 KiB
Python
999 lines
50 KiB
Python
# Copyright 2013 Hewlett-Packard Development Company, L.P.
|
|
# All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
"""Test class for iSCSI deploy mechanism."""
|
|
|
|
import os
|
|
import tempfile
|
|
|
|
from ironic_lib import disk_utils
|
|
from ironic_lib import utils as ironic_utils
|
|
import mock
|
|
from oslo_config import cfg
|
|
from oslo_utils import fileutils
|
|
|
|
from ironic.common import dhcp_factory
|
|
from ironic.common import driver_factory
|
|
from ironic.common import exception
|
|
from ironic.common import pxe_utils
|
|
from ironic.common import states
|
|
from ironic.common import utils
|
|
from ironic.conductor import task_manager
|
|
from ironic.conductor import utils as manager_utils
|
|
from ironic.drivers.modules import agent_base_vendor
|
|
from ironic.drivers.modules import agent_client
|
|
from ironic.drivers.modules import deploy_utils
|
|
from ironic.drivers.modules import iscsi_deploy
|
|
from ironic.drivers.modules.network import flat as flat_network
|
|
from ironic.drivers.modules import pxe
|
|
from ironic.drivers.modules.storage import noop as noop_storage
|
|
from ironic.drivers import utils as driver_utils
|
|
from ironic.tests.unit.conductor import mgr_utils
|
|
from ironic.tests.unit.db import base as db_base
|
|
from ironic.tests.unit.db import utils as db_utils
|
|
from ironic.tests.unit.objects import utils as obj_utils
|
|
|
|
CONF = cfg.CONF
|
|
|
|
INST_INFO_DICT = db_utils.get_test_pxe_instance_info()
|
|
DRV_INFO_DICT = db_utils.get_test_pxe_driver_info()
|
|
DRV_INTERNAL_INFO_DICT = db_utils.get_test_pxe_driver_internal_info()
|
|
|
|
|
|
class IscsiDeployPrivateMethodsTestCase(db_base.DbTestCase):
|
|
|
|
def setUp(self):
|
|
super(IscsiDeployPrivateMethodsTestCase, self).setUp()
|
|
n = {
|
|
'driver': 'fake_pxe',
|
|
'instance_info': INST_INFO_DICT,
|
|
'driver_info': DRV_INFO_DICT,
|
|
'driver_internal_info': DRV_INTERNAL_INFO_DICT,
|
|
}
|
|
mgr_utils.mock_the_extension_manager(driver="fake_pxe")
|
|
self.node = obj_utils.create_test_node(self.context, **n)
|
|
|
|
def test__save_disk_layout(self):
|
|
info = dict(INST_INFO_DICT)
|
|
info['ephemeral_gb'] = 10
|
|
info['swap_mb'] = 0
|
|
info['root_gb'] = 10
|
|
info['preserve_ephemeral'] = False
|
|
self.node.instance_info = info
|
|
|
|
iscsi_deploy._save_disk_layout(self.node, info)
|
|
self.node.refresh()
|
|
for param in ('ephemeral_gb', 'swap_mb', 'root_gb'):
|
|
self.assertEqual(
|
|
info[param], self.node.driver_internal_info['instance'][param]
|
|
)
|
|
|
|
def test__get_image_dir_path(self):
|
|
self.assertEqual(os.path.join(CONF.pxe.images_path,
|
|
self.node.uuid),
|
|
iscsi_deploy._get_image_dir_path(self.node.uuid))
|
|
|
|
def test__get_image_file_path(self):
|
|
self.assertEqual(os.path.join(CONF.pxe.images_path,
|
|
self.node.uuid,
|
|
'disk'),
|
|
iscsi_deploy._get_image_file_path(self.node.uuid))
|
|
|
|
|
|
class IscsiDeployMethodsTestCase(db_base.DbTestCase):
|
|
|
|
def setUp(self):
|
|
super(IscsiDeployMethodsTestCase, self).setUp()
|
|
instance_info = dict(INST_INFO_DICT)
|
|
instance_info['deploy_key'] = 'fake-56789'
|
|
n = {
|
|
'driver': 'fake_pxe',
|
|
'instance_info': instance_info,
|
|
'driver_info': DRV_INFO_DICT,
|
|
'driver_internal_info': DRV_INTERNAL_INFO_DICT,
|
|
}
|
|
mgr_utils.mock_the_extension_manager(driver="fake_pxe")
|
|
self.node = obj_utils.create_test_node(self.context, **n)
|
|
|
|
@mock.patch.object(disk_utils, 'get_image_mb', autospec=True)
|
|
def test_check_image_size(self, get_image_mb_mock):
|
|
get_image_mb_mock.return_value = 1000
|
|
with task_manager.acquire(self.context, self.node.uuid,
|
|
shared=False) as task:
|
|
task.node.instance_info['root_gb'] = 1
|
|
iscsi_deploy.check_image_size(task)
|
|
get_image_mb_mock.assert_called_once_with(
|
|
iscsi_deploy._get_image_file_path(task.node.uuid))
|
|
|
|
@mock.patch.object(disk_utils, 'get_image_mb', autospec=True)
|
|
def test_check_image_size_fails(self, get_image_mb_mock):
|
|
get_image_mb_mock.return_value = 1025
|
|
with task_manager.acquire(self.context, self.node.uuid,
|
|
shared=False) as task:
|
|
task.node.instance_info['root_gb'] = 1
|
|
self.assertRaises(exception.InstanceDeployFailure,
|
|
iscsi_deploy.check_image_size,
|
|
task)
|
|
get_image_mb_mock.assert_called_once_with(
|
|
iscsi_deploy._get_image_file_path(task.node.uuid))
|
|
|
|
@mock.patch.object(deploy_utils, 'fetch_images', autospec=True)
|
|
def test_cache_instance_images_master_path(self, mock_fetch_image):
|
|
temp_dir = tempfile.mkdtemp()
|
|
self.config(images_path=temp_dir, group='pxe')
|
|
self.config(instance_master_path=os.path.join(temp_dir,
|
|
'instance_master_path'),
|
|
group='pxe')
|
|
fileutils.ensure_tree(CONF.pxe.instance_master_path)
|
|
|
|
(uuid, image_path) = iscsi_deploy.cache_instance_image(None, self.node)
|
|
mock_fetch_image.assert_called_once_with(None,
|
|
mock.ANY,
|
|
[(uuid, image_path)], True)
|
|
self.assertEqual('glance://image_uuid', uuid)
|
|
self.assertEqual(os.path.join(temp_dir,
|
|
self.node.uuid,
|
|
'disk'),
|
|
image_path)
|
|
|
|
@mock.patch.object(ironic_utils, 'unlink_without_raise', autospec=True)
|
|
@mock.patch.object(utils, 'rmtree_without_raise', autospec=True)
|
|
@mock.patch.object(iscsi_deploy, 'InstanceImageCache', autospec=True)
|
|
def test_destroy_images(self, mock_cache, mock_rmtree, mock_unlink):
|
|
self.config(images_path='/path', group='pxe')
|
|
|
|
iscsi_deploy.destroy_images('uuid')
|
|
|
|
mock_cache.return_value.clean_up.assert_called_once_with()
|
|
mock_unlink.assert_called_once_with('/path/uuid/disk')
|
|
mock_rmtree.assert_called_once_with('/path/uuid')
|
|
|
|
@mock.patch.object(driver_utils, 'collect_ramdisk_logs', autospec=True)
|
|
@mock.patch.object(iscsi_deploy, '_save_disk_layout', autospec=True)
|
|
@mock.patch.object(iscsi_deploy, 'InstanceImageCache', autospec=True)
|
|
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
|
|
@mock.patch.object(deploy_utils, 'deploy_partition_image', autospec=True)
|
|
def test_continue_deploy_fail(
|
|
self, deploy_mock, power_mock, mock_image_cache, mock_disk_layout,
|
|
mock_collect_logs):
|
|
kwargs = {'address': '123456', 'iqn': 'aaa-bbb'}
|
|
deploy_mock.side_effect = exception.InstanceDeployFailure(
|
|
"test deploy error")
|
|
self.node.provision_state = states.DEPLOYWAIT
|
|
self.node.target_provision_state = states.ACTIVE
|
|
self.node.save()
|
|
|
|
with task_manager.acquire(self.context, self.node.uuid,
|
|
shared=False) as task:
|
|
params = iscsi_deploy.get_deploy_info(task.node, **kwargs)
|
|
# Ironic exceptions are preserved as they are
|
|
self.assertRaisesRegex(exception.InstanceDeployFailure,
|
|
'^test deploy error$',
|
|
iscsi_deploy.continue_deploy,
|
|
task, **kwargs)
|
|
self.assertEqual(states.DEPLOYFAIL, task.node.provision_state)
|
|
self.assertEqual(states.ACTIVE, task.node.target_provision_state)
|
|
self.assertIsNotNone(task.node.last_error)
|
|
deploy_mock.assert_called_once_with(**params)
|
|
power_mock.assert_called_once_with(task, states.POWER_OFF)
|
|
mock_image_cache.assert_called_once_with()
|
|
mock_image_cache.return_value.clean_up.assert_called_once_with()
|
|
self.assertFalse(mock_disk_layout.called)
|
|
mock_collect_logs.assert_called_once_with(task.node)
|
|
|
|
@mock.patch.object(driver_utils, 'collect_ramdisk_logs', autospec=True)
|
|
@mock.patch.object(iscsi_deploy, '_save_disk_layout', autospec=True)
|
|
@mock.patch.object(iscsi_deploy, 'InstanceImageCache', autospec=True)
|
|
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
|
|
@mock.patch.object(deploy_utils, 'deploy_partition_image', autospec=True)
|
|
def test_continue_deploy_unexpected_fail(
|
|
self, deploy_mock, power_mock, mock_image_cache, mock_disk_layout,
|
|
mock_collect_logs):
|
|
kwargs = {'address': '123456', 'iqn': 'aaa-bbb'}
|
|
deploy_mock.side_effect = KeyError('boom')
|
|
self.node.provision_state = states.DEPLOYWAIT
|
|
self.node.target_provision_state = states.ACTIVE
|
|
self.node.save()
|
|
|
|
with task_manager.acquire(self.context, self.node.uuid,
|
|
shared=False) as task:
|
|
params = iscsi_deploy.get_deploy_info(task.node, **kwargs)
|
|
self.assertRaisesRegex(exception.InstanceDeployFailure,
|
|
"Deploy failed.*Error: 'boom'",
|
|
iscsi_deploy.continue_deploy,
|
|
task, **kwargs)
|
|
self.assertEqual(states.DEPLOYFAIL, task.node.provision_state)
|
|
self.assertEqual(states.ACTIVE, task.node.target_provision_state)
|
|
self.assertIsNotNone(task.node.last_error)
|
|
deploy_mock.assert_called_once_with(**params)
|
|
power_mock.assert_called_once_with(task, states.POWER_OFF)
|
|
mock_image_cache.assert_called_once_with()
|
|
mock_image_cache.return_value.clean_up.assert_called_once_with()
|
|
self.assertFalse(mock_disk_layout.called)
|
|
mock_collect_logs.assert_called_once_with(task.node)
|
|
|
|
@mock.patch.object(driver_utils, 'collect_ramdisk_logs', autospec=True)
|
|
@mock.patch.object(iscsi_deploy, '_save_disk_layout', autospec=True)
|
|
@mock.patch.object(iscsi_deploy, 'InstanceImageCache', autospec=True)
|
|
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
|
|
@mock.patch.object(deploy_utils, 'deploy_partition_image', autospec=True)
|
|
def test_continue_deploy_fail_no_root_uuid_or_disk_id(
|
|
self, deploy_mock, power_mock, mock_image_cache, mock_disk_layout,
|
|
mock_collect_logs):
|
|
kwargs = {'address': '123456', 'iqn': 'aaa-bbb'}
|
|
deploy_mock.return_value = {}
|
|
self.node.provision_state = states.DEPLOYWAIT
|
|
self.node.target_provision_state = states.ACTIVE
|
|
self.node.save()
|
|
|
|
with task_manager.acquire(self.context, self.node.uuid,
|
|
shared=False) as task:
|
|
params = iscsi_deploy.get_deploy_info(task.node, **kwargs)
|
|
self.assertRaises(exception.InstanceDeployFailure,
|
|
iscsi_deploy.continue_deploy,
|
|
task, **kwargs)
|
|
self.assertEqual(states.DEPLOYFAIL, task.node.provision_state)
|
|
self.assertEqual(states.ACTIVE, task.node.target_provision_state)
|
|
self.assertIsNotNone(task.node.last_error)
|
|
deploy_mock.assert_called_once_with(**params)
|
|
power_mock.assert_called_once_with(task, states.POWER_OFF)
|
|
mock_image_cache.assert_called_once_with()
|
|
mock_image_cache.return_value.clean_up.assert_called_once_with()
|
|
self.assertFalse(mock_disk_layout.called)
|
|
mock_collect_logs.assert_called_once_with(task.node)
|
|
|
|
@mock.patch.object(driver_utils, 'collect_ramdisk_logs', autospec=True)
|
|
@mock.patch.object(iscsi_deploy, '_save_disk_layout', autospec=True)
|
|
@mock.patch.object(iscsi_deploy, 'InstanceImageCache', autospec=True)
|
|
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
|
|
@mock.patch.object(deploy_utils, 'deploy_partition_image', autospec=True)
|
|
def test_continue_deploy_fail_empty_root_uuid(
|
|
self, deploy_mock, power_mock, mock_image_cache,
|
|
mock_disk_layout, mock_collect_logs):
|
|
kwargs = {'address': '123456', 'iqn': 'aaa-bbb'}
|
|
deploy_mock.return_value = {'root uuid': ''}
|
|
self.node.provision_state = states.DEPLOYWAIT
|
|
self.node.target_provision_state = states.ACTIVE
|
|
self.node.save()
|
|
|
|
with task_manager.acquire(self.context, self.node.uuid,
|
|
shared=False) as task:
|
|
params = iscsi_deploy.get_deploy_info(task.node, **kwargs)
|
|
self.assertRaises(exception.InstanceDeployFailure,
|
|
iscsi_deploy.continue_deploy,
|
|
task, **kwargs)
|
|
self.assertEqual(states.DEPLOYFAIL, task.node.provision_state)
|
|
self.assertEqual(states.ACTIVE, task.node.target_provision_state)
|
|
self.assertIsNotNone(task.node.last_error)
|
|
deploy_mock.assert_called_once_with(**params)
|
|
power_mock.assert_called_once_with(task, states.POWER_OFF)
|
|
mock_image_cache.assert_called_once_with()
|
|
mock_image_cache.return_value.clean_up.assert_called_once_with()
|
|
self.assertFalse(mock_disk_layout.called)
|
|
mock_collect_logs.assert_called_once_with(task.node)
|
|
|
|
@mock.patch.object(iscsi_deploy, '_save_disk_layout', autospec=True)
|
|
@mock.patch.object(iscsi_deploy, 'LOG', autospec=True)
|
|
@mock.patch.object(iscsi_deploy, 'get_deploy_info', autospec=True)
|
|
@mock.patch.object(iscsi_deploy, 'InstanceImageCache', autospec=True)
|
|
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
|
|
@mock.patch.object(deploy_utils, 'deploy_partition_image', autospec=True)
|
|
def test_continue_deploy(self, deploy_mock, power_mock, mock_image_cache,
|
|
mock_deploy_info, mock_log, mock_disk_layout):
|
|
kwargs = {'address': '123456', 'iqn': 'aaa-bbb'}
|
|
self.node.provision_state = states.DEPLOYWAIT
|
|
self.node.target_provision_state = states.ACTIVE
|
|
self.node.save()
|
|
|
|
mock_deploy_info.return_value = {
|
|
'address': '123456',
|
|
'boot_option': 'netboot',
|
|
'configdrive': "I've got the power",
|
|
'ephemeral_format': None,
|
|
'ephemeral_mb': 0,
|
|
'image_path': (u'/var/lib/ironic/images/1be26c0b-03f2-4d2e-ae87-'
|
|
u'c02d7f33c123/disk'),
|
|
'iqn': 'aaa-bbb',
|
|
'lun': '1',
|
|
'node_uuid': u'1be26c0b-03f2-4d2e-ae87-c02d7f33c123',
|
|
'port': '3260',
|
|
'preserve_ephemeral': True,
|
|
'root_mb': 102400,
|
|
'swap_mb': 0,
|
|
}
|
|
log_params = mock_deploy_info.return_value.copy()
|
|
# Make sure we don't log the full content of the configdrive
|
|
log_params['configdrive'] = '***'
|
|
expected_dict = {
|
|
'node': self.node.uuid,
|
|
'params': log_params,
|
|
}
|
|
uuid_dict_returned = {'root uuid': '12345678-87654321'}
|
|
deploy_mock.return_value = uuid_dict_returned
|
|
|
|
with task_manager.acquire(self.context, self.node.uuid,
|
|
shared=False) as task:
|
|
mock_log.isEnabledFor.return_value = True
|
|
retval = iscsi_deploy.continue_deploy(task, **kwargs)
|
|
mock_log.debug.assert_called_once_with(
|
|
mock.ANY, expected_dict)
|
|
self.assertEqual(states.DEPLOYWAIT, task.node.provision_state)
|
|
self.assertEqual(states.ACTIVE, task.node.target_provision_state)
|
|
self.assertIsNone(task.node.last_error)
|
|
mock_image_cache.assert_called_once_with()
|
|
mock_image_cache.return_value.clean_up.assert_called_once_with()
|
|
self.assertEqual(uuid_dict_returned, retval)
|
|
mock_disk_layout.assert_called_once_with(task.node, mock.ANY)
|
|
|
|
@mock.patch.object(iscsi_deploy, 'LOG', autospec=True)
|
|
@mock.patch.object(iscsi_deploy, 'get_deploy_info', autospec=True)
|
|
@mock.patch.object(iscsi_deploy, 'InstanceImageCache', autospec=True)
|
|
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
|
|
@mock.patch.object(deploy_utils, 'deploy_disk_image', autospec=True)
|
|
def test_continue_deploy_whole_disk_image(
|
|
self, deploy_mock, power_mock, mock_image_cache, mock_deploy_info,
|
|
mock_log):
|
|
kwargs = {'address': '123456', 'iqn': 'aaa-bbb'}
|
|
self.node.provision_state = states.DEPLOYWAIT
|
|
self.node.target_provision_state = states.ACTIVE
|
|
self.node.save()
|
|
|
|
mock_deploy_info.return_value = {
|
|
'address': '123456',
|
|
'image_path': (u'/var/lib/ironic/images/1be26c0b-03f2-4d2e-ae87-'
|
|
u'c02d7f33c123/disk'),
|
|
'iqn': 'aaa-bbb',
|
|
'lun': '1',
|
|
'node_uuid': u'1be26c0b-03f2-4d2e-ae87-c02d7f33c123',
|
|
'port': '3260',
|
|
}
|
|
log_params = mock_deploy_info.return_value.copy()
|
|
expected_dict = {
|
|
'node': self.node.uuid,
|
|
'params': log_params,
|
|
}
|
|
uuid_dict_returned = {'disk identifier': '87654321'}
|
|
deploy_mock.return_value = uuid_dict_returned
|
|
with task_manager.acquire(self.context, self.node.uuid,
|
|
shared=False) as task:
|
|
task.node.driver_internal_info['is_whole_disk_image'] = True
|
|
mock_log.isEnabledFor.return_value = True
|
|
retval = iscsi_deploy.continue_deploy(task, **kwargs)
|
|
mock_log.debug.assert_called_once_with(
|
|
mock.ANY, expected_dict)
|
|
self.assertEqual(states.DEPLOYWAIT, task.node.provision_state)
|
|
self.assertEqual(states.ACTIVE, task.node.target_provision_state)
|
|
self.assertIsNone(task.node.last_error)
|
|
mock_image_cache.assert_called_once_with()
|
|
mock_image_cache.return_value.clean_up.assert_called_once_with()
|
|
self.assertEqual(uuid_dict_returned, retval)
|
|
|
|
def _test_get_deploy_info(self, extra_instance_info=None):
|
|
if extra_instance_info is None:
|
|
extra_instance_info = {}
|
|
|
|
instance_info = self.node.instance_info
|
|
instance_info.update(extra_instance_info)
|
|
self.node.instance_info = instance_info
|
|
kwargs = {'address': '1.1.1.1', 'iqn': 'target-iqn'}
|
|
ret_val = iscsi_deploy.get_deploy_info(self.node, **kwargs)
|
|
self.assertEqual('1.1.1.1', ret_val['address'])
|
|
self.assertEqual('target-iqn', ret_val['iqn'])
|
|
return ret_val
|
|
|
|
def test_get_deploy_info_boot_option_default(self):
|
|
ret_val = self._test_get_deploy_info()
|
|
self.assertEqual('netboot', ret_val['boot_option'])
|
|
|
|
def test_get_deploy_info_netboot_specified(self):
|
|
capabilities = {'capabilities': {'boot_option': 'netboot'}}
|
|
ret_val = self._test_get_deploy_info(extra_instance_info=capabilities)
|
|
self.assertEqual('netboot', ret_val['boot_option'])
|
|
|
|
def test_get_deploy_info_localboot(self):
|
|
capabilities = {'capabilities': {'boot_option': 'local'}}
|
|
ret_val = self._test_get_deploy_info(extra_instance_info=capabilities)
|
|
self.assertEqual('local', ret_val['boot_option'])
|
|
|
|
def test_get_deploy_info_disk_label(self):
|
|
capabilities = {'capabilities': {'disk_label': 'msdos'}}
|
|
ret_val = self._test_get_deploy_info(extra_instance_info=capabilities)
|
|
self.assertEqual('msdos', ret_val['disk_label'])
|
|
|
|
def test_get_deploy_info_not_specified(self):
|
|
ret_val = self._test_get_deploy_info()
|
|
self.assertNotIn('disk_label', ret_val)
|
|
|
|
def test_get_deploy_info_portal_port(self):
|
|
self.config(portal_port=3266, group='iscsi')
|
|
ret_val = self._test_get_deploy_info()
|
|
self.assertEqual(3266, ret_val['port'])
|
|
|
|
def test_get_deploy_info_whole_disk_image(self):
|
|
instance_info = self.node.instance_info
|
|
instance_info['configdrive'] = 'My configdrive'
|
|
self.node.instance_info = instance_info
|
|
self.node.driver_internal_info['is_whole_disk_image'] = True
|
|
kwargs = {'address': '1.1.1.1', 'iqn': 'target-iqn'}
|
|
ret_val = iscsi_deploy.get_deploy_info(self.node, **kwargs)
|
|
self.assertEqual('1.1.1.1', ret_val['address'])
|
|
self.assertEqual('target-iqn', ret_val['iqn'])
|
|
self.assertEqual('My configdrive', ret_val['configdrive'])
|
|
|
|
@mock.patch.object(iscsi_deploy, 'continue_deploy', autospec=True)
|
|
def test_do_agent_iscsi_deploy_okay(self, continue_deploy_mock):
|
|
agent_client_mock = mock.MagicMock(spec_set=agent_client.AgentClient)
|
|
agent_client_mock.start_iscsi_target.return_value = {
|
|
'command_status': 'SUCCESS', 'command_error': None}
|
|
driver_internal_info = {'agent_url': 'http://1.2.3.4:1234'}
|
|
self.node.driver_internal_info = driver_internal_info
|
|
self.node.save()
|
|
uuid_dict_returned = {'root uuid': 'some-root-uuid'}
|
|
continue_deploy_mock.return_value = uuid_dict_returned
|
|
expected_iqn = 'iqn.2008-10.org.openstack:%s' % self.node.uuid
|
|
|
|
with task_manager.acquire(self.context, self.node.uuid,
|
|
shared=False) as task:
|
|
ret_val = iscsi_deploy.do_agent_iscsi_deploy(
|
|
task, agent_client_mock)
|
|
agent_client_mock.start_iscsi_target.assert_called_once_with(
|
|
task.node, expected_iqn, 3260, wipe_disk_metadata=True)
|
|
continue_deploy_mock.assert_called_once_with(
|
|
task, iqn=expected_iqn, address='1.2.3.4')
|
|
self.assertEqual(
|
|
'some-root-uuid',
|
|
task.node.driver_internal_info['root_uuid_or_disk_id'])
|
|
self.assertEqual(ret_val, uuid_dict_returned)
|
|
|
|
@mock.patch.object(iscsi_deploy, 'continue_deploy', autospec=True)
|
|
def test_do_agent_iscsi_deploy_preserve_ephemeral(self,
|
|
continue_deploy_mock):
|
|
"""Ensure the disk is not wiped if preserve_ephemeral is True."""
|
|
agent_client_mock = mock.MagicMock(spec_set=agent_client.AgentClient)
|
|
agent_client_mock.start_iscsi_target.return_value = {
|
|
'command_status': 'SUCCESS', 'command_error': None}
|
|
driver_internal_info = {
|
|
'agent_url': 'http://1.2.3.4:1234'}
|
|
self.node.driver_internal_info = driver_internal_info
|
|
self.node.save()
|
|
uuid_dict_returned = {'root uuid': 'some-root-uuid'}
|
|
continue_deploy_mock.return_value = uuid_dict_returned
|
|
expected_iqn = 'iqn.2008-10.org.openstack:%s' % self.node.uuid
|
|
|
|
with task_manager.acquire(self.context, self.node.uuid,
|
|
shared=False) as task:
|
|
task.node.instance_info['preserve_ephemeral'] = True
|
|
iscsi_deploy.do_agent_iscsi_deploy(
|
|
task, agent_client_mock)
|
|
agent_client_mock.start_iscsi_target.assert_called_once_with(
|
|
task.node, expected_iqn, 3260, wipe_disk_metadata=False)
|
|
|
|
@mock.patch.object(driver_utils, 'collect_ramdisk_logs', autospec=True)
|
|
def test_do_agent_iscsi_deploy_start_iscsi_failure(
|
|
self, mock_collect_logs):
|
|
agent_client_mock = mock.MagicMock(spec_set=agent_client.AgentClient)
|
|
agent_client_mock.start_iscsi_target.return_value = {
|
|
'command_status': 'FAILED', 'command_error': 'booom'}
|
|
self.node.provision_state = states.DEPLOYING
|
|
self.node.target_provision_state = states.ACTIVE
|
|
self.node.save()
|
|
expected_iqn = 'iqn.2008-10.org.openstack:%s' % self.node.uuid
|
|
|
|
with task_manager.acquire(self.context, self.node.uuid,
|
|
shared=False) as task:
|
|
self.assertRaises(exception.InstanceDeployFailure,
|
|
iscsi_deploy.do_agent_iscsi_deploy,
|
|
task, agent_client_mock)
|
|
agent_client_mock.start_iscsi_target.assert_called_once_with(
|
|
task.node, expected_iqn, 3260, wipe_disk_metadata=True)
|
|
self.node.refresh()
|
|
self.assertEqual(states.DEPLOYFAIL, self.node.provision_state)
|
|
self.assertEqual(states.ACTIVE, self.node.target_provision_state)
|
|
self.assertIsNotNone(self.node.last_error)
|
|
mock_collect_logs.assert_called_once_with(task.node)
|
|
|
|
@mock.patch('ironic.drivers.modules.deploy_utils.get_ironic_api_url')
|
|
def test_validate_good_api_url(self, mock_get_url):
|
|
mock_get_url.return_value = 'http://127.0.0.1:1234'
|
|
with task_manager.acquire(self.context, self.node.uuid,
|
|
shared=True) as task:
|
|
iscsi_deploy.validate(task)
|
|
mock_get_url.assert_called_once_with()
|
|
|
|
@mock.patch('ironic.drivers.modules.deploy_utils.get_ironic_api_url')
|
|
def test_validate_fail_no_api_url(self, mock_get_url):
|
|
mock_get_url.side_effect = exception.InvalidParameterValue('Ham!')
|
|
with task_manager.acquire(self.context, self.node.uuid,
|
|
shared=True) as task:
|
|
self.assertRaises(exception.InvalidParameterValue,
|
|
iscsi_deploy.validate, task)
|
|
mock_get_url.assert_called_once_with()
|
|
|
|
@mock.patch('ironic.drivers.modules.deploy_utils.get_ironic_api_url')
|
|
def test_validate_invalid_root_device_hints(self, mock_get_url):
|
|
mock_get_url.return_value = 'http://spam.ham/baremetal'
|
|
with task_manager.acquire(self.context, self.node.uuid,
|
|
shared=True) as task:
|
|
task.node.properties['root_device'] = {'size': 'not-int'}
|
|
self.assertRaises(exception.InvalidParameterValue,
|
|
iscsi_deploy.validate, task)
|
|
|
|
|
|
class ISCSIDeployTestCase(db_base.DbTestCase):
|
|
|
|
def setUp(self):
|
|
super(ISCSIDeployTestCase, self).setUp()
|
|
mgr_utils.mock_the_extension_manager(driver="fake_pxe")
|
|
self.driver = driver_factory.get_driver("fake_pxe")
|
|
# NOTE(TheJulia): We explicitly set the noop storage interface as the
|
|
# default below for deployment tests in order to raise any change
|
|
# in the default which could be a breaking behavior change
|
|
# as the storage interface is explicitly an "opt-in" interface.
|
|
self.node = obj_utils.create_test_node(
|
|
self.context, driver='fake_pxe',
|
|
instance_info=INST_INFO_DICT,
|
|
driver_info=DRV_INFO_DICT,
|
|
driver_internal_info=DRV_INTERNAL_INFO_DICT,
|
|
storage_interface='noop',
|
|
)
|
|
self.node.driver_internal_info['agent_url'] = 'http://1.2.3.4:1234'
|
|
dhcp_factory.DHCPFactory._dhcp_provider = None
|
|
|
|
def test_get_properties(self):
|
|
with task_manager.acquire(self.context, self.node.uuid,
|
|
shared=True) as task:
|
|
props = task.driver.deploy.get_properties()
|
|
self.assertEqual(['deploy_forces_oob_reboot'], list(props))
|
|
|
|
@mock.patch.object(iscsi_deploy, 'validate', autospec=True)
|
|
@mock.patch.object(deploy_utils, 'validate_capabilities', autospec=True)
|
|
@mock.patch.object(pxe.PXEBoot, 'validate', autospec=True)
|
|
def test_validate(self, pxe_validate_mock,
|
|
validate_capabilities_mock, validate_mock):
|
|
with task_manager.acquire(self.context, self.node.uuid,
|
|
shared=True) as task:
|
|
|
|
task.driver.deploy.validate(task)
|
|
|
|
pxe_validate_mock.assert_called_once_with(task.driver.boot, task)
|
|
validate_capabilities_mock.assert_called_once_with(task.node)
|
|
validate_mock.assert_called_once_with(task)
|
|
|
|
@mock.patch.object(noop_storage.NoopStorage, 'should_write_image',
|
|
autospec=True)
|
|
@mock.patch.object(iscsi_deploy, 'validate', autospec=True)
|
|
@mock.patch.object(deploy_utils, 'validate_capabilities', autospec=True)
|
|
@mock.patch.object(pxe.PXEBoot, 'validate', autospec=True)
|
|
def test_validate_storage_should_write_image_false(
|
|
self, pxe_validate_mock,
|
|
validate_capabilities_mock, validate_mock,
|
|
should_write_image_mock):
|
|
should_write_image_mock.return_value = False
|
|
with task_manager.acquire(self.context, self.node.uuid,
|
|
shared=True) as task:
|
|
|
|
task.driver.deploy.validate(task)
|
|
|
|
pxe_validate_mock.assert_called_once_with(task.driver.boot, task)
|
|
validate_capabilities_mock.assert_called_once_with(task.node)
|
|
self.assertFalse(validate_mock.called)
|
|
should_write_image_mock.assert_called_once_with(
|
|
task.driver.storage, task)
|
|
|
|
@mock.patch.object(noop_storage.NoopStorage, 'attach_volumes',
|
|
autospec=True)
|
|
@mock.patch.object(deploy_utils, 'populate_storage_driver_internal_info',
|
|
autospec=True)
|
|
@mock.patch.object(flat_network.FlatNetwork, 'add_provisioning_network',
|
|
spec_set=True, autospec=True)
|
|
@mock.patch.object(pxe.PXEBoot, 'prepare_instance', autospec=True)
|
|
def test_prepare_node_active(self, prepare_instance_mock,
|
|
add_provisioning_net_mock,
|
|
storage_driver_info_mock,
|
|
storage_attach_volumes_mock):
|
|
with task_manager.acquire(self.context, self.node.uuid) as task:
|
|
task.node.provision_state = states.ACTIVE
|
|
|
|
task.driver.deploy.prepare(task)
|
|
|
|
prepare_instance_mock.assert_called_once_with(
|
|
task.driver.boot, task)
|
|
self.assertEqual(0, add_provisioning_net_mock.call_count)
|
|
storage_driver_info_mock.assert_called_once_with(task)
|
|
self.assertFalse(storage_attach_volumes_mock.called)
|
|
|
|
@mock.patch.object(flat_network.FlatNetwork, 'add_provisioning_network',
|
|
spec_set=True, autospec=True)
|
|
@mock.patch.object(pxe.PXEBoot, 'prepare_instance', autospec=True)
|
|
def test_prepare_node_adopting(self, prepare_instance_mock,
|
|
add_provisioning_net_mock):
|
|
with task_manager.acquire(self.context, self.node.uuid) as task:
|
|
task.node.provision_state = states.ADOPTING
|
|
|
|
task.driver.deploy.prepare(task)
|
|
|
|
prepare_instance_mock.assert_called_once_with(
|
|
task.driver.boot, task)
|
|
self.assertEqual(0, add_provisioning_net_mock.call_count)
|
|
|
|
@mock.patch.object(noop_storage.NoopStorage, 'attach_volumes',
|
|
autospec=True)
|
|
@mock.patch.object(deploy_utils, 'populate_storage_driver_internal_info',
|
|
autospec=True)
|
|
@mock.patch.object(deploy_utils, 'build_agent_options', autospec=True)
|
|
@mock.patch.object(pxe.PXEBoot, 'prepare_ramdisk', autospec=True)
|
|
@mock.patch.object(flat_network.FlatNetwork, 'add_provisioning_network',
|
|
spec_set=True, autospec=True)
|
|
@mock.patch.object(flat_network.FlatNetwork,
|
|
'unconfigure_tenant_networks',
|
|
spec_set=True, autospec=True)
|
|
def test_prepare_node_deploying(
|
|
self, unconfigure_tenant_net_mock, add_provisioning_net_mock,
|
|
mock_prepare_ramdisk, mock_agent_options,
|
|
storage_driver_info_mock, storage_attach_volumes_mock):
|
|
mock_agent_options.return_value = {'c': 'd'}
|
|
with task_manager.acquire(self.context, self.node.uuid) as task:
|
|
task.node.provision_state = states.DEPLOYING
|
|
|
|
task.driver.deploy.prepare(task)
|
|
|
|
mock_agent_options.assert_called_once_with(task.node)
|
|
mock_prepare_ramdisk.assert_called_once_with(
|
|
task.driver.boot, task, {'c': 'd'})
|
|
add_provisioning_net_mock.assert_called_once_with(mock.ANY, task)
|
|
unconfigure_tenant_net_mock.assert_called_once_with(mock.ANY, task)
|
|
storage_driver_info_mock.assert_called_once_with(task)
|
|
storage_attach_volumes_mock.assert_called_once_with(
|
|
task.driver.storage, task)
|
|
|
|
@mock.patch.object(noop_storage.NoopStorage, 'should_write_image',
|
|
autospec=True)
|
|
@mock.patch.object(noop_storage.NoopStorage, 'attach_volumes',
|
|
autospec=True)
|
|
@mock.patch.object(deploy_utils, 'populate_storage_driver_internal_info',
|
|
autospec=True)
|
|
@mock.patch.object(deploy_utils, 'build_agent_options', autospec=True)
|
|
@mock.patch.object(pxe.PXEBoot, 'prepare_ramdisk', autospec=True)
|
|
@mock.patch.object(flat_network.FlatNetwork, 'add_provisioning_network',
|
|
spec_set=True, autospec=True)
|
|
@mock.patch.object(flat_network.FlatNetwork,
|
|
'unconfigure_tenant_networks',
|
|
spec_set=True, autospec=True)
|
|
def test_prepare_node_deploying_storage_should_write_false(
|
|
self, unconfigure_tenant_net_mock, add_provisioning_net_mock,
|
|
mock_prepare_ramdisk, mock_agent_options,
|
|
storage_driver_info_mock, storage_attach_volumes_mock,
|
|
storage_should_write_mock):
|
|
storage_should_write_mock.return_value = False
|
|
mock_agent_options.return_value = {'c': 'd'}
|
|
with task_manager.acquire(self.context, self.node.uuid) as task:
|
|
task.node.provision_state = states.DEPLOYING
|
|
|
|
task.driver.deploy.prepare(task)
|
|
|
|
mock_agent_options.assert_called_once_with(task.node)
|
|
mock_prepare_ramdisk.assert_called_once_with(
|
|
task.driver.boot, task, {'c': 'd'})
|
|
self.assertFalse(add_provisioning_net_mock.called)
|
|
self.assertFalse(unconfigure_tenant_net_mock.called)
|
|
storage_driver_info_mock.assert_called_once_with(task)
|
|
storage_attach_volumes_mock.assert_called_once_with(
|
|
task.driver.storage, task)
|
|
self.assertEqual(1, storage_should_write_mock.call_count)
|
|
|
|
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
|
|
@mock.patch.object(iscsi_deploy, 'check_image_size', autospec=True)
|
|
@mock.patch.object(iscsi_deploy, 'cache_instance_image', autospec=True)
|
|
def test_deploy(self, mock_cache_instance_image,
|
|
mock_check_image_size, mock_node_power_action):
|
|
with task_manager.acquire(self.context,
|
|
self.node.uuid, shared=False) as task:
|
|
state = task.driver.deploy.deploy(task)
|
|
self.assertEqual(state, states.DEPLOYWAIT)
|
|
mock_cache_instance_image.assert_called_once_with(
|
|
self.context, task.node)
|
|
mock_check_image_size.assert_called_once_with(task)
|
|
mock_node_power_action.assert_called_once_with(task, states.REBOOT)
|
|
|
|
@mock.patch.object(noop_storage.NoopStorage, 'should_write_image',
|
|
autospec=True)
|
|
@mock.patch.object(flat_network.FlatNetwork,
|
|
'configure_tenant_networks',
|
|
spec_set=True, autospec=True)
|
|
@mock.patch.object(flat_network.FlatNetwork,
|
|
'remove_provisioning_network',
|
|
spec_set=True, autospec=True)
|
|
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
|
|
@mock.patch.object(iscsi_deploy, 'check_image_size', autospec=True)
|
|
@mock.patch.object(iscsi_deploy, 'cache_instance_image', autospec=True)
|
|
def test_deploy_storage_check_write_image_false(self,
|
|
mock_cache_instance_image,
|
|
mock_check_image_size,
|
|
mock_node_power_action,
|
|
mock_remove_network,
|
|
mock_tenant_network,
|
|
mock_write):
|
|
mock_write.return_value = False
|
|
self.node.provision_state = states.DEPLOYING
|
|
self.node.save()
|
|
with task_manager.acquire(self.context,
|
|
self.node.uuid, shared=False) as task:
|
|
state = task.driver.deploy.deploy(task)
|
|
self.assertEqual(state, states.DEPLOYDONE)
|
|
self.assertFalse(mock_cache_instance_image.called)
|
|
self.assertFalse(mock_check_image_size.called)
|
|
mock_remove_network.assert_called_once_with(mock.ANY, task)
|
|
mock_tenant_network.assert_called_once_with(mock.ANY, task)
|
|
self.assertEqual(2, mock_node_power_action.call_count)
|
|
|
|
@mock.patch.object(noop_storage.NoopStorage, 'detach_volumes',
|
|
autospec=True)
|
|
@mock.patch.object(flat_network.FlatNetwork,
|
|
'unconfigure_tenant_networks',
|
|
spec_set=True, autospec=True)
|
|
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
|
|
def test_tear_down(self, node_power_action_mock,
|
|
unconfigure_tenant_nets_mock,
|
|
storage_detach_volumes_mock):
|
|
obj_utils.create_test_volume_target(
|
|
self.context, node_id=self.node.id)
|
|
with task_manager.acquire(self.context,
|
|
self.node.uuid, shared=False) as task:
|
|
state = task.driver.deploy.tear_down(task)
|
|
self.assertEqual(state, states.DELETED)
|
|
node_power_action_mock.assert_called_once_with(task,
|
|
states.POWER_OFF)
|
|
unconfigure_tenant_nets_mock.assert_called_once_with(mock.ANY,
|
|
task)
|
|
storage_detach_volumes_mock.assert_called_once_with(
|
|
task.driver.storage, task)
|
|
# Verify no volumes exist for new task instances.
|
|
with task_manager.acquire(self.context,
|
|
self.node.uuid, shared=False) as task:
|
|
self.assertEqual(0, len(task.volume_targets))
|
|
|
|
@mock.patch('ironic.common.dhcp_factory.DHCPFactory._set_dhcp_provider')
|
|
@mock.patch('ironic.common.dhcp_factory.DHCPFactory.clean_dhcp')
|
|
@mock.patch.object(pxe.PXEBoot, 'clean_up_instance', autospec=True)
|
|
@mock.patch.object(pxe.PXEBoot, 'clean_up_ramdisk', autospec=True)
|
|
@mock.patch.object(iscsi_deploy, 'destroy_images', autospec=True)
|
|
def test_clean_up(self, destroy_images_mock, clean_up_ramdisk_mock,
|
|
clean_up_instance_mock, clean_dhcp_mock,
|
|
set_dhcp_provider_mock):
|
|
with task_manager.acquire(self.context,
|
|
self.node.uuid, shared=False) as task:
|
|
task.driver.deploy.clean_up(task)
|
|
destroy_images_mock.assert_called_once_with(task.node.uuid)
|
|
clean_up_ramdisk_mock.assert_called_once_with(
|
|
task.driver.boot, task)
|
|
clean_up_instance_mock.assert_called_once_with(
|
|
task.driver.boot, task)
|
|
set_dhcp_provider_mock.assert_called_once_with()
|
|
clean_dhcp_mock.assert_called_once_with(task)
|
|
|
|
@mock.patch.object(deploy_utils, 'prepare_inband_cleaning', autospec=True)
|
|
def test_prepare_cleaning(self, prepare_inband_cleaning_mock):
|
|
prepare_inband_cleaning_mock.return_value = states.CLEANWAIT
|
|
with task_manager.acquire(self.context, self.node.uuid) as task:
|
|
self.assertEqual(
|
|
states.CLEANWAIT, task.driver.deploy.prepare_cleaning(task))
|
|
prepare_inband_cleaning_mock.assert_called_once_with(
|
|
task, manage_boot=True)
|
|
|
|
@mock.patch.object(deploy_utils, 'tear_down_inband_cleaning',
|
|
autospec=True)
|
|
def test_tear_down_cleaning(self, tear_down_cleaning_mock):
|
|
with task_manager.acquire(self.context, self.node.uuid) as task:
|
|
task.driver.deploy.tear_down_cleaning(task)
|
|
tear_down_cleaning_mock.assert_called_once_with(
|
|
task, manage_boot=True)
|
|
|
|
@mock.patch('ironic.drivers.modules.deploy_utils.agent_get_clean_steps',
|
|
autospec=True)
|
|
def test_get_clean_steps(self, mock_get_clean_steps):
|
|
# Test getting clean steps
|
|
self.config(group='deploy', erase_devices_priority=10)
|
|
self.config(group='deploy', erase_devices_metadata_priority=5)
|
|
mock_steps = [{'priority': 10, 'interface': 'deploy',
|
|
'step': 'erase_devices'}]
|
|
self.node.driver_internal_info = {'agent_url': 'foo'}
|
|
self.node.save()
|
|
mock_get_clean_steps.return_value = mock_steps
|
|
with task_manager.acquire(self.context, self.node.uuid) as task:
|
|
steps = task.driver.deploy.get_clean_steps(task)
|
|
mock_get_clean_steps.assert_called_once_with(
|
|
task, interface='deploy',
|
|
override_priorities={
|
|
'erase_devices': 10,
|
|
'erase_devices_metadata': 5})
|
|
self.assertEqual(mock_steps, steps)
|
|
|
|
@mock.patch.object(deploy_utils, 'agent_execute_clean_step', autospec=True)
|
|
def test_execute_clean_step(self, agent_execute_clean_step_mock):
|
|
with task_manager.acquire(self.context, self.node.uuid) as task:
|
|
task.driver.deploy.execute_clean_step(
|
|
task, {'some-step': 'step-info'})
|
|
agent_execute_clean_step_mock.assert_called_once_with(
|
|
task, {'some-step': 'step-info'})
|
|
|
|
@mock.patch.object(agent_base_vendor.AgentDeployMixin,
|
|
'reboot_and_finish_deploy', autospec=True)
|
|
@mock.patch.object(iscsi_deploy, 'do_agent_iscsi_deploy', autospec=True)
|
|
def test_continue_deploy_netboot(self, do_agent_iscsi_deploy_mock,
|
|
reboot_and_finish_deploy_mock):
|
|
|
|
self.node.provision_state = states.DEPLOYWAIT
|
|
self.node.target_provision_state = states.ACTIVE
|
|
self.node.save()
|
|
uuid_dict_returned = {'root uuid': 'some-root-uuid'}
|
|
do_agent_iscsi_deploy_mock.return_value = uuid_dict_returned
|
|
with task_manager.acquire(self.context, self.node.uuid) as task:
|
|
with mock.patch.object(
|
|
task.driver.boot, 'prepare_instance') as m_prep_instance:
|
|
task.driver.deploy.continue_deploy(task)
|
|
do_agent_iscsi_deploy_mock.assert_called_once_with(
|
|
task, task.driver.deploy._client)
|
|
reboot_and_finish_deploy_mock.assert_called_once_with(
|
|
mock.ANY, task)
|
|
m_prep_instance.assert_called_once_with(task)
|
|
|
|
@mock.patch.object(agent_base_vendor.AgentDeployMixin,
|
|
'reboot_and_finish_deploy', autospec=True)
|
|
@mock.patch.object(agent_base_vendor.AgentDeployMixin,
|
|
'configure_local_boot', autospec=True)
|
|
@mock.patch.object(iscsi_deploy, 'do_agent_iscsi_deploy', autospec=True)
|
|
def test_continue_deploy_localboot(self, do_agent_iscsi_deploy_mock,
|
|
configure_local_boot_mock,
|
|
reboot_and_finish_deploy_mock):
|
|
|
|
self.node.instance_info = {
|
|
'capabilities': {'boot_option': 'local'}}
|
|
self.node.provision_state = states.DEPLOYWAIT
|
|
self.node.target_provision_state = states.ACTIVE
|
|
self.node.save()
|
|
uuid_dict_returned = {'root uuid': 'some-root-uuid'}
|
|
do_agent_iscsi_deploy_mock.return_value = uuid_dict_returned
|
|
|
|
with task_manager.acquire(self.context, self.node.uuid) as task:
|
|
task.driver.deploy.continue_deploy(task)
|
|
do_agent_iscsi_deploy_mock.assert_called_once_with(
|
|
task, task.driver.deploy._client)
|
|
configure_local_boot_mock.assert_called_once_with(
|
|
task.driver.deploy, task, root_uuid='some-root-uuid',
|
|
efi_system_part_uuid=None)
|
|
reboot_and_finish_deploy_mock.assert_called_once_with(
|
|
task.driver.deploy, task)
|
|
|
|
@mock.patch.object(agent_base_vendor.AgentDeployMixin,
|
|
'reboot_and_finish_deploy', autospec=True)
|
|
@mock.patch.object(agent_base_vendor.AgentDeployMixin,
|
|
'configure_local_boot', autospec=True)
|
|
@mock.patch.object(iscsi_deploy, 'do_agent_iscsi_deploy', autospec=True)
|
|
def test_continue_deploy_localboot_uefi(self, do_agent_iscsi_deploy_mock,
|
|
configure_local_boot_mock,
|
|
reboot_and_finish_deploy_mock):
|
|
|
|
self.node.instance_info = {
|
|
'capabilities': {'boot_option': 'local'}}
|
|
self.node.provision_state = states.DEPLOYWAIT
|
|
self.node.target_provision_state = states.ACTIVE
|
|
self.node.save()
|
|
uuid_dict_returned = {'root uuid': 'some-root-uuid',
|
|
'efi system partition uuid': 'efi-part-uuid'}
|
|
do_agent_iscsi_deploy_mock.return_value = uuid_dict_returned
|
|
|
|
with task_manager.acquire(self.context, self.node.uuid) as task:
|
|
task.driver.deploy.continue_deploy(task)
|
|
do_agent_iscsi_deploy_mock.assert_called_once_with(
|
|
task, task.driver.deploy._client)
|
|
configure_local_boot_mock.assert_called_once_with(
|
|
task.driver.deploy, task, root_uuid='some-root-uuid',
|
|
efi_system_part_uuid='efi-part-uuid')
|
|
reboot_and_finish_deploy_mock.assert_called_once_with(
|
|
task.driver.deploy, task)
|
|
|
|
|
|
# Cleanup of iscsi_deploy with pxe boot interface
|
|
class CleanUpFullFlowTestCase(db_base.DbTestCase):
|
|
def setUp(self):
|
|
super(CleanUpFullFlowTestCase, self).setUp()
|
|
self.config(image_cache_size=0, group='pxe')
|
|
|
|
# Configure node
|
|
mgr_utils.mock_the_extension_manager(driver="fake_pxe")
|
|
instance_info = INST_INFO_DICT
|
|
instance_info['deploy_key'] = 'fake-56789'
|
|
self.node = obj_utils.create_test_node(
|
|
self.context, driver='fake_pxe',
|
|
instance_info=instance_info,
|
|
driver_info=DRV_INFO_DICT,
|
|
driver_internal_info=DRV_INTERNAL_INFO_DICT,
|
|
)
|
|
self.port = obj_utils.create_test_port(self.context,
|
|
node_id=self.node.id)
|
|
|
|
# Configure temporary directories
|
|
pxe_temp_dir = tempfile.mkdtemp()
|
|
self.config(tftp_root=pxe_temp_dir, group='pxe')
|
|
tftp_master_dir = os.path.join(CONF.pxe.tftp_root,
|
|
'tftp_master')
|
|
self.config(tftp_master_path=tftp_master_dir, group='pxe')
|
|
os.makedirs(tftp_master_dir)
|
|
|
|
instance_temp_dir = tempfile.mkdtemp()
|
|
self.config(images_path=instance_temp_dir,
|
|
group='pxe')
|
|
instance_master_dir = os.path.join(CONF.pxe.images_path,
|
|
'instance_master')
|
|
self.config(instance_master_path=instance_master_dir,
|
|
group='pxe')
|
|
os.makedirs(instance_master_dir)
|
|
self.pxe_config_dir = os.path.join(CONF.pxe.tftp_root, 'pxelinux.cfg')
|
|
os.makedirs(self.pxe_config_dir)
|
|
|
|
# Populate some file names
|
|
self.master_kernel_path = os.path.join(CONF.pxe.tftp_master_path,
|
|
'kernel')
|
|
self.master_instance_path = os.path.join(CONF.pxe.instance_master_path,
|
|
'image_uuid')
|
|
self.node_tftp_dir = os.path.join(CONF.pxe.tftp_root,
|
|
self.node.uuid)
|
|
os.makedirs(self.node_tftp_dir)
|
|
self.kernel_path = os.path.join(self.node_tftp_dir,
|
|
'kernel')
|
|
self.node_image_dir = iscsi_deploy._get_image_dir_path(self.node.uuid)
|
|
os.makedirs(self.node_image_dir)
|
|
self.image_path = iscsi_deploy._get_image_file_path(self.node.uuid)
|
|
self.config_path = pxe_utils.get_pxe_config_file_path(self.node.uuid)
|
|
self.mac_path = pxe_utils._get_pxe_mac_path(self.port.address)
|
|
|
|
# Create files
|
|
self.files = [self.config_path, self.master_kernel_path,
|
|
self.master_instance_path]
|
|
for fname in self.files:
|
|
# NOTE(dtantsur): files with 0 size won't be cleaned up
|
|
with open(fname, 'w') as fp:
|
|
fp.write('test')
|
|
|
|
os.link(self.config_path, self.mac_path)
|
|
os.link(self.master_kernel_path, self.kernel_path)
|
|
os.link(self.master_instance_path, self.image_path)
|
|
dhcp_factory.DHCPFactory._dhcp_provider = None
|
|
|
|
@mock.patch('ironic.common.dhcp_factory.DHCPFactory._set_dhcp_provider')
|
|
@mock.patch('ironic.common.dhcp_factory.DHCPFactory.clean_dhcp')
|
|
@mock.patch.object(pxe, '_get_instance_image_info', autospec=True)
|
|
@mock.patch.object(pxe, '_get_deploy_image_info', autospec=True)
|
|
def test_clean_up_with_master(self, mock_get_deploy_image_info,
|
|
mock_get_instance_image_info,
|
|
clean_dhcp_mock, set_dhcp_provider_mock):
|
|
image_info = {'kernel': ('kernel_uuid',
|
|
self.kernel_path)}
|
|
mock_get_instance_image_info.return_value = image_info
|
|
mock_get_deploy_image_info.return_value = {}
|
|
|
|
with task_manager.acquire(self.context, self.node.uuid,
|
|
shared=True) as task:
|
|
task.driver.deploy.clean_up(task)
|
|
mock_get_instance_image_info.assert_called_with(task.node,
|
|
task.context)
|
|
mock_get_deploy_image_info.assert_called_with(task.node)
|
|
set_dhcp_provider_mock.assert_called_once_with()
|
|
clean_dhcp_mock.assert_called_once_with(task)
|
|
for path in ([self.kernel_path, self.image_path, self.config_path]
|
|
+ self.files):
|
|
self.assertFalse(os.path.exists(path),
|
|
'%s is not expected to exist' % path)
|