Removes agent mixin from oneview drivers

This patch removes the agent mixin interface from oneview
drivers and adds a flag based solution instead. Once a set
boot device operation needs to be performed, the operation
is stored to driver_internal_info until the server power
on. Before power the server on again, the operation stored
is performed and then the server is powered on.

Change-Id: I8dabf7ef1ff6e44c062310c5cb3509e545585c0a
Closes-Bug: #1503855
This commit is contained in:
Xavier 2017-07-05 11:13:41 -03:00
parent 5187e80f03
commit 8f45317d43
8 changed files with 312 additions and 504 deletions

View File

@ -1,3 +1,4 @@
# Copyright 2017 Hewlett Packard Enterprise Development Company LP.
# Copyright 2015 Hewlett Packard Development Company, LP
# Copyright 2015 Universidade Federal de Campina Grande
#
@ -236,26 +237,41 @@ def _verify_node_info(node_namespace, node_info_dict, info_required):
def node_has_server_profile(func):
"""Checks if the node's Server Hardware has a Server Profile associated.
Decorator to execute before the function execution if the Server Profile
is applied to the Server Hardware.
:param func: a given decorated function.
"""
def inner(self, *args, **kwargs):
oneview_client = self.oneview_client
task = args[0]
oneview_info = get_oneview_info(task.node)
try:
node_has_server_profile = (
oneview_client.get_server_profile_from_hardware(oneview_info)
)
except oneview_exceptions.OneViewException as oneview_exc:
LOG.error(
"Failed to get server profile from OneView appliance for"
" node %(node)s. Error: %(message)s",
{"node": task.node.uuid, "message": oneview_exc}
)
raise exception.OneViewError(error=oneview_exc)
if not node_has_server_profile:
raise exception.OperationNotPermitted(
_("A Server Profile is not associated with node %s.") %
task.node.uuid
)
has_server_profile(task, oneview_client)
return func(self, *args, **kwargs)
return inner
def has_server_profile(task, oneview_client):
"""Checks if the node's Server Hardware has a Server Profile associated.
Function to check if the Server Profile is applied to the Server Hardware.
:param oneview_client: an instance of the OneView client
:param task: a TaskManager instance containing the node to act on.
"""
oneview_info = get_oneview_info(task.node)
try:
node_has_server_profile = (
oneview_client.get_server_profile_from_hardware(oneview_info)
)
except oneview_exceptions.OneViewException as oneview_exc:
LOG.error(
"Failed to get server profile from OneView appliance for"
" node %(node)s. Error: %(message)s",
{"node": task.node.uuid, "message": oneview_exc}
)
raise exception.OneViewError(error=oneview_exc)
if not node_has_server_profile:
raise exception.OperationNotPermitted(
_("A Server Profile is not associated with node %s.") %
task.node.uuid
)

View File

@ -1,3 +1,4 @@
# Copyright 2017 Hewlett Packard Enterprise Development Company LP.
# Copyright 2016 Hewlett Packard Enterprise Development LP.
# Copyright 2016 Universidade Federal de Campina Grande
# All Rights Reserved.
@ -19,17 +20,12 @@ import abc
from futurist import periodics
from ironic_lib import metrics_utils
from oslo_log import log as logging
import retrying
import six
from ironic.common import exception
from ironic.common.i18n import _
from ironic.common import states
from ironic.conductor import utils as manager_utils
from ironic.conf import CONF
from ironic.drivers.modules import agent
from ironic.drivers.modules import agent_base_vendor
from ironic.drivers.modules import deploy_utils as ironic_deploy_utils
from ironic.drivers.modules import iscsi_deploy
from ironic.drivers.modules.oneview import common
from ironic.drivers.modules.oneview import deploy_utils
@ -266,94 +262,7 @@ class OneViewIscsiDeploy(iscsi_deploy.ISCSIDeploy, OneViewPeriodicTasks):
super(OneViewIscsiDeploy, self).tear_down_cleaning(task)
# NOTE (thiagop): We overwrite this interface because we cannot change the boot
# device of OneView managed blades while they are still powered on. We moved
# the call of node_set_boot_device from reboot_to_instance to
# reboot_and_finish_deploy and changed the behavior to shutdown the node before
# doing it.
# TODO(thiagop): remove this interface once bug/1503855 is fixed
class OneViewAgentDeployMixin(object):
@METRICS.timer('OneViewAgentDeployMixin.reboot_to_instance')
def reboot_to_instance(self, task, **kwargs):
task.process_event('resume')
node = task.node
error = self.check_deploy_success(node)
if error is not None:
# TODO(jimrollenhagen) power off if using neutron dhcp to
# align with pxe driver?
msg = (_('node %(node)s command status errored: %(error)s') %
{'node': node.uuid, 'error': error})
LOG.error(msg)
ironic_deploy_utils.set_failed_state(task, msg)
return
LOG.info('Image successfully written to node %s', node.uuid)
LOG.debug('Rebooting node %s to instance', node.uuid)
self.reboot_and_finish_deploy(task)
# NOTE(TheJulia): If we deployed a whole disk image, we
# should expect a whole disk image and clean-up the tftp files
# on-disk incase the node is disregarding the boot preference.
# TODO(rameshg87): Not all in-tree drivers using reboot_to_instance
# have a boot interface. So include a check for now. Remove this
# check once all in-tree drivers have a boot interface.
if task.driver.boot:
task.driver.boot.clean_up_ramdisk(task)
@METRICS.timer('OneViewAgentDeployMixin.reboot_and_finish_deploy')
def reboot_and_finish_deploy(self, task):
"""Helper method to trigger reboot on the node and finish deploy.
This method initiates a reboot on the node. On success, it
marks the deploy as complete. On failure, it logs the error
and marks deploy as failure.
:param task: a TaskManager object containing the node
:raises: InstanceDeployFailure, if node reboot failed.
"""
wait = CONF.agent.post_deploy_get_power_state_retry_interval * 1000
attempts = CONF.agent.post_deploy_get_power_state_retries + 1
@retrying.retry(
stop_max_attempt_number=attempts,
retry_on_result=lambda state: state != states.POWER_OFF,
wait_fixed=wait
)
def _wait_until_powered_off(task):
return task.driver.power.get_power_state(task)
node = task.node
try:
try:
self._client.power_off(node)
_wait_until_powered_off(task)
except Exception as e:
LOG.warning(
'Failed to soft power off node %(node_uuid)s '
'in at least %(timeout)d seconds. Error: %(error)s',
{'node_uuid': node.uuid,
'timeout': (wait * (attempts - 1)) / 1000,
'error': e})
manager_utils.node_power_action(task, states.POWER_OFF)
manager_utils.node_set_boot_device(task, 'disk',
persistent=True)
manager_utils.node_power_action(task, states.POWER_ON)
except Exception as e:
msg = (_('Error rebooting node %(node)s after deploy. '
'Error: %(error)s') %
{'node': node.uuid, 'error': e})
agent_base_vendor.log_and_raise_deployment_error(task, msg)
task.process_event('done')
LOG.info('Deployment to node %s done', task.node.uuid)
class OneViewAgentDeploy(OneViewAgentDeployMixin, agent.AgentDeploy,
OneViewPeriodicTasks):
class OneViewAgentDeploy(agent.AgentDeploy, OneViewPeriodicTasks):
"""Class for OneView Agent deployment driver."""
oneview_driver = common.AGENT_PXE_ONEVIEW

