Merge "iscsi_ilo driver to support agent ramdisk"

This commit is contained in:
Jenkins
2015-03-16 18:31:45 +00:00
committed by Gerrit Code Review
2 changed files with 136 additions and 18 deletions

View File

@@ -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)

View File

@@ -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):