Merge "Add inspection feature for the OneView drivers"

This commit is contained in:
Jenkins 2016-10-06 21:42:50 +00:00 committed by Gerrit Code Review
commit 4858dd2e68
14 changed files with 458 additions and 60 deletions

View File

@ -8,7 +8,7 @@ proliantutils>=2.1.11
pyghmi>=0.8.0
pysnmp
python-ironic-inspector-client>=1.5.0
python-oneviewclient<3.0.0,>=2.0.2
python-oneviewclient<3.0.0,>=2.5.1
python-scciclient>=0.4.0
python-seamicroclient>=0.4.0
UcsSdk==0.8.2.2

View File

@ -354,3 +354,4 @@ class FakeOneViewDriver(base.BaseDriver):
self.management = oneview_management.OneViewManagement()
self.boot = fake.FakeBoot()
self.deploy = fake.FakeDeploy()
self.inspect = fake.FakeInspect()

View File

@ -155,13 +155,12 @@ def validate_oneview_resources_compatibility(task):
including server_hardware_uri, server_hardware_type_uri,
server_profile_template_uri, enclosure_group_uri and node ports. Also
verifies if a Server Profile is applied to the Server Hardware the node
represents. If any validation fails, python-oneviewclient will raise
an appropriate OneViewException.
represents when in pre-allocation model. If any validation fails,
python-oneviewclient will raise an appropriate OneViewException.
:param: task: a TaskManager instance containing the node to act on.
"""
node = task.node
node_ports = task.ports
oneview_info = get_oneview_info(task.node)
@ -169,13 +168,15 @@ def validate_oneview_resources_compatibility(task):
try:
oneview_client = get_oneview_client()
oneview_client.validate_node_server_hardware(
oneview_info, node.properties.get('memory_mb'),
node.properties.get('cpus')
)
oneview_client.validate_node_server_profile_template(oneview_info)
oneview_client.validate_node_server_hardware_type(oneview_info)
oneview_client.validate_node_enclosure_group(oneview_info)
oneview_client.validate_node_server_profile_template(oneview_info)
oneview_client.validate_node_server_hardware(
oneview_info,
task.node.properties.get('memory_mb'),
task.node.properties.get('cpus')
)
# NOTE(thiagop): Support to pre-allocation will be dropped in the Pike
# release
@ -183,12 +184,12 @@ def validate_oneview_resources_compatibility(task):
oneview_client.is_node_port_mac_compatible_with_server_hardware(
oneview_info, node_ports
)
oneview_client.validate_node_server_profile_template(oneview_info)
else:
oneview_client.check_server_profile_is_applied(oneview_info)
oneview_client.is_node_port_mac_compatible_with_server_profile(
oneview_info, node_ports
)
except oneview_exceptions.OneViewException as oneview_exc:
msg = (_("Error validating node resources with OneView: %s") %
oneview_exc)

View File

@ -211,6 +211,14 @@ class OneViewIscsiDeploy(iscsi_deploy.ISCSIDeploy, OneViewPeriodicTasks):
def get_properties(self):
deploy_utils.get_properties()
def validate(self, task):
common.verify_node_info(task.node)
try:
common.validate_oneview_resources_compatibility(task)
except exception.OneViewError as oneview_exc:
raise exception.InvalidParameterValue(oneview_exc)
super(OneViewIscsiDeploy, self).validate(task)
def prepare(self, task):
if common.is_dynamic_allocation_enabled(task.node):
deploy_utils.prepare(task)
@ -241,6 +249,14 @@ class OneViewAgentDeploy(agent.AgentDeploy, OneViewPeriodicTasks):
def get_properties(self):
deploy_utils.get_properties()
def validate(self, task):
common.verify_node_info(task.node)
try:
common.validate_oneview_resources_compatibility(task)
except exception.OneViewError as oneview_exc:
raise exception.InvalidParameterValue(oneview_exc)
super(OneViewAgentDeploy, self).validate(task)
def prepare(self, task):
if common.is_dynamic_allocation_enabled(task.node):
deploy_utils.prepare(task)

View File

@ -14,11 +14,13 @@
# License for the specific language governing permissions and limitations
# under the License.
import operator
from oslo_log import log as logging
from oslo_utils import importutils
from ironic.common import exception
from ironic.common.i18n import _, _LE, _LI, _LW
from ironic.common.i18n import _, _LE, _LI
from ironic.common import states
from ironic.drivers.modules.oneview import common
@ -54,7 +56,7 @@ def prepare(task):
{"instance_name": instance_display_name,
"instance_uuid": instance_uuid}
)
_allocate_server_hardware_to_ironic(task.node, server_profile_name)
allocate_server_hardware_to_ironic(task.node, server_profile_name)
except exception.OneViewError as e:
raise exception.InstanceDeployFailure(node=task.node.uuid,
reason=e)
@ -74,7 +76,7 @@ def tear_down(task):
"""
try:
_deallocate_server_hardware_from_ironic(task.node)
deallocate_server_hardware_from_ironic(task.node)
except exception.OneViewError as e:
raise exception.InstanceDeployFailure(node=task.node.uuid, reason=e)
@ -94,7 +96,7 @@ def prepare_cleaning(task):
"""
try:
server_profile_name = "Ironic Cleaning [%s]" % task.node.uuid
_allocate_server_hardware_to_ironic(task.node, server_profile_name)
allocate_server_hardware_to_ironic(task.node, server_profile_name)
except exception.OneViewError as e:
oneview_error = common.SERVER_HARDWARE_ALLOCATION_ERROR
driver_internal_info = task.node.driver_internal_info
@ -119,11 +121,29 @@ def tear_down_cleaning(task):
"""
try:
_deallocate_server_hardware_from_ironic(task.node)
deallocate_server_hardware_from_ironic(task.node)
except exception.OneViewError as e:
raise exception.NodeCleaningFailure(node=task.node.uuid, reason=e)
def _is_node_in_use(server_hardware, applied_sp_uri, by_oneview=False):
"""Check if node is in use by ironic or by OneView.
:param by_oneview: Boolean value. True when want to verify if node is in
use by OneView. False to verify if node is in use by
ironic.
:param node: an ironic node object
:returns: Boolean value. True if by_oneview param is also True and node is
in use by OneView, False otherwise. True if by_oneview param is
False and node is in use by ironic, False otherwise.
"""
operation = operator.ne if by_oneview else operator.eq
return (server_hardware.server_profile_uri not in (None, '') and
operation(applied_sp_uri, server_hardware.server_profile_uri))
def is_node_in_use_by_oneview(node):
"""Check if node is in use by OneView user.
@ -131,6 +151,54 @@ def is_node_in_use_by_oneview(node):
:returns: Boolean value. True if node is in use by OneView,
False otherwise.
:raises OneViewError: if not possible to get OneView's informations
for the given node, if not possible to retrieve Server Hardware
from OneView.
"""
positive = _("Node '%s' is in use by OneView.") % node.uuid
negative = _("Node '%s' is not in use by OneView.") % node.uuid
def predicate(server_hardware, applied_sp_uri):
# Check if Profile exists in Oneview and it is different of the one
# applied by ironic
return _is_node_in_use(server_hardware, applied_sp_uri,
by_oneview=True)
return _check_applied_server_profile(node, predicate, positive, negative)
def is_node_in_use_by_ironic(node):
"""Check if node is in use by ironic in OneView.
:param node: an ironic node object
:returns: Boolean value. True if node is in use by ironic,
False otherwise.
:raises OneViewError: if not possible to get OneView's information
for the given node, if not possible to retrieve Server Hardware
from OneView.
"""
positive = _("Node '%s' is in use by Ironic.") % node.uuid
negative = _("Node '%s' is not in use by Ironic.") % node.uuid
def predicate(server_hardware, applied_sp_uri):
# Check if Profile exists in Oneview and it is equals of the one
# applied by ironic
return _is_node_in_use(server_hardware, applied_sp_uri,
by_oneview=False)
return _check_applied_server_profile(node, predicate, positive, negative)
def _check_applied_server_profile(node, predicate, positive, negative):
"""Check if node is in use by ironic in OneView.
:param node: an ironic node object
:returns: Boolean value. True if node is in use by ironic,
False otherwise.
:raises OneViewError: if not possible to get OneView's information
for the given node, if not possible to retrieve Server Hardware
from OneView.
@ -157,24 +225,14 @@ def is_node_in_use_by_oneview(node):
node.driver_info.get('applied_server_profile_uri')
)
# Check if Profile exists in Oneview and it is different of the one
# applied by ironic
if (server_hardware.server_profile_uri not in (None, '') and
applied_sp_uri != server_hardware.server_profile_uri):
LOG.warning(_LW("Node %s is already in use by OneView."),
node.uuid)
return True
result = predicate(server_hardware, applied_sp_uri)
if result:
LOG.debug(positive)
else:
LOG.debug(_(
"Hardware %(hardware_uri)s is free for use by "
"ironic on node %(node_uuid)s."),
{"hardware_uri": server_hardware.uri,
"node_uuid": node.uuid})
LOG.debug(negative)
return False
return result
def _add_applied_server_profile_uri_field(node, applied_profile):
@ -201,7 +259,7 @@ def _del_applied_server_profile_uri_field(node):
node.save()
def _allocate_server_hardware_to_ironic(node, server_profile_name):
def allocate_server_hardware_to_ironic(node, server_profile_name):
"""Allocate Server Hardware to ironic.
:param node: an ironic node object
@ -276,7 +334,7 @@ def _allocate_server_hardware_to_ironic(node, server_profile_name):
raise exception.OneViewError(error=msg)
def _deallocate_server_hardware_from_ironic(node):
def deallocate_server_hardware_from_ironic(node):
"""Deallocate Server Hardware from ironic.
:param node: an ironic node object

View File

@ -0,0 +1,98 @@
# Copyright 2016 Hewlett Packard Enterprise Development LP.
# Copyright 2016 Universidade Federal de Campina Grande
# 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.
from futurist import periodics
from oslo_log import log as logging
from oslo_utils import importutils
from ironic.common import exception
from ironic.common import states
from ironic.conductor import task_manager
from ironic.drivers.modules import inspector
from ironic.drivers.modules.oneview import common
from ironic.drivers.modules.oneview import deploy_utils
from ironic.conf import CONF
LOG = logging.getLogger(__name__)
oneview_exception = importutils.try_import('oneview_client.exceptions')
oneview_utils = importutils.try_import('oneview_client.utils')
class OneViewInspect(inspector.Inspector):
"""Interface for in band inspection."""
def get_properties(self):
return common.COMMON_PROPERTIES
def validate(self, task):
"""Checks required info on 'driver_info' and validates node with OneView
Validates whether the 'driver_info' property of the supplied
task's node contains the required info such as server_hardware_uri,
server_hardware_type, server_profile_template_uri and
enclosure_group_uri. Also, checks if the server profile of the node is
applied, if NICs are valid for the server profile of the node.
:param task: a task from TaskManager.
:raises: InvalidParameterValue if parameters set are inconsistent with
resources in OneView
"""
common.verify_node_info(task.node)
try:
common.validate_oneview_resources_compatibility(task)
except exception.OneViewError as oneview_exc:
raise exception.InvalidParameterValue(oneview_exc)
def inspect_hardware(self, task):
profile_name = 'Ironic Inspecting [%s]' % task.node.uuid
deploy_utils.allocate_server_hardware_to_ironic(
task.node, profile_name
)
return super(OneViewInspect, self).inspect_hardware(task)
@periodics.periodic(spacing=CONF.inspector.status_check_period,
enabled=CONF.inspector.enabled)
def _periodic_check_result(self, manager, context):
filters = {'provision_state': states.INSPECTING}
node_iter = manager.iter_nodes(filters=filters)
for node_uuid, driver in node_iter:
if driver in [common.AGENT_PXE_ONEVIEW,
common.ISCSI_PXE_ONEVIEW]:
try:
lock_purpose = 'checking hardware inspection status'
with task_manager.acquire(context, node_uuid,
shared=True,
purpose=lock_purpose) as task:
self._check_status(task)
except (exception.NodeLocked, exception.NodeNotFound):
continue
def _check_status(self, task):
state_before = task.node.provision_state
result = inspector._check_status(task)
state_after = task.node.provision_state
# inspection finished
if (state_before == states.INSPECTING and
state_after in [states.MANAGEABLE, states.INSPECTFAIL]):
deploy_utils.deallocate_server_hardware_from_ironic(task.node)
return result

View File

@ -23,6 +23,7 @@ from ironic.common.i18n import _
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
LOG = logging.getLogger(__name__)
@ -65,6 +66,10 @@ class OneViewManagement(base.ManagementInterface):
try:
common.validate_oneview_resources_compatibility(task)
if not deploy_utils.is_node_in_use_by_ironic(task.node):
raise exception.InvalidParameterValue(
_("Node %s is not in use by ironic.") % task.node.uuid)
except exception.OneViewError as oneview_exc:
raise exception.InvalidParameterValue(oneview_exc)

View File

@ -24,6 +24,7 @@ from ironic.drivers import base
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 inspect
from ironic.drivers.modules.oneview import management
from ironic.drivers.modules.oneview import power
from ironic.drivers.modules.oneview import vendor
@ -55,6 +56,8 @@ class AgentPXEOneViewDriver(base.BaseDriver):
self.boot = pxe.PXEBoot()
self.deploy = deploy.OneViewAgentDeploy()
self.vendor = vendor.AgentVendorInterface()
self.inspect = inspect.OneViewInspect.create_if_enabled(
'AgentPXEOneViewDriver')
class ISCSIPXEOneViewDriver(base.BaseDriver):
@ -82,3 +85,5 @@ class ISCSIPXEOneViewDriver(base.BaseDriver):
self.boot = pxe.PXEBoot()
self.deploy = deploy.OneViewIscsiDeploy()
self.vendor = iscsi_deploy.VendorPassthru()
self.inspect = inspect.OneViewInspect.create_if_enabled(
'ISCSIPXEOneViewDriver')

View File

@ -237,8 +237,6 @@ class OneViewCommonTestCase(db_base.DbTestCase):
oneview_client = mock_get_ov_client()
with task_manager.acquire(self.context, self.node.uuid) as task:
common.validate_oneview_resources_compatibility(task)
self.assertTrue(
oneview_client.validate_node_server_hardware.called)
self.assertTrue(
oneview_client.validate_node_server_hardware_type.called)
self.assertTrue(
@ -264,15 +262,14 @@ class OneViewCommonTestCase(db_base.DbTestCase):
"""Validate compatibility of resources for Dynamic Allocation model.
1) Set 'dynamic_allocation' flag as True on node's driver_info
2) Check validate_node_server_hardware method is called
3) Check validate_node_server_hardware_type method is called
4) Check validate_node_enclosure_group method is called
5) Check validate_node_server_profile_template method is called
6) Check is_node_port_mac_compatible_with_server_hardware method
2) Check validate_node_server_hardware_type method is called
3) Check validate_node_enclosure_group method is called
4) Check validate_node_server_profile_template method is called
5) Check is_node_port_mac_compatible_with_server_hardware method
is called
7) Check validate_node_server_profile_template method is called
8) Check check_server_profile_is_applied method is not called
9) Check is_node_port_mac_compatible_with_server_profile method is
6) Check validate_node_server_profile_template method is called
7) Check check_server_profile_is_applied method is not called
8) Check is_node_port_mac_compatible_with_server_profile method is
not called
"""
@ -283,8 +280,6 @@ class OneViewCommonTestCase(db_base.DbTestCase):
task.node.driver_info = driver_info
common.validate_oneview_resources_compatibility(task)
self.assertTrue(
oneview_client.validate_node_server_hardware.called)
self.assertTrue(
oneview_client.validate_node_server_hardware_type.called)
self.assertTrue(

View File

@ -242,6 +242,43 @@ class OneViewDeployUtilsTestCase(db_base.DbTestCase):
deploy_utils.is_node_in_use_by_oneview(task.node)
)
# Tests for is_node_in_use_by_oneview
def test_is_node_in_use_by_ironic(self, mock_get_ov_client):
"""Node has a Server Profile applied by ironic.
"""
fake_sh = oneview_models.ServerHardware()
fake_sh.server_profile_uri = "same/applied_sp_uri/"
ov_client = mock_get_ov_client.return_value
ov_client.get_server_hardware_by_uuid.return_value = fake_sh
with task_manager.acquire(self.context, self.node.uuid) as task:
driver_info = task.node.driver_info
driver_info['dynamic_allocation'] = True
driver_info['applied_server_profile_uri'] = 'same/applied_sp_uri/'
task.node.driver_info = driver_info
self.assertTrue(
deploy_utils.is_node_in_use_by_ironic(task.node)
)
def test_is_node_in_use_by_ironic_no_server_profile(
self, mock_get_ov_client
):
"""Node has no Server Profile.
"""
fake_sh = oneview_models.ServerHardware()
fake_sh.server_profile_uri = None
ov_client = mock_get_ov_client.return_value
ov_client.get_server_hardware_by_uuid.return_value = fake_sh
with task_manager.acquire(self.context, self.node.uuid) as task:
self.assertFalse(
deploy_utils.is_node_in_use_by_ironic(task.node)
)
# Tests for _add_applied_server_profile_uri_field
def test__add_applied_server_profile_uri_field(self, mock_get_ov_client):
"""Checks if applied_server_profile_uri was added to driver_info.
@ -276,9 +313,9 @@ class OneViewDeployUtilsTestCase(db_base.DbTestCase):
self.assertNotIn('applied_server_profile_uri',
task.node.driver_info)
# Tests for _allocate_server_hardware_to_ironic
# Tests for allocate_server_hardware_to_ironic
@mock.patch.object(objects.Node, 'save')
def test__allocate_server_hardware_to_ironic(
def test_allocate_server_hardware_to_ironic(
self, mock_node_save, mock_get_ov_client
):
"""Checks if a Server Profile was created and its uri is in driver_info.
@ -291,7 +328,7 @@ class OneViewDeployUtilsTestCase(db_base.DbTestCase):
mock_get_ov_client.return_value = ov_client
with task_manager.acquire(self.context, self.node.uuid) as task:
deploy_utils._allocate_server_hardware_to_ironic(
deploy_utils.allocate_server_hardware_to_ironic(
task.node, 'serverProfileName'
)
self.assertTrue(ov_client.clone_template_and_apply.called)
@ -300,7 +337,7 @@ class OneViewDeployUtilsTestCase(db_base.DbTestCase):
@mock.patch.object(objects.Node, 'save')
@mock.patch.object(deploy_utils,
'_del_applied_server_profile_uri_field')
def test__allocate_server_hardware_to_ironic_node_has_server_profile(
def test_allocate_server_hardware_to_ironic_node_has_server_profile(
self, mock_delete_applied_sp, mock_node_save, mock_get_ov_client
):
"""Tests server profile allocation when applied_server_profile_uri exists.
@ -321,14 +358,14 @@ class OneViewDeployUtilsTestCase(db_base.DbTestCase):
driver_info['applied_server_profile_uri'] = 'any/applied_sp_uri/'
task.node.driver_info = driver_info
deploy_utils._allocate_server_hardware_to_ironic(
deploy_utils.allocate_server_hardware_to_ironic(
task.node, 'serverProfileName'
)
self.assertTrue(mock_delete_applied_sp.called)
# Tests for _deallocate_server_hardware_from_ironic
# Tests for deallocate_server_hardware_from_ironic
@mock.patch.object(objects.Node, 'save')
def test__deallocate_server_hardware_from_ironic(
def test_deallocate_server_hardware_from_ironic(
self, mock_node_save, mock_get_ov_client
):
ov_client = mock_get_ov_client.return_value
@ -342,7 +379,7 @@ class OneViewDeployUtilsTestCase(db_base.DbTestCase):
driver_info['applied_server_profile_uri'] = 'any/applied_sp_uri/'
task.node.driver_info = driver_info
deploy_utils._deallocate_server_hardware_from_ironic(task.node)
deploy_utils.deallocate_server_hardware_from_ironic(task.node)
self.assertTrue(ov_client.delete_server_profile.called)
self.assertTrue(
'applied_server_profile_uri' not in task.node.driver_info

View File

@ -0,0 +1,95 @@
# Copyright 2016 Hewlett Packard Enterprise Development LP.
# Copyright 2016 Universidade Federal de Campina Grande
# 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.
import mock
from ironic.conductor import task_manager
from ironic.drivers.modules.oneview import common as oneview_common
from ironic.drivers.modules.oneview import deploy_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
class AgentPXEOneViewInspectTestCase(db_base.DbTestCase):
def setUp(self):
super(AgentPXEOneViewInspectTestCase, self).setUp()
self.config(enabled=True, group='inspector')
mgr_utils.mock_the_extension_manager(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(),
)
def test_get_properties(self):
expected = oneview_common.COMMON_PROPERTIES
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
self.assertEqual(expected, task.driver.inspect.get_properties())
@mock.patch.object(oneview_common, 'verify_node_info', spec_set=True,
autospec=True)
def test_validate(self, mock_verify_node_info):
self.config(enabled=False, group='inspector')
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.driver.inspect.validate(task)
mock_verify_node_info.assert_called_once_with(task.node)
@mock.patch.object(deploy_utils, 'allocate_server_hardware_to_ironic')
def test_inspect_hardware(self, mock_allocate_server_hardware_to_ironic):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.driver.inspect.inspect_hardware(task)
self.assertTrue(mock_allocate_server_hardware_to_ironic.called)
class ISCSIPXEOneViewInspectTestCase(db_base.DbTestCase):
def setUp(self):
super(ISCSIPXEOneViewInspectTestCase, self).setUp()
self.config(enabled=True, group='inspector')
mgr_utils.mock_the_extension_manager(driver="iscsi_pxe_oneview")
self.node = obj_utils.create_test_node(
self.context, driver='iscsi_pxe_oneview',
properties=db_utils.get_test_oneview_properties(),
driver_info=db_utils.get_test_oneview_driver_info(),
)
def test_get_properties(self):
expected = oneview_common.COMMON_PROPERTIES
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
self.assertEqual(expected, task.driver.inspect.get_properties())
@mock.patch.object(oneview_common, 'verify_node_info', spec_set=True,
autospec=True)
def test_validate(self, mock_verify_node_info):
self.config(enabled=False, group='inspector')
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.driver.inspect.validate(task)
mock_verify_node_info.assert_called_once_with(task.node)
@mock.patch.object(deploy_utils, 'allocate_server_hardware_to_ironic')
def test_inspect_hardware(self, mock_allocate_server_hardware_to_ironic):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.driver.inspect.inspect_hardware(task)
self.assertTrue(mock_allocate_server_hardware_to_ironic.called)

View File

@ -32,6 +32,7 @@ from ironic.tests.unit.objects import utils as obj_utils
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)
@ -56,10 +57,37 @@ class OneViewManagementDriverTestCase(db_base.DbTestCase):
@mock.patch.object(common, 'validate_oneview_resources_compatibility',
spect_set=True, autospec=True)
def test_validate(self, mock_validate, mock_get_ov_client):
client = mock_get_ov_client.return_value
fake_server_hardware = oneview_models.ServerHardware()
fake_server_hardware.server_profile_uri = 'any/applied_sp_uri/'
client.get_server_hardware_by_uuid.return_value = fake_server_hardware
mock_get_ov_client.return_value = client
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) as task:
task.driver.management.validate(task)
self.assertTrue(mock_validate.called)
@mock.patch.object(common, 'validate_oneview_resources_compatibility',
spect_set=True, autospec=True)
def test_validate_for_node_not_in_use_by_ironic(self,
mock_validate,
mock_get_ov_client):
client = mock_get_ov_client.return_value
fake_server_hardware = oneview_models.ServerHardware()
fake_server_hardware.server_profile_uri = 'any/applied_sp_uri/'
client.get_server_hardware_by_uuid.return_value = fake_server_hardware
mock_get_ov_client.return_value = client
driver_info = self.node.driver_info
driver_info['applied_server_profile_uri'] = 'other/applied_sp_uri/'
self.node.driver_info = driver_info
self.node.save()
with task_manager.acquire(self.context, self.node.uuid) as task:
self.assertRaises(exception.InvalidParameterValue,
task.driver.management.validate, task)
def test_validate_fail(self, mock_get_ov_client):
node = obj_utils.create_test_node(self.context,
uuid=uuidutils.generate_uuid(),

View File

@ -15,16 +15,18 @@
# License for the specific language governing permissions and limitations
# under the License.
import mock
import time
import types
import mock
from oslo_utils import importutils
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.drivers.modules import agent_client
from ironic.drivers.modules.oneview import common
from ironic.drivers.modules.oneview import power
from ironic.drivers.modules.oneview import vendor
from ironic.drivers.modules import pxe
@ -34,10 +36,13 @@ 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
oneview_models = importutils.try_import('oneview_client.models')
GET_POWER_STATE_RETRIES = 5
@mock.patch.object(common, 'get_oneview_client', spec_set=True, autospec=True)
class TestBaseAgentVendor(db_base.DbTestCase):
def setUp(self):
@ -63,7 +68,8 @@ class TestBaseAgentVendor(db_base.DbTestCase):
@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):
node_power_action_mock,
mock_get_ov_client):
self.node.provision_state = states.DEPLOYING
self.node.target_provision_state = states.ACTIVE
self.node.save()
@ -89,9 +95,18 @@ class TestBaseAgentVendor(db_base.DbTestCase):
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):
node_power_action_mock, mock_get_ov_client):
client = mock_get_ov_client.return_value
fake_server_hardware = oneview_models.ServerHardware()
fake_server_hardware.server_profile_uri = 'any/applied_sp_uri/'
client.get_server_hardware_by_uuid.return_value = fake_server_hardware
mock_get_ov_client.return_value = 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:
@ -111,10 +126,20 @@ class TestBaseAgentVendor(db_base.DbTestCase):
@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):
self, power_off_mock, node_power_action_mock,
mock_get_ov_client):
client = mock_get_ov_client.return_value
fake_server_hardware = oneview_models.ServerHardware()
fake_server_hardware.server_profile_uri = 'any/applied_sp_uri/'
client.get_server_hardware_by_uuid.return_value = fake_server_hardware
mock_get_ov_client.return_value = 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:
@ -135,9 +160,18 @@ class TestBaseAgentVendor(db_base.DbTestCase):
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):
node_power_action_mock, mock_get_ov_client):
client = mock_get_ov_client.return_value
fake_server_hardware = oneview_models.ServerHardware()
fake_server_hardware.server_profile_uri = 'any/applied_sp_uri/'
client.get_server_hardware_by_uuid.return_value = fake_server_hardware
mock_get_ov_client.return_value = 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:
@ -162,7 +196,8 @@ class TestBaseAgentVendor(db_base.DbTestCase):
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):
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()
@ -193,11 +228,20 @@ class TestBaseAgentVendor(db_base.DbTestCase):
@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):
node_power_action_mock, mock_get_ov_client):
check_deploy_mock.return_value = None
client = mock_get_ov_client.return_value
fake_server_hardware = oneview_models.ServerHardware()
fake_server_hardware.server_profile_uri = 'any/applied_sp_uri/'
client.get_server_hardware_by_uuid.return_value = fake_server_hardware
mock_get_ov_client.return_value = 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:
@ -227,11 +271,21 @@ class TestBaseAgentVendor(db_base.DbTestCase):
check_deploy_mock,
power_off_mock,
get_power_state_mock,
node_power_action_mock):
node_power_action_mock,
mock_get_ov_client):
client = mock_get_ov_client.return_value
fake_server_hardware = oneview_models.ServerHardware()
fake_server_hardware.server_profile_uri = 'any/applied_sp_uri/'
client.get_server_hardware_by_uuid.return_value = fake_server_hardware
mock_get_ov_client.return_value = 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:

View File

@ -0,0 +1,5 @@
---
upgrade:
- Minimum required version of python-oneviewclient bumped to 2.5.1
features:
- Adds in-band inspection interface usable by OneView drivers.