View File

@ -1,4 +1,4 @@
#
# Copyright 2017 Hewlett Packard Enterprise Development Company LP.
# Copyright 2015 Hewlett Packard Development Company, LP
# Copyright 2015 Universidade Federal de Campina Grande
#
@ -44,6 +44,59 @@ BOOT_DEVICE_OV_TO_GENERIC = {
oneview_exceptions = importutils.try_import('oneview_client.exceptions')
def set_boot_device(task):
"""Sets the boot device for a node.
Sets the boot device to use on next reboot of the node.
:param task: a task from TaskManager.
:raises: InvalidParameterValue if an invalid boot device is
specified.
:raises: OperationNotPermitted if the server has no server profile or
if the server is already powered on.
:raises: OneViewError if the communication with OneView fails
"""
oneview_client = common.get_oneview_client()
common.has_server_profile(task, oneview_client)
driver_internal_info = task.node.driver_internal_info
next_boot_device = driver_internal_info.get('next_boot_device')
if next_boot_device:
boot_device = next_boot_device.get('boot_device')
persistent = next_boot_device.get('persistent')
if boot_device not in sorted(BOOT_DEVICE_MAPPING_TO_OV):
raise exception.InvalidParameterValue(
_("Invalid boot device %s specified.") % boot_device)
LOG.debug("Setting boot device to %(boot_device)s and "
"persistent to %(persistent)s for node %(node)s",
{"boot_device": boot_device, "persistent": persistent,
"node": task.node.uuid})
try:
oneview_info = common.get_oneview_info(task.node)
device_to_oneview = BOOT_DEVICE_MAPPING_TO_OV.get(boot_device)
oneview_client.set_boot_device(oneview_info,
device_to_oneview,
onetime=not persistent)
driver_internal_info.pop('next_boot_device', None)
task.node.driver_internal_info = driver_internal_info
task.node.save()
except oneview_exceptions.OneViewException as oneview_exc:
msg = (_(
"Error setting boot device on OneView. Error: %s")
% oneview_exc
)
raise exception.OneViewError(error=msg)
else:
LOG.debug("Not going to set boot device because there is no "
"'next_boot_device' on driver_internal_info "
"for the %(node)s",
{"node": task.node.uuid})
class OneViewManagement(base.ManagementInterface):
def __init__(self):
@ -99,9 +152,11 @@ class OneViewManagement(base.ManagementInterface):
@task_manager.require_exclusive_lock
@common.node_has_server_profile
def set_boot_device(self, task, device, persistent=False):
"""Sets the boot device for a node.
"""Set the next boot device to the node.
Sets the boot device to use on next reboot of the node.
Sets the boot device to the node next_boot_device on
driver_internal_info namespace. The operation will be
performed before the next node power on.
:param task: a task from TaskManager.
:param device: the boot device, one of the supported devices
@ -111,36 +166,32 @@ class OneViewManagement(base.ManagementInterface):
Default: False.
:raises: InvalidParameterValue if an invalid boot device is
specified.
:raises: OperationNotPermitted if the server has no server profile or
if the server is already powered on.
:raises: OneViewError if the communication with OneView fails
"""
oneview_info = common.get_oneview_info(task.node)
if device not in self.get_supported_boot_devices(task):
raise exception.InvalidParameterValue(
_("Invalid boot device %s specified.") % device)
LOG.debug("Setting boot device to %(device)s for node %(node)s",
{"device": device, "node": task.node.uuid})
try:
device_to_oneview = BOOT_DEVICE_MAPPING_TO_OV.get(device)
self.oneview_client.set_boot_device(oneview_info,
device_to_oneview,
onetime=not persistent)
except oneview_exceptions.OneViewException as oneview_exc:
msg = (_(
"Error setting boot device on OneView. Error: %s")
% oneview_exc
)
raise exception.OneViewError(error=msg)
driver_internal_info = task.node.driver_internal_info
next_boot_device = {'boot_device': device,
'persistent': persistent}
driver_internal_info['next_boot_device'] = next_boot_device
task.node.driver_internal_info = driver_internal_info
task.node.save()
LOG.debug("The 'next_boot_device' flag was updated on "
"driver_internal_info with device=%(boot_device)s "
"and persistent=%(persistent)s for the node "
"%(node)s",
{"boot_device": device, "persistent": persistent,
"node": task.node.uuid})
@METRICS.timer('OneViewManagement.get_boot_device')
@common.node_has_server_profile
def get_boot_device(self, task):
"""Get the current boot device for the task's node.
"""Get the current boot device from the node.
Provides the current boot device of the node.
Gets the boot device from the node 'next_boot_device on
driver_internal_info namespace if exists. Gets through
a request to OneView otherwise.
:param task: a task from TaskManager.
:returns: a dictionary containing:
@ -153,6 +204,12 @@ class OneViewManagement(base.ManagementInterface):
:raises: InvalidParameterValue if the boot device is unknown
:raises: OneViewError if the communication with OneView fails
"""
driver_internal_info = task.node.driver_internal_info
next_boot_device = driver_internal_info.get('next_boot_device')
if next_boot_device:
return next_boot_device
oneview_info = common.get_oneview_info(task.node)
try:

View File

@ -1,4 +1,4 @@
#
# Copyright 2017 Hewlett Packard Enterprise Development Company LP.
# Copyright 2015 Hewlett Packard Development Company, LP
# Copyright 2015 Universidade Federal de Campina Grande
#
@ -25,6 +25,7 @@ from ironic.conductor import task_manager
from ironic.drivers import base
from ironic.drivers.modules.oneview import common
from ironic.drivers.modules.oneview import deploy_utils
from ironic.drivers.modules.oneview import management
LOG = logging.getLogger(__name__)
@ -130,11 +131,13 @@ class OneViewPower(base.PowerInterface):
try:
if power_state == states.POWER_ON:
management.set_boot_device(task)
self.oneview_client.power_on(oneview_info)
elif power_state == states.POWER_OFF:
self.oneview_client.power_off(oneview_info)
elif power_state == states.REBOOT:
self.oneview_client.power_off(oneview_info)
management.set_boot_device(task)
self.oneview_client.power_on(oneview_info)
else:
raise exception.InvalidParameterValue(

View File

@ -1,3 +1,4 @@
# Copyright 2017 Hewlett Packard Enterprise Development Company LP.
# Copyright 2016 Hewlett Packard Enterprise Development LP.
# Copyright 2016 Universidade Federal de Campina Grande
# All Rights Reserved.
@ -14,9 +15,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import time
import types
import mock
from oslo_utils import importutils
@ -24,17 +22,12 @@ from ironic.common import driver_factory
from ironic.common import exception
from ironic.common import states
from ironic.conductor import task_manager
from ironic.conductor import utils as manager_utils
from ironic.conf import CONF
from ironic.drivers.modules import agent
from ironic.drivers.modules import agent_client
from ironic.drivers.modules import iscsi_deploy
from ironic.drivers.modules.oneview import common
from ironic.drivers.modules.oneview import deploy
from ironic.drivers.modules.oneview import deploy_utils
from ironic.drivers.modules.oneview import power
from ironic.drivers.modules import pxe
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
@ -266,301 +259,6 @@ class OneViewPeriodicTasks(db_base.DbTestCase):
self.assertFalse('oneview_error' in self.node.driver_internal_info)
@mock.patch.object(common, 'get_oneview_client', spec_set=True, autospec=True)
class TestOneViewAgentDeploy(db_base.DbTestCase):
def setUp(self):
super(TestOneViewAgentDeploy, self).setUp()
self.config(
post_deploy_get_power_state_retries=GET_POWER_STATE_RETRIES,
group='agent')
mgr_utils.mock_the_extension_manager(driver="agent_pxe_oneview")
self.driver = driver_factory.get_driver("agent_pxe_oneview")
self.node = obj_utils.create_test_node(
self.context, driver='agent_pxe_oneview',
properties=db_utils.get_test_oneview_properties(),
driver_info=db_utils.get_test_oneview_driver_info(),
driver_internal_info={'agent_url': 'http://1.2.3.4:5678'},
)
@mock.patch.object(time, 'sleep', lambda seconds: None)
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
@mock.patch.object(power.OneViewPower, 'get_power_state',
spec=types.FunctionType)
@mock.patch.object(agent_client.AgentClient, 'power_off',
spec=types.FunctionType)
@mock.patch('ironic.conductor.utils.node_set_boot_device', autospec=True)
def test_reboot_and_finish_deploy(self, set_bootdev_mock, power_off_mock,
get_power_state_mock,
node_power_action_mock,
mock_get_ov_client):
self.node.provision_state = states.DEPLOYING
self.node.target_provision_state = states.ACTIVE
self.node.save()
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
get_power_state_mock.side_effect = [states.POWER_ON,
states.POWER_OFF]
task.driver.deploy.reboot_and_finish_deploy(task)
power_off_mock.assert_called_once_with(task.node)
self.assertEqual(2, get_power_state_mock.call_count)
set_bootdev_mock.assert_called_once_with(task, 'disk',
persistent=True)
node_power_action_mock.assert_called_once_with(
task, states.POWER_ON)
self.assertEqual(states.ACTIVE, task.node.provision_state)
self.assertEqual(states.NOSTATE, task.node.target_provision_state)
@mock.patch.object(time, 'sleep', lambda seconds: None)
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
@mock.patch.object(power.OneViewPower, 'get_power_state',
spec=types.FunctionType)
@mock.patch.object(agent_client.AgentClient, 'power_off',
spec=types.FunctionType)
def test_reboot_and_finish_deploy_soft_poweroff_doesnt_complete(
self, power_off_mock, get_power_state_mock,
node_power_action_mock, mock_get_ov_client):
oneview_client = mock_get_ov_client.return_value
self.driver.management.oneview_client = oneview_client
fake_server_hardware = oneview_models.ServerHardware()
fake_server_hardware.server_profile_uri = 'any/applied_sp_uri/'
oneview_client.get_server_hardware_by_uuid.return_value = (
fake_server_hardware
)
mock_get_ov_client.return_value = oneview_client
self.node.provision_state = states.DEPLOYING
self.node.target_provision_state = states.ACTIVE
driver_info = self.node.driver_info
driver_info['applied_server_profile_uri'] = 'any/applied_sp_uri/'
self.node.driver_info = driver_info
self.node.save()
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
get_power_state_mock.return_value = states.POWER_ON
task.driver.deploy.reboot_and_finish_deploy(task)
power_off_mock.assert_called_once_with(task.node)
self.assertEqual(GET_POWER_STATE_RETRIES + 1,
get_power_state_mock.call_count)
node_power_action_mock.assert_has_calls([
mock.call(task, states.POWER_OFF),
mock.call(task, states.POWER_ON)
])
self.assertEqual(states.ACTIVE, task.node.provision_state)
self.assertEqual(states.NOSTATE, task.node.target_provision_state)
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
@mock.patch.object(agent_client.AgentClient, 'power_off',
spec=types.FunctionType)
def test_reboot_and_finish_deploy_soft_poweroff_fails(
self, power_off_mock, node_power_action_mock,
mock_get_ov_client):
oneview_client = mock_get_ov_client.return_value
self.driver.management.oneview_client = oneview_client
fake_server_hardware = oneview_models.ServerHardware()
fake_server_hardware.server_profile_uri = 'any/applied_sp_uri/'
oneview_client.get_server_hardware_by_uuid.return_value = (
fake_server_hardware
)
mock_get_ov_client.return_value = oneview_client
power_off_mock.side_effect = RuntimeError("boom")
self.node.provision_state = states.DEPLOYING
self.node.target_provision_state = states.ACTIVE
driver_info = self.node.driver_info
driver_info['applied_server_profile_uri'] = 'any/applied_sp_uri/'
self.node.driver_info = driver_info
self.node.save()
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.driver.deploy.reboot_and_finish_deploy(task)
power_off_mock.assert_called_once_with(task.node)
node_power_action_mock.assert_has_calls([
mock.call(task, states.POWER_OFF),
mock.call(task, states.POWER_ON)
])
self.assertEqual(states.ACTIVE, task.node.provision_state)
self.assertEqual(states.NOSTATE, task.node.target_provision_state)
@mock.patch.object(time, 'sleep', lambda seconds: None)
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
@mock.patch.object(power.OneViewPower, 'get_power_state',
spec=types.FunctionType)
@mock.patch.object(agent_client.AgentClient, 'power_off',
spec=types.FunctionType)
def test_reboot_and_finish_deploy_get_power_state_fails(
self, power_off_mock, get_power_state_mock,
node_power_action_mock, mock_get_ov_client):
oneview_client = mock_get_ov_client.return_value
self.driver.management.oneview_client = oneview_client
fake_server_hardware = oneview_models.ServerHardware()
fake_server_hardware.server_profile_uri = 'any/applied_sp_uri/'
oneview_client.get_server_hardware_by_uuid.return_value = (
fake_server_hardware
)
mock_get_ov_client.return_value = oneview_client
self.node.provision_state = states.DEPLOYING
self.node.target_provision_state = states.ACTIVE
driver_info = self.node.driver_info
driver_info['applied_server_profile_uri'] = 'any/applied_sp_uri/'
self.node.driver_info = driver_info
self.node.save()
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
get_power_state_mock.side_effect = RuntimeError("boom")
task.driver.deploy.reboot_and_finish_deploy(task)
power_off_mock.assert_called_once_with(task.node)
self.assertEqual(GET_POWER_STATE_RETRIES + 1,
get_power_state_mock.call_count)
node_power_action_mock.assert_has_calls([
mock.call(task, states.POWER_OFF),
mock.call(task, states.POWER_ON)
])
self.assertEqual(states.ACTIVE, task.node.provision_state)
self.assertEqual(states.NOSTATE, task.node.target_provision_state)
@mock.patch.object(driver_utils, 'collect_ramdisk_logs', autospec=True)
@mock.patch.object(time, 'sleep', lambda seconds: None)
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
@mock.patch.object(power.OneViewPower, 'get_power_state',
spec=types.FunctionType)
@mock.patch.object(agent_client.AgentClient, 'power_off',
spec=types.FunctionType)
def test_reboot_and_finish_deploy_power_action_fails(
self, power_off_mock, get_power_state_mock,
node_power_action_mock, collect_ramdisk_logs_mock,
mock_get_ov_client):
self.node.provision_state = states.DEPLOYING
self.node.target_provision_state = states.ACTIVE
self.node.save()
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
get_power_state_mock.return_value = states.POWER_ON
node_power_action_mock.side_effect = RuntimeError("boom")
self.assertRaises(exception.InstanceDeployFailure,
task.driver.deploy.reboot_and_finish_deploy,
task)
power_off_mock.assert_called_once_with(task.node)
self.assertEqual(GET_POWER_STATE_RETRIES + 1,
get_power_state_mock.call_count)
node_power_action_mock.assert_has_calls([
mock.call(task, states.POWER_OFF),
mock.call(task, states.POWER_OFF)])
self.assertEqual(states.DEPLOYFAIL, task.node.provision_state)
self.assertEqual(states.ACTIVE, task.node.target_provision_state)
collect_ramdisk_logs_mock.assert_called_once_with(task.node)
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
@mock.patch.object(power.OneViewPower, 'get_power_state',
spec=types.FunctionType)
@mock.patch.object(agent_client.AgentClient, 'power_off',
spec=types.FunctionType)
@mock.patch('ironic.drivers.modules.agent.AgentDeploy'
'.check_deploy_success', autospec=True)
@mock.patch.object(pxe.PXEBoot, 'clean_up_ramdisk', autospec=True)
def test_reboot_to_instance(self, clean_pxe_mock, check_deploy_mock,
power_off_mock, get_power_state_mock,
node_power_action_mock, mock_get_ov_client):
check_deploy_mock.return_value = None
oneview_client = mock_get_ov_client.return_value
self.driver.management.oneview_client = oneview_client
fake_server_hardware = oneview_models.ServerHardware()
fake_server_hardware.server_profile_uri = 'any/applied_sp_uri/'
oneview_client.get_server_hardware_by_uuid.return_value = (
fake_server_hardware
)
mock_get_ov_client.return_value = oneview_client
self.node.provision_state = states.DEPLOYWAIT
self.node.target_provision_state = states.ACTIVE
driver_info = self.node.driver_info
driver_info['applied_server_profile_uri'] = 'any/applied_sp_uri/'
self.node.driver_info = driver_info
self.node.save()
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
get_power_state_mock.return_value = states.POWER_OFF
task.node.driver_internal_info['is_whole_disk_image'] = True
task.driver.deploy.reboot_to_instance(task)
clean_pxe_mock.assert_called_once_with(task.driver.boot, task)
check_deploy_mock.assert_called_once_with(mock.ANY, task.node)
power_off_mock.assert_called_once_with(task.node)
get_power_state_mock.assert_called_once_with(task)
node_power_action_mock.assert_called_once_with(
task, states.POWER_ON)
self.assertEqual(states.ACTIVE, task.node.provision_state)
self.assertEqual(states.NOSTATE, task.node.target_provision_state)
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
@mock.patch.object(power.OneViewPower, 'get_power_state',
spec=types.FunctionType)
@mock.patch.object(agent_client.AgentClient, 'power_off',
spec=types.FunctionType)
@mock.patch('ironic.drivers.modules.agent.AgentDeploy'
'.check_deploy_success', autospec=True)
@mock.patch.object(pxe.PXEBoot, 'clean_up_ramdisk', autospec=True)
def test_reboot_to_instance_boot_none(self, clean_pxe_mock,
check_deploy_mock,
power_off_mock,
get_power_state_mock,
node_power_action_mock,
mock_get_ov_client):
oneview_client = mock_get_ov_client.return_value
self.driver.management.oneview_client = oneview_client
fake_server_hardware = oneview_models.ServerHardware()
fake_server_hardware.server_profile_uri = 'any/applied_sp_uri/'
oneview_client.get_server_hardware_by_uuid.return_value = (
fake_server_hardware
)
mock_get_ov_client.return_value = oneview_client
check_deploy_mock.return_value = None
self.node.provision_state = states.DEPLOYWAIT
self.node.target_provision_state = states.ACTIVE
driver_info = self.node.driver_info
driver_info['applied_server_profile_uri'] = 'any/applied_sp_uri/'
self.node.driver_info = driver_info
self.node.save()
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
get_power_state_mock.return_value = states.POWER_OFF
task.node.driver_internal_info['is_whole_disk_image'] = True
task.driver.boot = None
task.driver.deploy.reboot_to_instance(task)
self.assertFalse(clean_pxe_mock.called)
check_deploy_mock.assert_called_once_with(mock.ANY, task.node)
power_off_mock.assert_called_once_with(task.node)
get_power_state_mock.assert_called_once_with(task)
node_power_action_mock.assert_called_once_with(
task, states.POWER_ON)
self.assertEqual(states.ACTIVE, task.node.provision_state)
self.assertEqual(states.NOSTATE, task.node.target_provision_state)
@mock.patch.object(common, 'get_oneview_client', spec_set=True, autospec=True)
class OneViewIscsiDeployTestCase(db_base.DbTestCase):

View File

@ -1,5 +1,4 @@
# -*- encoding: utf-8 -*-
#
# Copyright 2017 Hewlett Packard Enterprise Development Company LP.
# Copyright 2015 Hewlett Packard Development Company, LP
# Copyright 2015 Universidade Federal de Campina Grande
#
@ -35,6 +34,117 @@ oneview_exceptions = importutils.try_import('oneview_client.exceptions')
oneview_models = importutils.try_import('oneview_client.models')
@mock.patch.object(common, 'get_oneview_client', spect_set=True, autospec=True)
class OneViewManagementDriverFunctionsTestCase(db_base.DbTestCase):
def setUp(self):
super(OneViewManagementDriverFunctionsTestCase, self).setUp()
self.config(manager_url='https://1.2.3.4', group='oneview')
self.config(username='user', group='oneview')
self.config(password='password', group='oneview')
mgr_utils.mock_the_extension_manager(driver="fake_oneview")
self.driver = driver_factory.get_driver("fake_oneview")
self.node = obj_utils.create_test_node(
self.context, driver='fake_oneview',
properties=db_utils.get_test_oneview_properties(),
driver_info=db_utils.get_test_oneview_driver_info(),
)
self.info = common.get_oneview_info(self.node)
def test_set_boot_device(self, mock_get_ov_client):
oneview_client = mock_get_ov_client()
with task_manager.acquire(self.context, self.node.uuid) as task:
driver_internal_info = task.node.driver_internal_info
next_boot_device = {'boot_device': boot_devices.PXE,
'persistent': False}
driver_internal_info['next_boot_device'] = next_boot_device
task.node.driver_internal_info = driver_internal_info
management.set_boot_device(task)
oneview_client.set_boot_device.assert_called_once_with(
self.info,
management.BOOT_DEVICE_MAPPING_TO_OV[boot_devices.PXE],
onetime=True
)
driver_internal_info = task.node.driver_internal_info
self.assertNotIn('next_boot_device', driver_internal_info)
def test_set_boot_device_persistent(self, mock_get_ov_client):
oneview_client = mock_get_ov_client()
with task_manager.acquire(self.context, self.node.uuid) as task:
driver_internal_info = task.node.driver_internal_info
next_boot_device = {'boot_device': boot_devices.PXE,
'persistent': True}
driver_internal_info['next_boot_device'] = next_boot_device
task.node.driver_internal_info = driver_internal_info
management.set_boot_device(task)
oneview_client.set_boot_device.assert_called_once_with(
self.info,
management.BOOT_DEVICE_MAPPING_TO_OV[boot_devices.PXE],
onetime=False
)
driver_internal_info = task.node.driver_internal_info
self.assertNotIn('next_boot_device', driver_internal_info)
def test_set_boot_device_invalid_device(self, mock_get_ov_client):
oneview_client = mock_get_ov_client()
with task_manager.acquire(self.context, self.node.uuid) as task:
driver_internal_info = task.node.driver_internal_info
next_boot_device = {'boot_device': 'pixie-boots',
'persistent': True}
driver_internal_info['next_boot_device'] = next_boot_device
task.node.driver_internal_info = driver_internal_info
self.assertRaises(exception.InvalidParameterValue,
management.set_boot_device,
task)
self.assertFalse(oneview_client.set_boot_device.called)
self.assertIn('next_boot_device', driver_internal_info)
def test_set_boot_device_fail_to_get_server_profile(
self, mock_get_ov_client):
oneview_client = mock_get_ov_client()
oneview_client.get_server_profile_from_hardware.side_effect = \
oneview_exceptions.OneViewException()
with task_manager.acquire(self.context, self.node.uuid) as task:
driver_internal_info = task.node.driver_internal_info
next_boot_device = {'boot_device': 'disk',
'persistent': True}
driver_internal_info['next_boot_device'] = next_boot_device
task.node.driver_internal_info = driver_internal_info
self.assertRaises(exception.OneViewError,
management.set_boot_device,
task)
self.assertFalse(oneview_client.set_boot_device.called)
self.assertIn('next_boot_device', driver_internal_info)
def test_set_boot_device_without_server_profile(self, mock_get_ov_client):
oneview_client = mock_get_ov_client()
oneview_client.get_server_profile_from_hardware.return_value = False
with task_manager.acquire(self.context, self.node.uuid) as task:
driver_internal_info = task.node.driver_internal_info
next_boot_device = {'device': 'disk',
'persistent': True}
driver_internal_info['next_boot_device'] = next_boot_device
task.node.driver_internal_info = driver_internal_info
expected_msg = (
'A Server Profile is not associated with node %s.'
% self.node.uuid
)
self.assertRaisesRegex(
exception.OperationNotPermitted,
expected_msg,
management.set_boot_device,
task
)
self.assertIn('next_boot_device', driver_internal_info)
@mock.patch.object(common, 'get_oneview_client', spect_set=True, autospec=True)
class OneViewManagementDriverTestCase(db_base.DbTestCase):
@ -126,70 +236,35 @@ class OneViewManagementDriverTestCase(db_base.DbTestCase):
self.assertItemsEqual(expected,
self.driver.management.get_properties())
def test_set_boot_device(self, mock_get_ov_client):
oneview_client = mock_get_ov_client()
self.driver.management.oneview_client = oneview_client
def test_set_boot_device_persistent_true(self, mock_get_ov_client):
with task_manager.acquire(self.context, self.node.uuid) as task:
self.driver.management.set_boot_device(task, boot_devices.PXE)
oneview_client.set_boot_device.assert_called_once_with(
self.info,
management.BOOT_DEVICE_MAPPING_TO_OV[boot_devices.PXE],
onetime=True
)
def test_set_boot_device_persistent(self, mock_get_ov_client):
oneview_client = mock_get_ov_client()
self.driver.management.oneview_client = oneview_client
task.driver.management.set_boot_device(
task, boot_devices.PXE, True)
driver_internal_info = task.node.driver_internal_info
next_boot_device = driver_internal_info.get('next_boot_device')
self.assertIn('next_boot_device', driver_internal_info)
self.assertEqual(
next_boot_device.get('boot_device'), boot_devices.PXE)
self.assertTrue(next_boot_device.get('persistent'))
def test_set_boot_device_persistent_false(self, mock_get_ov_client):
with task_manager.acquire(self.context, self.node.uuid) as task:
self.driver.management.set_boot_device(task, boot_devices.PXE,
persistent=True)
oneview_client.set_boot_device.assert_called_once_with(
self.info,
management.BOOT_DEVICE_MAPPING_TO_OV[boot_devices.PXE],
onetime=False
)
task.driver.management.set_boot_device(
task, boot_devices.PXE, False)
driver_internal_info = task.node.driver_internal_info
next_boot_device = driver_internal_info.get('next_boot_device')
self.assertIn('next_boot_device', driver_internal_info)
self.assertEqual(
next_boot_device.get('boot_device'), boot_devices.PXE)
self.assertFalse(next_boot_device.get('persistent'))
def test_set_boot_device_invalid_device(self, mock_get_ov_client):
oneview_client = mock_get_ov_client()
self.driver.management.oneview_client = oneview_client
with task_manager.acquire(self.context, self.node.uuid) as task:
self.assertRaises(exception.InvalidParameterValue,
self.driver.management.set_boot_device,
task, 'fake-device')
self.assertFalse(oneview_client.set_boot_device.called)
def test_set_boot_device_fail_to_get_server_profile(self,
mock_get_ov_client):
oneview_client = mock_get_ov_client()
oneview_client.get_server_profile_from_hardware.side_effect = \
oneview_exceptions.OneViewException()
self.driver.management.oneview_client = oneview_client
with task_manager.acquire(self.context, self.node.uuid) as task:
self.assertRaises(exception.OneViewError,
self.driver.management.set_boot_device,
task, 'disk')
self.assertFalse(oneview_client.set_boot_device.called)
def test_set_boot_device_without_server_profile(self, mock_get_ov_client):
oneview_client = mock_get_ov_client()
oneview_client.get_server_profile_from_hardware.return_value = False
self.driver.management.oneview_client = oneview_client
with task_manager.acquire(self.context, self.node.uuid) as task:
expected_msg = (
'A Server Profile is not associated with node %s.'
% self.node.uuid
)
self.assertRaisesRegex(
exception.OperationNotPermitted,
expected_msg,
self.driver.management.set_boot_device,
task,
'disk'
)
task.driver.management.set_boot_device,
task, 'unknown-device', False)
driver_internal_info = task.node.driver_internal_info
self.assertNotIn('next_boot_device', driver_internal_info)
def test_get_supported_boot_devices(self, mock_get_ov_client):
with task_manager.acquire(self.context, self.node.uuid) as task:
@ -218,6 +293,25 @@ class OneViewManagementDriverTestCase(db_base.DbTestCase):
self.assertEqual(expected_response, response)
oneview_client.get_boot_order.assert_called_with(self.info)
def test_get_boot_device_from_next_boot_device(
self, mock_get_ov_client):
oneview_client = mock_get_ov_client()
self.driver.management.oneview_client = oneview_client
with task_manager.acquire(self.context, self.node.uuid) as task:
driver_internal_info = task.node.driver_internal_info
next_boot_device = {'boot_device': boot_devices.DISK,
'persistent': True}
driver_internal_info['next_boot_device'] = next_boot_device
task.node.driver_internal_info = driver_internal_info
expected_response = {
'boot_device': boot_devices.DISK,
'persistent': True
}
response = self.driver.management.get_boot_device(task)
self.assertEqual(expected_response, response)
self.assertFalse(oneview_client.get_boot_order.called)
def test_get_boot_device_fail(self, mock_get_ov_client):
oneview_client = mock_get_ov_client()
oneview_client.get_boot_order.side_effect = \

View File

@ -25,6 +25,7 @@ from ironic.common import states
from ironic.conductor import task_manager
from ironic.drivers.modules.oneview import common
from ironic.drivers.modules.oneview import deploy_utils
from ironic.drivers.modules.oneview import management
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
@ -142,7 +143,9 @@ class OneViewPowerDriverTestCase(db_base.DbTestCase):
task
)
def test_set_power_on(self, mock_get_ov_client):
@mock.patch.object(management, 'set_boot_device')
def test_set_power_on(
self, mock_set_boot_device, mock_get_ov_client):
sp_uri = '/any/server-profile'
oneview_client = mock_get_ov_client()
@ -158,10 +161,13 @@ class OneViewPowerDriverTestCase(db_base.DbTestCase):
driver_info['applied_server_profile_uri'] = sp_uri
task.node.driver_info = driver_info
self.driver.power.set_power_state(task, states.POWER_ON)
mock_set_boot_device.assert_called_once_with(task)
self.info['applied_server_profile_uri'] = sp_uri
oneview_client.power_on.assert_called_once_with(self.info)
def test_set_power_off(self, mock_get_ov_client):
@mock.patch.object(management, 'set_boot_device')
def test_set_power_off(
self, mock_set_boot_device, mock_get_ov_client):
sp_uri = '/any/server-profile'
oneview_client = mock_get_ov_client()
@ -177,10 +183,13 @@ class OneViewPowerDriverTestCase(db_base.DbTestCase):
driver_info['applied_server_profile_uri'] = sp_uri
task.node.driver_info = driver_info
self.driver.power.set_power_state(task, states.POWER_OFF)
self.assertFalse(mock_set_boot_device.called)
self.info['applied_server_profile_uri'] = sp_uri
oneview_client.power_off.assert_called_once_with(self.info)
def test_set_power_on_fail(self, mock_get_ov_client):
@mock.patch.object(management, 'set_boot_device')
def test_set_power_on_fail(
self, mock_set_boot_device, mock_get_ov_client):
sp_uri = '/any/server-profile'
oneview_client = mock_get_ov_client()
@ -198,10 +207,13 @@ class OneViewPowerDriverTestCase(db_base.DbTestCase):
self.assertRaises(exception.OneViewError,
self.driver.power.set_power_state, task,
states.POWER_ON)
mock_set_boot_device.assert_called_once_with(task)
self.info['applied_server_profile_uri'] = sp_uri
oneview_client.power_on.assert_called_once_with(self.info)
def test_set_power_off_fail(self, mock_get_ov_client):
@mock.patch.object(management, 'set_boot_device')
def test_set_power_off_fail(
self, mock_set_boot_device, mock_get_ov_client):
sp_uri = '/any/server-profile'
oneview_client = mock_get_ov_client()
@ -219,10 +231,13 @@ class OneViewPowerDriverTestCase(db_base.DbTestCase):
self.assertRaises(exception.OneViewError,
self.driver.power.set_power_state, task,
states.POWER_OFF)
self.assertFalse(mock_set_boot_device.called)
self.info['applied_server_profile_uri'] = sp_uri
oneview_client.power_off.assert_called_once_with(self.info)
def test_set_power_invalid_state(self, mock_get_ov_client):
@mock.patch.object(management, 'set_boot_device')
def test_set_power_invalid_state(
self, mock_set_boot_device, mock_get_ov_client):
sp_uri = '/any/server-profile'
oneview_client = mock_get_ov_client()
@ -240,8 +255,11 @@ class OneViewPowerDriverTestCase(db_base.DbTestCase):
self.assertRaises(exception.InvalidParameterValue,
self.driver.power.set_power_state, task,
'fake state')
self.assertFalse(mock_set_boot_device.called)
def test_set_power_reboot(self, mock_get_ov_client):
@mock.patch.object(management, 'set_boot_device')
def test_set_power_reboot(
self, mock_set_boot_device, mock_get_ov_client):
sp_uri = '/any/server-profile'
oneview_client = mock_get_ov_client()
@ -257,12 +275,15 @@ class OneViewPowerDriverTestCase(db_base.DbTestCase):
driver_info['applied_server_profile_uri'] = sp_uri
task.node.driver_info = driver_info
self.driver.power.set_power_state(task, states.REBOOT)
mock_set_boot_device.assert_called_once_with(task)
self.info['applied_server_profile_uri'] = sp_uri
oneview_client.power_off.assert_called_once_with(self.info)
oneview_client.power_off.assert_called_once_with(self.info)
oneview_client.power_on.assert_called_once_with(self.info)
def test_reboot(self, mock_get_ov_client):
@mock.patch.object(management, 'set_boot_device')
def test_reboot(
self, mock_set_boot_device, mock_get_ov_client):
sp_uri = '/any/server-profile'
oneview_client = mock_get_ov_client()
@ -278,11 +299,14 @@ class OneViewPowerDriverTestCase(db_base.DbTestCase):
driver_info['applied_server_profile_uri'] = sp_uri
task.node.driver_info = driver_info
self.driver.power.reboot(task)
mock_set_boot_device.assert_called_once_with(task)
self.info['applied_server_profile_uri'] = sp_uri
oneview_client.power_off.assert_called_once_with(self.info)
oneview_client.power_on.assert_called_once_with(self.info)
def test_reboot_fail(self, mock_get_ov_client):
@mock.patch.object(management, 'set_boot_device')
def test_reboot_fail(
self, mock_set_boot_device, mock_get_ov_client):
sp_uri = '/any/server-profile'
oneview_client = mock_get_ov_client()
@ -300,6 +324,7 @@ class OneViewPowerDriverTestCase(db_base.DbTestCase):
task.node.driver_info = driver_info
self.assertRaises(exception.OneViewError,
self.driver.power.reboot, task)
self.assertFalse(mock_set_boot_device.called)
self.info['applied_server_profile_uri'] = sp_uri
oneview_client.power_off.assert_called_once_with(self.info)
self.assertFalse(oneview_client.power_on.called)

View File

@ -0,0 +1,6 @@
---
features:
- |
Oneview drivers caches the next boot device in node's internal
info when set_boot_device() is called. It is applied on the
bare metal when node is power cycled.