Merge "iscsi_ilo driver to support agent ramdisk"
This commit is contained in:
@@ -28,12 +28,14 @@ from ironic.common.i18n import _LE
|
||||
from ironic.common.i18n import _LI
|
||||
from ironic.common import image_service
|
||||
from ironic.common import images
|
||||
from ironic.common import keystone
|
||||
from ironic.common import states
|
||||
from ironic.common import swift
|
||||
from ironic.conductor import task_manager
|
||||
from ironic.conductor import utils as manager_utils
|
||||
from ironic.drivers import base
|
||||
from ironic.drivers.modules import agent
|
||||
from ironic.drivers.modules import agent_base_vendor
|
||||
from ironic.drivers.modules import deploy_utils
|
||||
from ironic.drivers.modules.ilo import common as ilo_common
|
||||
from ironic.drivers.modules import ipmitool
|
||||
@@ -309,6 +311,8 @@ class IloVirtualMediaIscsiDeploy(base.DeployInterface):
|
||||
iscsi_deploy.check_image_size(task)
|
||||
|
||||
deploy_ramdisk_opts = iscsi_deploy.build_deploy_ramdisk_options(node)
|
||||
agent_opts = agent.build_agent_options(node)
|
||||
deploy_ramdisk_opts.update(agent_opts)
|
||||
deploy_nic_mac = deploy_utils.get_single_nic_with_vif_port_id(task)
|
||||
deploy_ramdisk_opts['BOOTIF'] = deploy_nic_mac
|
||||
deploy_iso = node.driver_info['ilo_deploy_iso']
|
||||
@@ -498,7 +502,7 @@ class IloPXEVendorPassthru(pxe.VendorPassthru):
|
||||
super(IloPXEVendorPassthru, self)._continue_deploy(task, **kwargs)
|
||||
|
||||
|
||||
class VendorPassthru(base.VendorInterface):
|
||||
class VendorPassthru(agent_base_vendor.BaseAgentVendor):
|
||||
"""Vendor-specific interfaces for iLO deploy drivers."""
|
||||
|
||||
def get_properties(self):
|
||||
@@ -519,7 +523,24 @@ class VendorPassthru(base.VendorInterface):
|
||||
:raises: InvalidParameterValue, if any of the parameters have invalid
|
||||
value.
|
||||
"""
|
||||
iscsi_deploy.get_deploy_info(task.node, **kwargs)
|
||||
if method == 'pass_deploy_info':
|
||||
iscsi_deploy.get_deploy_info(task.node, **kwargs)
|
||||
|
||||
def _configure_vmedia_boot(self, task, root_uuid):
|
||||
"""Configure vmedia boot for the node."""
|
||||
node = task.node
|
||||
boot_iso = _get_boot_iso(task, root_uuid)
|
||||
if not boot_iso:
|
||||
LOG.error(_LE("Cannot get boot ISO for node %s"), node.uuid)
|
||||
return
|
||||
|
||||
ilo_common.setup_vmedia_for_boot(task, boot_iso)
|
||||
manager_utils.node_set_boot_device(task, boot_devices.CDROM)
|
||||
|
||||
i_info = node.instance_info
|
||||
if not i_info.get('ilo_boot_iso'):
|
||||
i_info['ilo_boot_iso'] = boot_iso
|
||||
node.instance_info = i_info
|
||||
|
||||
@base.passthru(['POST'], method='pass_deploy_info')
|
||||
@task_manager.require_exclusive_lock
|
||||
@@ -558,19 +579,7 @@ class VendorPassthru(base.VendorInterface):
|
||||
manager_utils.node_set_boot_device(task, boot_devices.DISK,
|
||||
persistent=True)
|
||||
else:
|
||||
boot_iso = _get_boot_iso(task, root_uuid_or_disk_id)
|
||||
if not boot_iso:
|
||||
LOG.error(_LE("Cannot get boot ISO for node %s"),
|
||||
node.uuid)
|
||||
return
|
||||
|
||||
ilo_common.setup_vmedia_for_boot(task, boot_iso)
|
||||
manager_utils.node_set_boot_device(task, boot_devices.CDROM)
|
||||
|
||||
i_info = node.instance_info
|
||||
if not i_info.get('ilo_boot_iso'):
|
||||
i_info['ilo_boot_iso'] = boot_iso
|
||||
node.instance_info = i_info
|
||||
self._configure_vmedia_boot(task, root_uuid_or_disk_id)
|
||||
|
||||
deploy_utils.notify_deploy_complete(kwargs.get('address'))
|
||||
|
||||
@@ -582,3 +591,35 @@ class VendorPassthru(base.VendorInterface):
|
||||
{'instance': node.instance_uuid, 'error': e})
|
||||
msg = _('Failed to continue iSCSI deployment.')
|
||||
deploy_utils.set_failed_state(task, msg)
|
||||
|
||||
@task_manager.require_exclusive_lock
|
||||
def continue_deploy(self, task, **kwargs):
|
||||
"""Method invoked when deployed with the IPA ramdisk.
|
||||
|
||||
This method is invoked during a heartbeat from an agent when
|
||||
the node is in wait-call-back state. This deploys the image on
|
||||
the node and then configures the node to boot according to the
|
||||
desired boot option (netboot or localboot).
|
||||
|
||||
:param task: a TaskManager object containing the node.
|
||||
:param kwargs: the kwargs passed from the heartbeat method.
|
||||
:raises: InstanceDeployFailure, if it encounters some error during
|
||||
the deploy.
|
||||
"""
|
||||
task.process_event('resume')
|
||||
node = task.node
|
||||
LOG.debug('Continuing the deployment on node %s', node.uuid)
|
||||
|
||||
ilo_common.cleanup_vmedia_boot(task)
|
||||
|
||||
root_uuid = iscsi_deploy.do_agent_iscsi_deploy(task, self._client)
|
||||
|
||||
if iscsi_deploy.get_boot_option(node) == "local":
|
||||
self.configure_local_boot(task, root_uuid)
|
||||
else:
|
||||
# Agent vendorpassthru are made without auth token.
|
||||
# We require auth_token to talk to glance while building boot iso.
|
||||
task.context.auth_token = keystone.get_admin_auth_token()
|
||||
self._configure_vmedia_boot(task, root_uuid)
|
||||
|
||||
self.reboot_and_finish_deploy(task)
|
||||
|
||||
@@ -25,11 +25,13 @@ from ironic.common import exception
|
||||
from ironic.common.glance_service import service_utils
|
||||
from ironic.common import image_service
|
||||
from ironic.common import images
|
||||
from ironic.common import keystone
|
||||
from ironic.common import states
|
||||
from ironic.common import swift
|
||||
from ironic.conductor import task_manager
|
||||
from ironic.conductor import utils as manager_utils
|
||||
from ironic.drivers.modules import agent
|
||||
from ironic.drivers.modules import agent_base_vendor
|
||||
from ironic.drivers.modules import deploy_utils
|
||||
from ironic.drivers.modules.ilo import common as ilo_common
|
||||
from ironic.drivers.modules.ilo import deploy as ilo_deploy
|
||||
@@ -284,14 +286,17 @@ class IloVirtualMediaIscsiDeployTestCase(db_base.DbTestCase):
|
||||
|
||||
@mock.patch.object(ilo_deploy, '_reboot_into')
|
||||
@mock.patch.object(deploy_utils, 'get_single_nic_with_vif_port_id')
|
||||
@mock.patch.object(agent, 'build_agent_options')
|
||||
@mock.patch.object(iscsi_deploy, 'build_deploy_ramdisk_options')
|
||||
@mock.patch.object(manager_utils, 'node_power_action')
|
||||
@mock.patch.object(iscsi_deploy, 'check_image_size')
|
||||
@mock.patch.object(iscsi_deploy, 'cache_instance_image')
|
||||
def test_deploy(self, cache_instance_image_mock, check_image_size_mock,
|
||||
node_power_action_mock, build_opts_mock, get_nic_mock,
|
||||
reboot_into_mock):
|
||||
node_power_action_mock, build_opts_mock,
|
||||
agent_options_mock, get_nic_mock, reboot_into_mock):
|
||||
deploy_opts = {'a': 'b'}
|
||||
agent_options_mock.return_value = {
|
||||
'ipa-api-url': 'http://1.2.3.4:6385'}
|
||||
build_opts_mock.return_value = deploy_opts
|
||||
get_nic_mock.return_value = '12:34:56:78:90:ab'
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
@@ -304,7 +309,8 @@ class IloVirtualMediaIscsiDeployTestCase(db_base.DbTestCase):
|
||||
cache_instance_image_mock.assert_called_once_with(task.context,
|
||||
task.node)
|
||||
check_image_size_mock.assert_called_once_with(task)
|
||||
expected_ramdisk_opts = {'a': 'b', 'BOOTIF': '12:34:56:78:90:ab'}
|
||||
expected_ramdisk_opts = {'a': 'b', 'BOOTIF': '12:34:56:78:90:ab',
|
||||
'ipa-api-url': 'http://1.2.3.4:6385'}
|
||||
build_opts_mock.assert_called_once_with(task.node)
|
||||
get_nic_mock.assert_called_once_with(task)
|
||||
reboot_into_mock.assert_called_once_with(task, 'deploy-iso',
|
||||
@@ -391,6 +397,23 @@ class VendorPassthruTestCase(db_base.DbTestCase):
|
||||
driver='iscsi_ilo',
|
||||
driver_info=INFO_DICT)
|
||||
|
||||
@mock.patch.object(iscsi_deploy, 'get_deploy_info')
|
||||
def test_validate_pass_deploy_info(self, get_deploy_info_mock):
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=False) as task:
|
||||
vendor = ilo_deploy.VendorPassthru()
|
||||
vendor.validate(task, method='pass_deploy_info', foo='bar')
|
||||
get_deploy_info_mock.assert_called_once_with(task.node,
|
||||
foo='bar')
|
||||
|
||||
@mock.patch.object(iscsi_deploy, 'get_deploy_info')
|
||||
def test_validate_heartbeat(self, get_deploy_info_mock):
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=False) as task:
|
||||
vendor = ilo_deploy.VendorPassthru()
|
||||
vendor.validate(task, method='heartbeat', foo='bar')
|
||||
self.assertFalse(get_deploy_info_mock.called)
|
||||
|
||||
@mock.patch.object(deploy_utils, 'notify_deploy_complete')
|
||||
@mock.patch.object(manager_utils, 'node_set_boot_device')
|
||||
@mock.patch.object(ilo_common, 'setup_vmedia_for_boot')
|
||||
@@ -559,6 +582,60 @@ class VendorPassthruTestCase(db_base.DbTestCase):
|
||||
self.node.save()
|
||||
self._test__continue_deploy_localboot()
|
||||
|
||||
@mock.patch.object(keystone, 'get_admin_auth_token')
|
||||
@mock.patch.object(agent_base_vendor.BaseAgentVendor,
|
||||
'reboot_and_finish_deploy')
|
||||
@mock.patch.object(ilo_deploy.VendorPassthru, '_configure_vmedia_boot')
|
||||
@mock.patch.object(iscsi_deploy, 'do_agent_iscsi_deploy')
|
||||
@mock.patch.object(ilo_common, 'cleanup_vmedia_boot')
|
||||
def test_continue_deploy_netboot(self, cleanup_vmedia_boot_mock,
|
||||
do_agent_iscsi_deploy_mock,
|
||||
configure_vmedia_boot_mock,
|
||||
reboot_and_finish_deploy_mock,
|
||||
keystone_mock):
|
||||
self.node.provision_state = states.DEPLOYWAIT
|
||||
self.node.target_provision_state = states.DEPLOYING
|
||||
self.node.save()
|
||||
do_agent_iscsi_deploy_mock.return_value = 'some-root-uuid'
|
||||
keystone_mock.return_value = 'admin-token'
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=False) as task:
|
||||
task.driver.vendor.continue_deploy(task)
|
||||
cleanup_vmedia_boot_mock.assert_called_once_with(task)
|
||||
do_agent_iscsi_deploy_mock.assert_called_once_with(task,
|
||||
mock.ANY)
|
||||
configure_vmedia_boot_mock.assert_called_once_with(
|
||||
task, 'some-root-uuid')
|
||||
reboot_and_finish_deploy_mock.assert_called_once_with(task)
|
||||
# Ensure that admin token is populated in task
|
||||
self.assertEqual('admin-token', task.context.auth_token)
|
||||
|
||||
@mock.patch.object(agent_base_vendor.BaseAgentVendor,
|
||||
'reboot_and_finish_deploy')
|
||||
@mock.patch.object(agent_base_vendor.BaseAgentVendor,
|
||||
'configure_local_boot')
|
||||
@mock.patch.object(iscsi_deploy, 'do_agent_iscsi_deploy')
|
||||
@mock.patch.object(ilo_common, 'cleanup_vmedia_boot')
|
||||
def test_continue_deploy_localboot(self, cleanup_vmedia_boot_mock,
|
||||
do_agent_iscsi_deploy_mock,
|
||||
configure_local_boot_mock,
|
||||
reboot_and_finish_deploy_mock):
|
||||
self.node.provision_state = states.DEPLOYWAIT
|
||||
self.node.target_provision_state = states.DEPLOYING
|
||||
self.node.instance_info = {
|
||||
'capabilities': {'boot_option': 'local'}}
|
||||
self.node.save()
|
||||
do_agent_iscsi_deploy_mock.return_value = 'some-root-uuid'
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=False) as task:
|
||||
task.driver.vendor.continue_deploy(task)
|
||||
cleanup_vmedia_boot_mock.assert_called_once_with(task)
|
||||
do_agent_iscsi_deploy_mock.assert_called_once_with(task,
|
||||
mock.ANY)
|
||||
configure_local_boot_mock.assert_called_once_with(
|
||||
task, 'some-root-uuid')
|
||||
reboot_and_finish_deploy_mock.assert_called_once_with(task)
|
||||
|
||||
|
||||
class IloPXEDeployTestCase(db_base.DbTestCase):
|
||||
|
||||
|
||||
Reference in New Issue
Block a user