summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2014-09-04 15:15:31 +0000
committerGerrit Code Review <review@openstack.org>2014-09-04 15:15:31 +0000
commit21e12485d392bc5cc67d459faaffb500ee54d715 (patch)
tree6864a833960542f740bd78265cbb6fd2e68673a1
parent2358549d69db38f67d819a49e1e7cd9bc60bc71e (diff)
parent5894ff356ec788c8ed93e53f656dc7353148c444 (diff)
downloadironic-2014.2.b3.tar.gz
Merge "IloVirtualMediaAgent deploy driver"2014.2.b3
-rw-r--r--ironic/drivers/ilo.py24
-rw-r--r--ironic/drivers/modules/agent.py38
-rw-r--r--ironic/drivers/modules/agent_config.template2
-rw-r--r--ironic/drivers/modules/ilo/deploy.py76
-rw-r--r--ironic/tests/conductor/test_manager.py10
-rw-r--r--ironic/tests/drivers/agent_pxe_config.template2
-rw-r--r--ironic/tests/drivers/ilo/test_deploy.py54
-rw-r--r--ironic/tests/drivers/test_agent.py19
-rw-r--r--setup.cfg1
9 files changed, 219 insertions, 7 deletions
diff --git a/ironic/drivers/ilo.py b/ironic/drivers/ilo.py
index ff24c634f..3889bb147 100644
--- a/ironic/drivers/ilo.py
+++ b/ironic/drivers/ilo.py
@@ -20,6 +20,7 @@ from oslo.utils import importutils
from ironic.common import exception
from ironic.common.i18n import _
from ironic.drivers import base
+from ironic.drivers.modules import agent
from ironic.drivers.modules.ilo import deploy
from ironic.drivers.modules.ilo import power
from ironic.drivers.modules import ipmitool
@@ -46,3 +47,26 @@ class IloVirtualMediaIscsiDriver(base.BaseDriver):
self.console = ipmitool.IPMIShellinaboxConsole()
self.management = ipmitool.IPMIManagement()
self.vendor = deploy.VendorPassthru()
+
+
+class IloVirtualMediaAgentDriver(base.BaseDriver):
+ """IloDriver using IloClient interface.
+
+ This driver implements the `core` functionality using
+ :class:ironic.drivers.modules.ilo.power.IloPower for power management
+ and
+ :class:ironic.drivers.modules.ilo.deploy.IloVirtualMediaAgentDriver for
+ deploy.
+ """
+
+ def __init__(self):
+ if not importutils.try_import('proliantutils'):
+ raise exception.DriverLoadError(
+ driver=self.__class__.__name__,
+ reason=_("Unable to import proliantutils library"))
+
+ self.power = power.IloPower()
+ self.deploy = deploy.IloVirtualMediaAgentDeploy()
+ self.console = ipmitool.IPMIShellinaboxConsole()
+ self.management = ipmitool.IPMIManagement()
+ self.vendor = agent.AgentVendorInterface()
diff --git a/ironic/drivers/modules/agent.py b/ironic/drivers/modules/agent.py
index 08cfdfd80..2ba5740b1 100644
--- a/ironic/drivers/modules/agent.py
+++ b/ironic/drivers/modules/agent.py
@@ -74,15 +74,38 @@ def _get_client():
return client
-def _build_pxe_config_options(pxe_info):
+def build_agent_options():
+ """Build the options to be passed to the agent ramdisk.
+
+ :returns: a dictionary containing the parameters to be passed to
+ agent ramdisk.
+ """
ironic_api = (CONF.conductor.api_url or
keystone.get_service_url()).rstrip('/')
return {
+ 'ipa-api-url': ironic_api,
+ }
+
+
+def _build_pxe_config_options(pxe_info):
+ """Builds the pxe config options for booting agent.
+
+ This method builds the config options to be replaced on
+ the agent pxe config template.
+
+ :param pxe_info: A dict containing the 'deploy_kernel' and
+ 'deploy_ramdisk' for the agent pxe config template.
+ :returns: a dict containing the options to be applied on
+ the agent pxe config template.
+ """
+ agent_config_opts = {
'deployment_aki_path': pxe_info['deploy_kernel'][1],
'deployment_ari_path': pxe_info['deploy_ramdisk'][1],
'pxe_append_params': CONF.agent.agent_pxe_append_params,
- 'ipa_api_url': ironic_api,
}
+ agent_opts = build_agent_options()
+ agent_config_opts.update(agent_opts)
+ return agent_config_opts
def _get_tftp_image_info(node):
@@ -162,8 +185,13 @@ def _cache_tftp_images(ctx, node, pxe_info):
_fetch_images(ctx, AgentTFTPImageCache(), pxe_info.values())
-def _build_instance_info_for_deploy(task):
- """Build instance_info necessary for deploying to a node."""
+def build_instance_info_for_deploy(task):
+ """Build instance_info necessary for deploying to a node.
+
+ :param task: a TaskManager object containing the node
+ :returns: a dictionary containing the properties to be updated
+ in instance_info
+ """
node = task.node
instance_info = node.instance_info
@@ -248,7 +276,7 @@ class AgentDeploy(base.DeployInterface):
CONF.agent.agent_pxe_config_template)
_cache_tftp_images(task.context, node, pxe_info)
- node.instance_info = _build_instance_info_for_deploy(task)
+ node.instance_info = build_instance_info_for_deploy(task)
node.save(task.context)
def clean_up(self, task):
diff --git a/ironic/drivers/modules/agent_config.template b/ironic/drivers/modules/agent_config.template
index 3f36d4e69..4f71f0dc7 100644
--- a/ironic/drivers/modules/agent_config.template
+++ b/ironic/drivers/modules/agent_config.template
@@ -2,4 +2,4 @@ default deploy
label deploy
kernel {{ pxe_options.deployment_aki_path }}
-append initrd={{ pxe_options.deployment_ari_path }} text {{ pxe_options.pxe_append_params }} {% if pxe_options.ipa_api_url %}ipa-api-url={{ pxe_options.ipa_api_url }}{% endif %} {% if pxe_options.ipa_advertise_host %}ipa-advertise-host={{ pxe_options.ipa_advertise_host }}{% endif %}
+append initrd={{ pxe_options.deployment_ari_path }} text {{ pxe_options.pxe_append_params }} {% if pxe_options.ipa-api-url %}ipa-api-url={{ pxe_options.ipa-api-url }}{% endif %} {% if pxe_options.ipa-advertise-host %}ipa-advertise-host={{ pxe_options.ipa-advertise-host }}{% endif %}
diff --git a/ironic/drivers/modules/ilo/deploy.py b/ironic/drivers/modules/ilo/deploy.py
index 67a92d2db..d77a6594b 100644
--- a/ironic/drivers/modules/ilo/deploy.py
+++ b/ironic/drivers/modules/ilo/deploy.py
@@ -28,6 +28,7 @@ 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 deploy_utils
from ironic.drivers.modules.ilo import common as ilo_common
from ironic.drivers.modules import iscsi_deploy
@@ -306,6 +307,81 @@ class IloVirtualMediaIscsiDeploy(base.DeployInterface):
pass
+class IloVirtualMediaAgentDeploy(base.DeployInterface):
+ """Interface for deploy-related actions."""
+
+ def get_properties(self):
+ """Return the properties of the interface.
+
+ :returns: dictionary of <property name>:<property description> entries.
+ """
+ return COMMON_PROPERTIES
+
+ def validate(self, task):
+ """Validate the driver-specific Node deployment info.
+
+ :param task: a TaskManager instance
+ :raises: MissingParameterValue if some parameters are missing.
+ """
+ _parse_driver_info(task.node)
+
+ @task_manager.require_exclusive_lock
+ def deploy(self, task):
+ """Perform a deployment to a node.
+
+ Prepares the options for the agent ramdisk and sets the node to boot
+ from virtual media cdrom.
+
+ :param task: a TaskManager instance.
+ :returns: states.DEPLOYWAIT
+ :raises: ImageCreationFailed, if it failed while creating the floppy
+ image.
+ :raises: IloOperationError, if some operation on iLO fails.
+ """
+ deploy_ramdisk_opts = agent.build_agent_options()
+ deploy_iso_uuid = task.node.driver_info['ilo_deploy_iso']
+ deploy_iso = 'glance:' + deploy_iso_uuid
+ _reboot_into(task, deploy_iso, deploy_ramdisk_opts)
+
+ return states.DEPLOYWAIT
+
+ @task_manager.require_exclusive_lock
+ def tear_down(self, task):
+ """Tear down a previous deployment on the task's node.
+
+ :param task: a TaskManager instance.
+ :returns: states.DELETED
+ """
+ manager_utils.node_power_action(task, states.POWER_OFF)
+ return states.DELETED
+
+ def prepare(self, task):
+ """Prepare the deployment environment for this node.
+
+ :param task: a TaskManager instance.
+ """
+ node = task.node
+ node.instance_info = agent.build_instance_info_for_deploy(task)
+ node.save(task.context)
+
+ def clean_up(self, task):
+ """Clean up the deployment environment for this node.
+
+ Ejects the attached virtual media from the iLO and also removes
+ the floppy image from Swift, if it exists.
+
+ :param task: a TaskManager instance.
+ """
+ ilo_common.cleanup_vmedia_boot(task)
+
+ def take_over(self, task):
+ """Take over management of this node from a dead conductor.
+
+ :param task: a TaskManager instance.
+ """
+ pass
+
+
class VendorPassthru(base.VendorInterface):
"""Vendor-specific interfaces for iLO deploy drivers."""
diff --git a/ironic/tests/conductor/test_manager.py b/ironic/tests/conductor/test_manager.py
index 1825e1c80..06025e53a 100644
--- a/ironic/tests/conductor/test_manager.py
+++ b/ironic/tests/conductor/test_manager.py
@@ -2269,6 +2269,16 @@ class ManagerTestProperties(tests_db_base.DbTestCase):
'ipmi_target_address', 'ipmi_local_address']
self._check_driver_properties("iscsi_ilo", expected)
+ def test_driver_properties_agent_ilo(self):
+ expected = ['ilo_address', 'ilo_username', 'ilo_password',
+ 'client_port', 'client_timeout', 'ilo_deploy_iso',
+ 'ipmi_address', 'ipmi_terminal_port',
+ 'ipmi_password', 'ipmi_priv_level',
+ 'ipmi_username', 'ipmi_bridging', 'ipmi_transit_channel',
+ 'ipmi_transit_address', 'ipmi_target_channel',
+ 'ipmi_target_address', 'ipmi_local_address']
+ self._check_driver_properties("agent_ilo", expected)
+
def test_driver_properties_fail(self):
mgr_utils.mock_the_extension_manager()
self.driver = driver_factory.get_driver("fake")
diff --git a/ironic/tests/drivers/agent_pxe_config.template b/ironic/tests/drivers/agent_pxe_config.template
index ec68da5e0..25a2321ea 100644
--- a/ironic/tests/drivers/agent_pxe_config.template
+++ b/ironic/tests/drivers/agent_pxe_config.template
@@ -2,4 +2,4 @@ default deploy
label deploy
kernel {{ pxe_options.deployment_aki_path }}
-append initrd={{ pxe_options.deployment_ari_path }} root=squashfs: {% if pxe_options.pxe_append_params %}{{ pxe_options.pxe_append_params }}{% endif %} state=tmpfs: ipa-api-url={{ pxe_options.ipa_api_url }} {% if pxe_options.ipa_advertise_host %}ipa-advertise-host={{ pxe_options.ipa_advertise_host }}{% endif %}
+append initrd={{ pxe_options.deployment_ari_path }} text root=squashfs: {% if pxe_options.pxe_append_params %}{{ pxe_options.pxe_append_params }}{% endif %} state=tmpfs: ipa-api-url={{ pxe_options.ipa-api-url }} {% if pxe_options.ipa-advertise-host %}ipa-advertise-host={{ pxe_options.ipa-advertise-host }}{% endif %}
diff --git a/ironic/tests/drivers/ilo/test_deploy.py b/ironic/tests/drivers/ilo/test_deploy.py
index d76697c40..5eb096471 100644
--- a/ironic/tests/drivers/ilo/test_deploy.py
+++ b/ironic/tests/drivers/ilo/test_deploy.py
@@ -27,6 +27,7 @@ from ironic.common import utils
from ironic.conductor import task_manager
from ironic.conductor import utils as manager_utils
from ironic.db import api as dbapi
+from ironic.drivers.modules import agent
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
@@ -249,6 +250,59 @@ class IloVirtualMediaIscsiDeployTestCase(base.TestCase):
clean_up_boot_mock.assert_called_once_with(task.node)
+class IloVirtualMediaAgentDeployTestCase(base.TestCase):
+
+ def setUp(self):
+ super(IloVirtualMediaAgentDeployTestCase, self).setUp()
+ self.dbapi = dbapi.get_instance()
+ self.context = context.get_admin_context()
+ mgr_utils.mock_the_extension_manager(driver="agent_ilo")
+ self.node = obj_utils.create_test_node(self.context,
+ driver='agent_ilo', driver_info=INFO_DICT)
+
+ @mock.patch.object(ilo_deploy, '_parse_driver_info')
+ def test_validate(self, parse_driver_info_mock):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ task.driver.deploy.validate(task)
+ parse_driver_info_mock.assert_called_once_with(task.node)
+
+ @mock.patch.object(ilo_deploy, '_reboot_into')
+ @mock.patch.object(agent, 'build_agent_options')
+ def test_deploy(self, build_options_mock, reboot_into_mock):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ deploy_opts = {'a': 'b'}
+ build_options_mock.return_value = deploy_opts
+ task.node.driver_info['ilo_deploy_iso'] = 'deploy-iso-uuid'
+
+ returned_state = task.driver.deploy.deploy(task)
+
+ build_options_mock.assert_called_once_with()
+ reboot_into_mock.assert_called_once_with(task,
+ 'glance:deploy-iso-uuid',
+ deploy_opts)
+ self.assertEqual(states.DEPLOYWAIT, returned_state)
+
+ @mock.patch.object(manager_utils, 'node_power_action')
+ def test_tear_down(self, node_power_action_mock):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ returned_state = task.driver.deploy.tear_down(task)
+ node_power_action_mock.assert_called_once_with(task,
+ states.POWER_OFF)
+ self.assertEqual(states.DELETED, returned_state)
+
+ @mock.patch.object(agent, 'build_instance_info_for_deploy')
+ def test_prepare(self, build_instance_info_mock):
+ deploy_opts = {'a': 'b'}
+ build_instance_info_mock.return_value = deploy_opts
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ task.driver.deploy.prepare(task)
+ self.assertEqual(deploy_opts, task.node.instance_info)
+
+
class VendorPassthruTestCase(base.TestCase):
def setUp(self):
diff --git a/ironic/tests/drivers/test_agent.py b/ironic/tests/drivers/test_agent.py
index eb48eff0c..685d7ba18 100644
--- a/ironic/tests/drivers/test_agent.py
+++ b/ironic/tests/drivers/test_agent.py
@@ -17,6 +17,7 @@ from oslo.config import cfg
from ironic.common import dhcp_factory
from ironic.common import exception
+from ironic.common import keystone
from ironic.common import pxe_utils
from ironic.common import states
from ironic.conductor import task_manager
@@ -35,6 +36,24 @@ DRIVER_INFO = db_utils.get_test_agent_driver_info()
CONF = cfg.CONF
+class TestAgentMethods(db_base.DbTestCase):
+ def setUp(self):
+ super(TestAgentMethods, self).setUp()
+
+ def test_build_agent_options_conf(self):
+ self.config(api_url='api-url', group='conductor')
+ options = agent.build_agent_options()
+ self.assertEqual('api-url', options['ipa-api-url'])
+
+ @mock.patch.object(keystone, 'get_service_url')
+ def test_build_agent_options_keystone(self, get_url_mock):
+
+ self.config(api_url=None, group='conductor')
+ get_url_mock.return_value = 'api-url'
+ options = agent.build_agent_options()
+ self.assertEqual('api-url', options['ipa-api-url'])
+
+
class TestAgentDeploy(db_base.DbTestCase):
def setUp(self):
super(TestAgentDeploy, self).setUp()
diff --git a/setup.cfg b/setup.cfg
index 8a1b8e77c..dcb3a33c9 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -35,6 +35,7 @@ ironic.dhcp =
none = ironic.dhcp.none:NoneDHCPApi
ironic.drivers =
+ agent_ilo = ironic.drivers.ilo:IloVirtualMediaAgentDriver
agent_ipmitool = ironic.drivers.agent:AgentAndIPMIToolDriver
agent_pyghmi = ironic.drivers.agent:AgentAndIPMINativeDriver
agent_ssh = ironic.drivers.agent:AgentAndSSHDriver