Merge "Remove oneview drivers"

This commit is contained in:
Zuul 2018-10-22 18:58:10 +00:00 committed by Gerrit Code Review
commit 01d46be1fa
32 changed files with 15 additions and 4516 deletions

View File

@ -113,9 +113,6 @@ IRONIC_HW_ARCH=${IRONIC_HW_ARCH:-x86_64}
# cisco-ucs-managed:
# <BMC address> <MAC address> <BMC username> <BMC password> <UCS service profile>
#
# oneview:
# <Server Hardware URI> <Server Hardware Type URI> <Enclosure Group URI> <Server Profile Template URI> <MAC of primary connection> <Applied Server Profile URI>
#
# idrac:
# <BMC address> <MAC address> <BMC username> <BMC password>
#
@ -288,7 +285,7 @@ fi
# are ``ipmi``, ``snmp`` and ``redfish``.
#
# Additional valid choices if IRONIC_IS_HARDWARE == true are:
# ``cisco-ucs-managed``, ``cisco-ucs-standalone``, ``oneview``, ``idrac``,
# ``cisco-ucs-managed``, ``cisco-ucs-standalone``, ``idrac``,
# and ``irmc``.
IRONIC_DEPLOY_DRIVER=${IRONIC_DEPLOY_DRIVER:-ipmi}
@ -627,11 +624,6 @@ function is_deployed_by_ucs {
return 1
}
function is_deployed_by_oneview {
[[ "${IRONIC_DEPLOY_DRIVER}" == oneview ]] && return 0
return 1
}
function is_deployed_by_ilo {
[[ "${IRONIC_DEPLOY_DRIVER}" == ilo ]] && return 0
return 1
@ -1936,32 +1928,6 @@ function enroll_nodes {
--driver-info ucs_password=$bmc_passwd \
--driver-info ucs_username=$bmc_username \
--driver-info ucs_service_profile=$ucs_service_profile"
elif is_deployed_by_oneview; then
local server_hardware_uri
server_hardware_uri=$(echo $hardware_info |awk '{print $1}')
local server_hardware_type_uri
server_hardware_type_uri=$(echo $hardware_info |awk '{print $2}')
local enclosure_group_uri
enclosure_group_uri=$(echo $hardware_info |awk '{print $3}')
local server_profile_template_uri
server_profile_template_uri=$(echo $hardware_info |awk '{print $4}')
mac_address=$(echo $hardware_info |awk '{print $5}')
local applied_server_profile_uri
applied_server_profile_uri=$(echo $hardware_info |awk '{print $6}')
node_options+=" --driver-info server_hardware_uri=$server_hardware_uri"
if [[ -n "$applied_server_profile_uri" ]]; then
node_options+=" --driver-info applied_server_profile_uri=$applied_server_profile_uri"
fi
if [[ "$node_capabilities" ]]; then
node_capabilities+=","
else
node_capabilities+=" --property capabilities="
fi
node_capabilities+="server_hardware_type_uri:$server_hardware_type_uri,"
node_capabilities+="enclosure_group_uri:$enclosure_group_uri,"
node_capabilities+="server_profile_template_uri:$server_profile_template_uri"
elif is_deployed_by_ilo; then
node_options+=" --driver-info ilo_address=$bmc_address \
--driver-info ilo_password=$bmc_passwd \

View File

@ -22,7 +22,6 @@ Hardware Types
drivers/ilo
drivers/ipmitool
drivers/irmc
drivers/oneview
drivers/redfish
drivers/snmp
drivers/ucs

View File

@ -1,343 +0,0 @@
.. _oneview:
==============
OneView driver
==============
.. note::
The `oneview` hardware type, along with related interfaces to support
OneView, have been deprecated, and should be expected to be
removed from ironic in the Stein cycle. Please see
`storyboard <https://storyboard.openstack.org/#!/story/2001924>`_ for
additional details.
Overview
========
HP OneView [1]_ is a single integrated platform, packaged as an appliance that
implements a software-defined approach to managing physical infrastructure.
The appliance supports scenarios such as deploying bare metal servers, for
instance. In this context, the ``HP OneView driver`` for ironic enables the
users of OneView to use ironic as a bare metal provider to their managed
physical hardware.
HPE OneView hardware is supported by the ``oneview`` hardware type.
To provide a bare metal instance there are four components involved in the
process:
* The ironic service
* The ironic-inspector service (if using hardware inspection)
* The ironic hardware type for OneView
* The hpOneView library
* The OneView appliance
The role of ironic is to serve as a bare metal provider to OneView's managed
physical hardware and to provide communication with other necessary OpenStack
services such as Nova and Glance. When ironic receives a boot request, it
works together with the ironic OneView driver to access a machine in OneView,
the ``hpOneView`` being responsible for the communication with the OneView
appliance.
From the Newton release on, OneView drivers enables a new feature called
**dynamic allocation** of nodes [6]_. In this model, the driver allocates
resources in OneView only at boot time, allowing idle resources in ironic
to be used by OneView users, enabling actual resource sharing among ironic
and OneView users.
Since OneView can claim nodes in ``available`` state at any time, a set of
tasks runs periodically to detect nodes in use by OneView. A node in use by
OneView is placed in ``manageable`` state and has maintenance mode set. Once
the node is no longer in use, these tasks will make place them back in
``available`` state and clear maintenance mode.
Prerequisites
=============
* ``OneView appliance`` is the HP physical infrastructure manager to be
integrated with the OneView driver.
Minimum version supported is 2.0.
* ``hpOneView`` is a python package containing a client to manage the
communication between ironic and OneView.
Install the ``hpOneView`` module to enable the communication. Minimum version
required is 4.4.0 but it is recommended to install the most up-to-date
version::
$ pip install "hpOneView>=4.4.0"
* ``ironic-inspector`` if using hardware inspection.
Tested platforms
================
* The OneView appliance used for testing was the OneView 2.0.
* The Enclosure used for testing was the ``BladeSystem c7000 Enclosure G2``.
* The driver should work on HP Proliant Gen8 and Gen9 Servers supported by
OneView 2.0 and above, or any hardware whose network can be managed by
OneView's ServerProfile. It has been tested with the following servers:
- Proliant BL460c Gen8
- Proliant BL460c Gen9
- Proliant BL465c Gen8
- Proliant DL360 Gen9
Notice that for the driver to work correctly with Gen8 and Gen9 DL servers
in general, the hardware also needs to run version 4.2.3 of iLO, with
Redfish enabled.
Hardware Interfaces
===================
The ``oneview`` hardware type supports the following hardware interfaces:
* boot
Supports only ``pxe``. It can be enabled by using the
``[DEFAULT]enabled_boot_interfaces`` option in ``ironic.conf``
as given below:
.. code-block:: ini
[DEFAULT]
enabled_hardware_types = oneview
enabled_boot_interfaces = pxe
* console
Supports only ``no-console``. It can be enabled by using the
``[DEFAULT]enabled_console_interfaces``
option in ``ironic.conf`` as given below:
.. code-block:: ini
[DEFAULT]
enabled_hardware_types = oneview
enabled_console_interfaces = no-console
* deploy
Supports ``oneview-direct`` and ``oneview-iscsi``. The default is
``oneview-iscsi``. They can be enabled by using the
``[DEFAULT]enabled_deploy_interfaces`` option in ``ironic.conf``
as given below:
.. code-block:: ini
[DEFAULT]
enabled_hardware_types = oneview
enabled_deploy_interfaces = oneview-iscsi,oneview-direct
* inspect
Supports ``oneview`` and ``no-inspect``. The default is ``oneview``.
They can be enabled by using the ``[DEFAULT]enabled_inspect_interfaces``
option in ``ironic.conf`` as given below:
.. code-block:: ini
[DEFAULT]
enabled_hardware_types = oneview
enabled_inspect_interfaces = oneview,no-inspect
* management
Supports only ``oneview``. It can be enabled by using the
``[DEFAULT]enabled_management_interfaces`` option in ``ironic.conf`` as
given below:
.. code-block:: ini
[DEFAULT]
enabled_hardware_types = oneview
enabled_management_interfaces = oneview
* power
Supports only ``oneview``. It can be enabled by using the
``[DEFAULT]enabled_power_interfaces`` option in ``ironic.conf`` as given
below:
.. code-block:: ini
[DEFAULT]
enabled_hardware_types = oneview
enabled_power_interfaces = oneview
The ``oneview`` hardware type also supports the standard *network* and
*storage* interfaces.
Here is an example of putting multiple interfaces configuration at once:
.. code-block:: ini
[DEFAULT]
enabled_hardware_types = oneview
enabled_deploy_interfaces = oneview-direct,oneview-iscsi
enabled_inspect_interfaces = oneview
enabled_power_interfaces = oneview
enabled_management_interfaces = oneview
Deploy process with oneview-iscsi deploy interface
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. Admin configures the Proliant baremetal node to use ``oneview-iscsi``
deploy interface.
2. ironic gets a request to deploy a Glance image on the baremetal node.
3. Driver sets the boot device to PXE.
4. Driver powers on the baremetal node.
5. ironic downloads the deploy and user images from a TFTP server.
6. Driver reboots the baremetal node.
7. User image is now deployed.
8. Driver powers off the machine.
9. Driver sets boot device to Disk.
10. Driver powers on the machine.
11. Baremetal node is active and ready to be used.
Deploy process with oneview-direct deploy interface
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. Admin configures the Proliant baremetal node to use ``oneview-direct``
deploy interface.
2. ironic gets a request to deploy a Glance image on the baremetal node.
3. Driver sets the boot device to PXE.
4. Driver powers on the baremetal node.
5. Node downloads the agent deploy images.
6. Agent downloads the user images and writes it to disk.
7. Driver reboots the baremetal node.
8. User image is now deployed.
9. Driver powers off the machine.
10. Driver sets boot device to Disk.
11. Driver powers on the machine.
12. Baremetal node is active and ready to be used.
Hardware inspection
===================
The OneView driver for ironic has the ability to do hardware inspection.
Hardware inspection is the process of discovering hardware properties like
memory size, CPU cores, processor architecture and disk size, of a given
hardware. The OneView driver does in-band inspection, that involves booting a
ramdisk on the hardware and fetching information directly from it. For that,
your cloud controller needs to have the ``ironic-inspector`` component
[9]_ running and properly enabled in ironic's configuration file.
See [10]_ for more information on how to install and configure
``ironic-inspector``.
Registering a OneView node in ironic
====================================
Nodes configured to use the OneView driver should have the ``driver``
property set to ``oneview``. Considering our context, a node is the
representation of a ``Server Hardware`` in OneView,
and should be consistent with all its properties and related components, such
as ``Server Hardware Type``, ``Server Profile Template``, ``Enclosure Group``,
etc. In this case, to be enrolled, the node must have the following parameters:
* In ``driver_info``
- ``server_hardware_uri``: URI of the ``Server Hardware`` on OneView.
* In ``properties/capabilities``
- ``server_hardware_type_uri``: URI of the ``Server Hardware Type`` of the
``Server Hardware``.
- ``server_profile_template_uri``: URI of the ``Server Profile Template`` used
to create the ``Server Profile`` of the ``Server Hardware``.
- ``enclosure_group_uri`` (optional): URI of the ``Enclosure Group`` of the
``Server Hardware``.
To enroll a node with the OneView driver using default values for the
supported hardware interfaces, do::
$ openstack baremetal node create --driver oneview
To enroll a node with the OneView driver using specific hardware
interfaces, do::
$ openstack baremetal node create --driver oneview \
--deploy-interface oneview-direct \
--power-interface oneview
To update the ``driver_info`` field of a newly enrolled OneView node, do::
$ openstack baremetal node set $NODE_UUID --driver-info server_hardware_uri=$SH_URI
To update the ``properties/capabilities`` namespace of a newly enrolled
OneView node, do::
$ openstack baremetal node set $NODE_UUID \
--property capabilities=server_hardware_type_uri:$SHT_URI,enclosure_group_uri:$EG_URI,server_profile_template_uri=$SPT_URI
In order to deploy, ironic will create and apply, at boot time, a ``Server
Profile`` based on the ``Server Profile Template`` specified on the node to the
``Server Hardware`` it represents on OneView. The URI of such ``Server Profile``
will be stored in ``driver_info.applied_server_profile_uri`` field while the
Server is allocated to ironic.
The ``Server Profile Templates`` and, therefore, the ``Server Profiles`` derived
from them MUST comply with the following requirements:
* The option `MAC Address` in the `Advanced` section of
``Server Profile``/``Server Profile Template`` should be set to `Physical`
option;
* Their first `Connection` interface should be:
* Connected to ironic's provisioning network and;
* The `Boot` option should be set to primary.
Node ports should be created considering the **MAC address of the first
Interface** of the given ``Server Hardware``.
To tell ironic which NIC should be connected to the provisioning network, do::
$ openstack baremetal port create --node $NODE_UUID $MAC_ADDRESS
For more information on the enrollment process of an ironic node, see
:ref:`enrollment`.
For more information on the definitions of ``Server Hardware``, ``Server
Profile``, ``Server Profile Template`` and other OneView entities, refer to
[1]_ or browse Help in your OneView appliance menu.
.. note::
Ironic manages OneView machines either when they have
a Server Profile applied by the driver or when they don't have any Server
Profile. Trying to change the power state of the machine in OneView without
first assigning a Server Profile will lead to allowing Ironic to revert the
power state change. Ironic will NOT change the power state of machines
which the Server Profile was applied by another OneView user.
3rd Party Tools
===============
In order to ease user manual tasks, which are often time-consuming, we provide
useful tools that work nicely with the OneView driver.
ironic-oneview-cli
~~~~~~~~~~~~~~~~~~
The ``ironic-oneView`` CLI is a command line interface for management tasks
involving OneView nodes. Its features include a facility to create of ironic
nodes with all required parameters for OneView nodes, creation of Nova flavors
for OneView nodes.
For more details on how Ironic-OneView CLI works and how to set it up, see
[8]_.
ironic-oneviewd
~~~~~~~~~~~~~~~
The ``ironic-oneviewd`` daemon monitors the ironic inventory of resources and
provides facilities to operators managing OneView driver deployments.
For more details on how Ironic-OneViewd works and how to set it up, see [7]_.
References
==========
.. [1] HP OneView - https://www.hpe.com/us/en/integrated-systems/software.html
.. [6] Dynamic Allocation in OneView drivers - https://specs.openstack.org/openstack/ironic-specs/specs/not-implemented/oneview-drivers-dynamic-allocation.html
.. [7] ironic-oneviewd - https://pypi.org/project/ironic-oneviewd/
.. [8] ironic-oneview-cli - https://pypi.org/project/ironic-oneview-cli/
.. [9] ironic-inspector - https://docs.openstack.org/ironic-inspector/latest/
.. [10] ironic-inspector install - https://docs.openstack.org/ironic-inspector/latest/install/index.html

View File

@ -11,10 +11,9 @@ to the target disk.
iSCSI deploy
============
With ``iscsi`` deploy interface (and also ``oneview-iscsi``, specific to the
``oneview`` hardware type) the deploy ramdisk publishes the node's hard drive
as an iSCSI_ share. The ironic-conductor then copies the image to this share.
See :ref:`iSCSI deploy diagram <iscsi-deploy-example>` for a detailed
With ``iscsi`` deploy interface, the deploy ramdisk publishes the node's hard
drive as an iSCSI_ share. The ironic-conductor then copies the image to this
share. See :ref:`iSCSI deploy diagram <iscsi-deploy-example>` for a detailed
explanation of how this deploy interface works.
This interface is used by default, if enabled (see
@ -31,8 +30,7 @@ when creating or updating a node::
Direct deploy
=============
With ``direct`` deploy interface (and also ``oneview-direct``, specific to the
``oneview`` hardware type), the deploy ramdisk fetches the image from an
With ``direct`` deploy interface, the deploy ramdisk fetches the image from an
HTTP location. It can be an object storage (swift or RadosGW) temporary URL or
a user-provided HTTP URL. The deploy ramdisk then copies the image to the
target disk. See :ref:`direct deploy diagram <direct-deploy-example>` for
@ -94,7 +92,7 @@ While somewhat more complex to set up, this deploy interface provides greater
flexibility in terms of advanced node preparation during provisioning.
This interface is supported by most but not all hardware types declared
in ironic (for example, ``oneview`` hardware type does not support it).
in ironic.
However this deploy interface is not enabled by default.
To enable it, add ``ansible`` to the list of enabled deploy
interfaces in ``enabled_deploy_interfaces`` option in the ``[DEFAULT]``

View File

@ -535,16 +535,6 @@ neutron:
url = None
url_timeout = 30
oneview:
allow_insecure_connections = False
enable_periodic_tasks = True
manager_url = None
max_polling_attempts = 12
password = ***
periodic_check_interval = 300
tls_cacert_file = None
username = None
oslo_concurrency:
disable_process_locking = False
lock_path = None

View File

@ -22,11 +22,9 @@ agent_ilo ilo ilo-virtual-media direct
agent_ipmitool ipmi pxe direct inspector ipmitool ipmitool
agent_ipmitool_socat ipmi pxe direct inspector ipmitool ipmitool
agent_irmc irmc irmc-virtual-media direct irmc irmc irmc
agent_pxe_oneview oneview pxe oneview-direct oneview oneview oneview
agent_ucs cisco-ucs-managed pxe direct inspector ucsm ucsm
iscsi_ilo ilo ilo-virtual-media iscsi ilo ilo ilo
iscsi_irmc irmc irmc-virtual-media iscsi irmc irmc irmc
iscsi_pxe_oneview oneview pxe oneview-iscsi oneview oneview oneview
pxe_agent_cimc cisco-ucs-standalone pxe direct inspector cimc cimc
pxe_drac idrac pxe iscsi idrac idrac idrac
pxe_drac_inspector idrac pxe iscsi inspector idrac idrac

View File

@ -7,10 +7,7 @@
proliantutils>=2.6.0
pysnmp>=4.3.0,<5.0.0
python-ironic-inspector-client>=1.5.0
python-oneviewclient<3.0.0,>=2.5.2
python-scciclient>=0.8.0
python-ilorest-library>=2.1.0
hpOneView>=4.4.0
UcsSdk==0.8.2.2
python-dracclient>=1.3.0
python-xclarityclient>=0.1.6

View File

@ -693,15 +693,6 @@ class CIMCException(DriverOperationError):
_msg_fmt = _("Cisco IMC exception occurred for node %(node)s: %(error)s")
class OneViewError(DriverOperationError):
_msg_fmt = _("OneView exception occurred. Error: %(error)s")
class OneViewInvalidNodeParameter(OneViewError):
_msg_fmt = _("Error while obtaining OneView info from node %(node_uuid)s. "
"Error: %(error)s")
class NodeTagNotFound(IronicException):
_msg_fmt = _("Node %(node_id)s doesn't have a tag '%(tag)s'")

View File

@ -38,7 +38,6 @@ from ironic.conf import iscsi
from ironic.conf import metrics
from ironic.conf import metrics_statsd
from ironic.conf import neutron
from ironic.conf import oneview
from ironic.conf import pxe
from ironic.conf import redfish
from ironic.conf import service_catalog
@ -71,7 +70,6 @@ iscsi.register_opts(CONF)
metrics.register_opts(CONF)
metrics_statsd.register_opts(CONF)
neutron.register_opts(CONF)
oneview.register_opts(CONF)
pxe.register_opts(CONF)
redfish.register_opts(CONF)
service_catalog.register_opts(CONF)

View File

@ -1,50 +0,0 @@
# Copyright 2016 Intel Corporation
# Copyright 2015 Hewlett Packard Development Company, LP
# Copyright 2015 Universidade Federal de Campina Grande
#
# 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 oslo_config import cfg
from ironic.common.i18n import _
opts = [
cfg.StrOpt('manager_url',
help=_('URL where OneView is available.')),
cfg.StrOpt('username',
help=_('OneView username to be used.')),
cfg.StrOpt('password',
secret=True,
help=_('OneView password to be used.')),
cfg.BoolOpt('allow_insecure_connections',
default=False,
help=_('Option to allow insecure connection with OneView.')),
cfg.StrOpt('tls_cacert_file',
help=_('Path to CA certificate.')),
cfg.BoolOpt('enable_periodic_tasks',
default=True,
help=_('Whether to enable the periodic tasks for OneView '
'driver be aware when OneView hardware resources are '
'taken and released by Ironic or OneView users '
'and proactively manage nodes in clean fail state '
'according to Dynamic Allocation model of hardware '
'resources allocation in OneView.')),
cfg.IntOpt('periodic_check_interval',
default=300,
help=_('Period (in seconds) for periodic tasks to be '
'executed when enable_periodic_tasks=True.')),
]
def register_opts(conf):
conf.register_opts(opts, group='oneview')

View File

@ -56,7 +56,6 @@ _opts = [
('metrics', ironic.conf.metrics.opts),
('metrics_statsd', ironic.conf.metrics_statsd.opts),
('neutron', ironic.conf.neutron.list_opts()),
('oneview', ironic.conf.oneview.opts),
('pxe', ironic.conf.pxe.opts),
('service_catalog', ironic.conf.service_catalog.list_opts()),
('snmp', ironic.conf.snmp.opts),

View File

@ -1,553 +0,0 @@
# Copyright (2015-2017) Hewlett Packard Enterprise Development LP
# Copyright (2015-2017) Universidade Federal de Campina Grande
#
# 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 re
from oslo_log import log as logging
from oslo_serialization import jsonutils
from oslo_utils import importutils
from six.moves.urllib import parse
from ironic.common import exception
from ironic.common.i18n import _
from ironic.conf import CONF
from ironic.drivers import utils
LOG = logging.getLogger(__name__)
hponeview_client = importutils.try_import('hpOneView.oneview_client')
redfish = importutils.try_import('redfish')
client_exception = importutils.try_import('hpOneView.exceptions')
REQUIRED_ON_DRIVER_INFO = {
'server_hardware_uri': _("Server Hardware URI. Required in driver_info."),
}
REQUIRED_ON_PROPERTIES = {
'server_hardware_type_uri': _(
"Server Hardware Type URI. Required in properties/capabilities."
),
'server_profile_template_uri': _(
"Server Profile Template URI to clone from. "
"Required in properties/capabilities."
),
}
OPTIONAL_ON_PROPERTIES = {
'enclosure_group_uri': _(
"Enclosure Group URI. Optional in properties/capabilities."),
}
ILOREST_BASE_PORT = "443"
COMMON_PROPERTIES = {}
COMMON_PROPERTIES.update(REQUIRED_ON_DRIVER_INFO)
COMMON_PROPERTIES.update(REQUIRED_ON_PROPERTIES)
COMMON_PROPERTIES.update(OPTIONAL_ON_PROPERTIES)
# NOTE(xavierr): We don't want to translate NODE_IN_USE_BY_ONEVIEW and
# SERVER_HARDWARE_ALLOCATION_ERROR to avoid inconsistency in the nodes
# caused by updates on translation in upgrades of ironic.
NODE_IN_USE_BY_ONEVIEW = 'node in use by OneView'
SERVER_HARDWARE_ALLOCATION_ERROR = 'server hardware allocation error'
def prepare_manager_url(manager_url):
# NOTE(mrtenio) python-oneviewclient uses https or http in the manager_url
# while python-hpOneView does not. This will not be necessary when
# python-hpOneView client is the only OneView library.
if manager_url:
url_match = "^(http[s]?://)?([^/]+)(/.*)?$"
manager_url = re.search(url_match, manager_url).group(2)
return manager_url
def get_hponeview_client():
"""Generate an instance of the hpOneView client.
Generates an instance of the hpOneView client using the hpOneView library.
:returns: an instance of the OneViewClient
:raises: InvalidParameterValue if mandatory information is missing on the
node or on invalid input.
:raises: OneViewError if try a secure connection without CA certificate.
"""
manager_url = prepare_manager_url(CONF.oneview.manager_url)
insecure = CONF.oneview.allow_insecure_connections
ssl_certificate = CONF.oneview.tls_cacert_file
if not (insecure or ssl_certificate):
msg = _("TLS CA certificate to connect with OneView is missing.")
raise exception.OneViewError(error=msg)
# NOTE(nicodemos) Ignore the CA certificate if it's an insecure connection
if insecure and ssl_certificate:
LOG.warning("Performing an insecure connection with OneView, the CA "
"certificate file: %s will be ignored.", ssl_certificate)
ssl_certificate = None
config = {
"ip": manager_url,
"credentials": {
"userName": CONF.oneview.username,
"password": CONF.oneview.password
},
"ssl_certificate": ssl_certificate
}
return hponeview_client.OneViewClient(config)
def get_ilorest_client(server_hardware):
"""Generate an instance of the iLORest library client.
:param: server_hardware: a server hardware uuid or uri
:returns: an instance of the iLORest client
:raises: InvalidParameterValue if mandatory information is missing on the
node or on invalid input.
"""
oneview_client = get_hponeview_client()
remote_console = oneview_client.server_hardware.get_remote_console_url(
server_hardware
)
host_ip, ilo_token = _get_ilo_access(remote_console)
base_url = "https://%s:%s" % (host_ip, ILOREST_BASE_PORT)
return redfish.rest_client(base_url=base_url, sessionkey=ilo_token)
def _get_ilo_access(remote_console):
"""Get the needed information to access ilo.
Get the host_ip and a token of an iLO remote console instance which can be
used to perform operations on that controller.
The Remote Console url has the following format:
hplocons://addr=1.2.3.4&sessionkey=a79659e3b3b7c8209c901ac3509a6719
:param remote_console: OneView Remote Console object with a
remoteConsoleUrl
:returns: A tuple with the Host IP and Token to access ilo, for
example: ('1.2.3.4', 'a79659e3b3b7c8209c901ac3509a6719')
"""
url = remote_console.get('remoteConsoleUrl')
url_parse = parse.urlparse(url)
host_ip = parse.parse_qs(url_parse.netloc).get('addr')[0]
token = parse.parse_qs(url_parse.netloc).get('sessionkey')[0]
return host_ip, token
def verify_node_info(node):
"""Verifies if fields and namespaces of a node are valid.
Verifies if the 'driver_info' field and the 'properties/capabilities'
namespace exist and are not empty.
:param: node: node object to be verified
:raises: InvalidParameterValue if required node capabilities and/or
driver_info are malformed or missing
:raises: MissingParameterValue if required node capabilities and/or
driver_info are missing
"""
capabilities_dict = utils.capabilities_to_dict(
node.properties.get('capabilities', '')
)
driver_info = node.driver_info
_verify_node_info('properties/capabilities', capabilities_dict,
REQUIRED_ON_PROPERTIES)
_verify_node_info('driver_info', driver_info,
REQUIRED_ON_DRIVER_INFO)
def get_oneview_info(node):
"""Gets OneView information from the node.
:param: node: node object to get information from
:returns: a dictionary containing:
:param server_hardware_uri: the uri of the server hardware in OneView
:param server_hardware_type_uri: the uri of the server hardware type in
OneView
:param enclosure_group_uri: the uri of the enclosure group in OneView
:server_profile_template_uri: the uri of the server profile template in
OneView
:raises: OneViewInvalidNodeParameter if node capabilities are malformed
"""
try:
capabilities_dict = utils.capabilities_to_dict(
node.properties.get('capabilities', '')
)
except exception.InvalidParameterValue as e:
raise exception.OneViewInvalidNodeParameter(node_uuid=node.uuid,
error=e)
driver_info = node.driver_info
oneview_info = {
'server_hardware_uri':
driver_info.get('server_hardware_uri'),
'server_hardware_type_uri':
capabilities_dict.get('server_hardware_type_uri'),
'enclosure_group_uri':
capabilities_dict.get('enclosure_group_uri'),
'server_profile_template_uri':
capabilities_dict.get('server_profile_template_uri'),
'applied_server_profile_uri':
driver_info.get('applied_server_profile_uri'),
}
return oneview_info
def validate_oneview_resources_compatibility(task):
"""Validate if the node configuration is consistent with OneView.
This method calls hpOneView functions to validate if the node
configuration is consistent with the OneView resources it represents,
including serverHardwareUri, serverHardwareTypeUri, serverGroupUri
serverProfileTemplateUri, enclosureGroupUri and node ports. If any
validation fails, the driver will raise an appropriate OneViewError.
:param task: a TaskManager instance containing the node to act on.
:raises: OneViewError if any validation fails.
"""
ports = task.ports
oneview_client = get_hponeview_client()
oneview_info = get_oneview_info(task.node)
_validate_node_server_profile_template(oneview_client, oneview_info)
_validate_node_server_hardware_type(oneview_client, oneview_info)
_validate_node_enclosure_group(oneview_client, oneview_info)
_validate_server_profile_template_mac_type(oneview_client, oneview_info)
_validate_node_port_mac_server_hardware(
oneview_client, oneview_info, ports)
def _verify_node_info(node_namespace, node_info_dict, info_required):
"""Verify if info_required is present in node_namespace of the node info.
"""
missing_keys = set(info_required) - set(node_info_dict)
if missing_keys:
raise exception.MissingParameterValue(
_("Missing the keys for the following OneView data in node's "
"%(namespace)s: %(missing_keys)s.") %
{'namespace': node_namespace,
'missing_keys': ', '.join(missing_keys)
}
)
# False and 0 can still be considered as valid values
missing_values_keys = [k for k in info_required
if node_info_dict[k] in ('', None)]
if missing_values_keys:
missing_keys = ["%s:%s" % (node_namespace, k)
for k in missing_values_keys]
raise exception.MissingParameterValue(
_("Missing parameter value for: '%s'") % "', '".join(missing_keys)
)
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):
task = args[0]
ensure_server_profile(task)
return func(self, *args, **kwargs)
return inner
def ensure_server_profile(task):
"""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 task: a TaskManager instance containing the node to act on.
:raises: OneViewError if failed to get server profile from OneView
"""
oneview_client = get_hponeview_client()
try:
profile_uri = task.node.driver_info.get('applied_server_profile_uri')
oneview_client.server_profiles.get(profile_uri)
except client_exception.HPOneViewException as exc:
LOG.error(
"Failed to get server profile: %(profile)s from OneView appliance "
"for node %(node)s. Error: %(message)s", {
"profile": profile_uri,
"node": task.node.uuid,
"message": exc
}
)
raise exception.OneViewError(error=exc)
def _get_server_hardware_mac_from_ilo(server_hardware):
"""Get the MAC of Server Hardware's iLO controller.
:param: server_hardware: a server hardware uuid or uri
:returns: MAC of Server Hardware's iLO controller.
:raises: InvalidParameterValue if required iLO credentials are missing.
:raises: OneViewError if can't get mac from a server hardware via iLO or
if fails to get JSON object with the default path.
"""
try:
ilo_client = get_ilorest_client(server_hardware)
ilo_path = "/rest/v1/systems/1"
hardware = jsonutils.loads(ilo_client.get(ilo_path).text)
hardware_mac = hardware['HostCorrelation']['HostMACAddress'][0]
except redfish.JsonDecodingError as exc:
LOG.error("Failed in JSON object getting path: %s", ilo_path)
raise exception.OneViewError(error=exc)
except (ValueError, TypeError, IndexError) as exc:
LOG.exception(
"Failed to get mac from server hardware %(server_hardware)s "
"via iLO. Error: %(message)s", {
"server_hardware": server_hardware.get("uri"),
"message": exc
}
)
raise exception.OneViewError(error=exc)
return hardware_mac
def _get_server_hardware_mac(server_hardware):
"""Get the MAC address of the first PXE bootable port of an Ethernet port.
:param server_hardware: OneView Server Hardware object.
:returns: MAC of the first Ethernet and function 'a' port of the
Server Hardware object.
:raises: OneViewError if there is no Ethernet port on the Server Hardware
or if there is no portMap on the Server Hardware requested.
"""
sh_physical_port = None
if server_hardware.get('portMap'):
for device in server_hardware.get(
'portMap', {}).get('deviceSlots', ()):
for physical_port in device.get('physicalPorts', ()):
if physical_port.get('type') == 'Ethernet':
sh_physical_port = physical_port
break
if sh_physical_port:
for virtual_port in sh_physical_port.get('virtualPorts', ()):
# NOTE(nicodemos): Ironic oneview drivers needs to use a
# port that type is Ethernet and function identifier 'a' for
# this FlexNIC to be able to make a deploy using PXE.
if virtual_port.get('portFunction') == 'a':
return virtual_port.get('mac', ()).lower()
raise exception.OneViewError(
_("There is no Ethernet port on the Server Hardware: %s") %
server_hardware.get('uri'))
else:
raise exception.OneViewError(
_("The Server Hardware: %s doesn't have a list of adapters/slots, "
"their ports and attributes. This information is available only "
"for blade servers. Is this a rack server?") %
server_hardware.get('uri'))
def _validate_node_server_profile_template(oneview_client, oneview_info):
"""Validate if the Server Profile Template is consistent.
:param oneview_client: an instance of the HPE OneView client.
:param oneview_info: the OneView related info in an Ironic node.
:raises: OneViewError if the node's Server Profile Template is not
consistent.
"""
server_profile_template = oneview_client.server_profile_templates.get(
oneview_info['server_profile_template_uri'])
server_hardware = oneview_client.server_hardware.get(
oneview_info['server_hardware_uri'])
_validate_server_profile_template_server_hardware_type(
server_profile_template, server_hardware)
_validate_spt_enclosure_group(server_profile_template, server_hardware)
_validate_server_profile_template_manage_boot(server_profile_template)
def _validate_server_profile_template_server_hardware_type(
server_profile_template, server_hardware):
"""Validate if the Server Hardware Types are the same.
Validate if the Server Profile Template and the Server Hardware have the
same Server Hardware Type.
:param server_profile_template: OneView Server Profile Template object.
:param server_hardware: OneView Server Hardware object.
:raises: OneViewError if the Server Profile Template and the Server
Hardware does not have the same Server Hardware Type.
"""
spt_server_hardware_type_uri = (
server_profile_template.get('serverHardwareTypeUri')
)
sh_server_hardware_type_uri = server_hardware.get('serverHardwareTypeUri')
if spt_server_hardware_type_uri != sh_server_hardware_type_uri:
message = _(
"Server profile template %(spt_uri)s serverHardwareTypeUri is "
"inconsistent with server hardware %(server_hardware_uri)s "
"serverHardwareTypeUri.") % {
'spt_uri': server_profile_template.get('uri'),
'server_hardware_uri': server_hardware.get('uri')}
raise exception.OneViewError(message)
def _validate_spt_enclosure_group(server_profile_template, server_hardware):
"""Validate Server Profile Template's Enclosure Group and Hardware's.
:param server_profile_template: OneView Server Profile Template object.
:param server_hardware: OneView Server Hardware object.
:raises: OneViewError if the Server Profile Template's Enclosure Group does
not match the Server Hardware's.
"""
spt_enclosure_group_uri = server_profile_template.get('enclosureGroupUri')
sh_enclosure_group_uri = server_hardware.get('serverGroupUri')
if spt_enclosure_group_uri != sh_enclosure_group_uri:
message = _("Server profile template %(spt_uri)s enclosureGroupUri is "
"inconsistent with server hardware %(sh_uri)s "
"serverGroupUri.") % {
'spt_uri': server_profile_template.get('uri'),
'sh_uri': server_hardware.get('uri')}
raise exception.OneViewError(message)
def _validate_server_profile_template_manage_boot(server_profile_template):
"""Validate if the Server Profile Template allows to manage the boot order.
:param server_profile_template: OneView Server Profile Template object.
:raises: OneViewError if the Server Profile Template does not allows to
manage the boot order.
"""
manage_boot = server_profile_template.get('boot', {}).get('manageBoot')
if not manage_boot:
message = _("Server Profile Template: %s, does not allow to manage "
"boot order.") % server_profile_template.get('uri')
raise exception.OneViewError(message)
def _validate_node_server_hardware_type(oneview_client, oneview_info):
"""Validate if the node's Server Hardware Type matches Server Hardware's.
:param: oneview_client: the HPE OneView Client.
:param: oneview_info: the OneView related info in an Ironic node.
:raises: OneViewError if the node's Server Hardware Type group doesn't
match the Server Hardware's.
"""
node_server_hardware_type_uri = oneview_info['server_hardware_type_uri']
server_hardware = oneview_client.server_hardware.get(
oneview_info['server_hardware_uri'])
server_hardware_sht_uri = server_hardware.get('serverHardwareTypeUri')
if server_hardware_sht_uri != node_server_hardware_type_uri:
message = _("Node server_hardware_type_uri is inconsistent "
"with OneView's server hardware %(server_hardware_uri)s "
"serverHardwareTypeUri.") % {
'server_hardware_uri': server_hardware.get('uri')}
raise exception.OneViewError(message)
def _validate_node_enclosure_group(oneview_client, oneview_info):
"""Validate if the node's Enclosure Group matches the Server Hardware's.
:param oneview_client: an instance of the HPE OneView client.
:param oneview_info: the OneView related info in an Ironic node.
:raises: OneViewError if the node's enclosure group doesn't match the
Server Hardware's.
"""
server_hardware = oneview_client.server_hardware.get(
oneview_info['server_hardware_uri'])
sh_enclosure_group_uri = server_hardware.get('serverGroupUri')
node_enclosure_group_uri = oneview_info['enclosure_group_uri']
if node_enclosure_group_uri and (
sh_enclosure_group_uri != node_enclosure_group_uri):
message = _(
"Node enclosure_group_uri '%(node_enclosure_group_uri)s' "
"is inconsistent with OneView's server hardware "
"serverGroupUri '%(sh_enclosure_group_uri)s' of "
"ServerHardware %(server_hardware)s") % {
'node_enclosure_group_uri': node_enclosure_group_uri,
'sh_enclosure_group_uri': sh_enclosure_group_uri,
'server_hardware': server_hardware.get('uri')}
raise exception.OneViewError(message)
def _validate_node_port_mac_server_hardware(oneview_client,
oneview_info, ports):
"""Validate if a port matches the node's Server Hardware's MAC.
:param oneview_client: an instance of the HPE OneView client.
:param oneview_info: the OneView related info in an Ironic node.
:param ports: a list of Ironic node's ports.
:raises: OneViewError if there is no port with MAC address matching one
in OneView.
"""
server_hardware = oneview_client.server_hardware.get(
oneview_info['server_hardware_uri'])
if not ports:
return
# NOTE(nicodemos) If hponeview client's unable to get the MAC of the Server
# Hardware and raises an exception, the driver will try to get it from
# the iLOrest client.
try:
mac = _get_server_hardware_mac(server_hardware)
except exception.OneViewError:
mac = _get_server_hardware_mac_from_ilo(server_hardware)
incompatible_macs = []
for port in ports:
if port.address.lower() == mac.lower():
return
incompatible_macs.append(port.address)
message = _("The ports of the node are not compatible with its "
"server hardware %(server_hardware_uri)s. There are no Ironic "
"port MAC's: %(port_macs)s, that matches with the "
"server hardware's MAC: %(server_hardware_mac)s") % {
'server_hardware_uri': server_hardware.get('uri'),
'port_macs': ', '.join(incompatible_macs),
'server_hardware_mac': mac}
raise exception.OneViewError(message)
def _validate_server_profile_template_mac_type(oneview_client, oneview_info):
"""Validate if the node's Server Profile Template's MAC type is physical.
:param oneview_client: an instance of the HPE OneView client.
:param oneview_info: the OneView related info in an Ironic node.
:raises: OneViewError if the node's Server Profile Template's MAC type is
not physical.
"""
server_profile_template = oneview_client.server_profile_templates.get(
oneview_info['server_profile_template_uri']
)
if server_profile_template.get('macType') != 'Physical':
message = _("The server profile template %s is not set to use "
"physical MAC.") % server_profile_template.get('uri')
raise exception.OneViewError(message)

View File

@ -1,308 +0,0 @@
# Copyright (2015-2017) Hewlett Packard Enterprise Development LP
# Copyright (2015-2017) Universidade Federal de Campina Grande
#
# 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 abc
from futurist import periodics
from ironic_lib import metrics_utils
from oslo_log import log as logging
import six
from ironic.common import exception
from ironic.common import states
from ironic.conductor import utils
from ironic.conf import CONF
from ironic.drivers.modules import agent
from ironic.drivers.modules import iscsi_deploy
from ironic.drivers.modules.oneview import common
from ironic.drivers.modules.oneview import deploy_utils
from ironic import objects
LOG = logging.getLogger(__name__)
METRICS = metrics_utils.get_metrics_logger(__name__)
@six.add_metaclass(abc.ABCMeta)
class OneViewPeriodicTasks(object):
@periodics.periodic(spacing=CONF.oneview.periodic_check_interval,
enabled=CONF.oneview.enable_periodic_tasks
and CONF.oneview.periodic_check_interval > 0)
def _periodic_check_nodes_taken_by_oneview(self, manager, context):
"""Checks if nodes in Ironic were taken by OneView users.
This driver periodic task will check for nodes that were taken by
OneView users while the node is in available state, set the node to
maintenance mode with an appropriate maintenance reason message and
move the node to manageable state.
:param manager: a ConductorManager instance
:param context: request context
:returns: None.
"""
filters = {
'provision_state': states.AVAILABLE,
'maintenance': False,
'driver': 'oneview'
}
node_iter = manager.iter_nodes(filters=filters)
for node_uuid, driver, conductor_group in node_iter:
node = objects.Node.get(context, node_uuid)
try:
oneview_using = deploy_utils.is_node_in_use_by_oneview(node)
except exception.OneViewError as e:
# NOTE(xavierr): Skip this node and process the
# remaining nodes. This node will be checked in
# the next periodic call.
LOG.error("Error while determining if node "
"%(node_uuid)s is in use by OneView. "
"Error: %(error)s",
{'node_uuid': node.uuid, 'error': e})
continue
if oneview_using:
purpose_msg = ('Updating node %(node_uuid)s in use '
'by OneView from %(provision_state)s state '
'to %(target_state)s state and maintenance '
'mode %(maintenance)s.')
purpose_data = {'node_uuid': node_uuid,
'provision_state': states.AVAILABLE,
'target_state': states.MANAGEABLE,
'maintenance': True}
LOG.info(purpose_msg, purpose_data)
node.maintenance = True
node.maintenance_reason = common.NODE_IN_USE_BY_ONEVIEW
manager.update_node(context, node)
manager.do_provisioning_action(context, node.uuid, 'manage')
@periodics.periodic(spacing=CONF.oneview.periodic_check_interval,
enabled=CONF.oneview.enable_periodic_tasks
and CONF.oneview.periodic_check_interval > 0)
def _periodic_check_nodes_freed_by_oneview(self, manager, context):
"""Checks if nodes taken by OneView users were freed.
This driver periodic task will be responsible to poll the nodes that
are in maintenance mode and on manageable state to check if the Server
Profile was removed, indicating that the node was freed by the OneView
user. If so, it'll provide the node, that will pass through the
cleaning process and become available to be provisioned.
:param manager: a ConductorManager instance
:param context: request context
:returns: None.
"""
filters = {
'provision_state': states.MANAGEABLE,
'maintenance': True,
'driver': 'oneview'
}
node_iter = manager.iter_nodes(fields=['maintenance_reason'],
filters=filters)
for (node_uuid, driver, conductor_group,
maintenance_reason) in node_iter:
if maintenance_reason == common.NODE_IN_USE_BY_ONEVIEW:
node = objects.Node.get(context, node_uuid)
try:
oneview_using = deploy_utils.is_node_in_use_by_oneview(
node
)
except exception.OneViewError as e:
# NOTE(xavierr): Skip this node and process the
# remaining nodes. This node will be checked in
# the next periodic call.
LOG.error("Error while determining if node "
"%(node_uuid)s is in use by OneView. "
"Error: %(error)s",
{'node_uuid': node.uuid, 'error': e})
continue
if not oneview_using:
purpose_msg = ('Bringing node %(node_uuid)s back from '
'use by OneView from %(provision_state)s '
'state to %(target_state)s state and '
'maintenance mode %(maintenance)s.')
purpose_data = {'node_uuid': node_uuid,
'provision_state': states.MANAGEABLE,
'target_state': states.AVAILABLE,
'maintenance': False}
LOG.info(purpose_msg, purpose_data)
node.maintenance = False
node.maintenance_reason = None
manager.update_node(context, node)
manager.do_provisioning_action(
context, node.uuid, 'provide'
)
@periodics.periodic(spacing=CONF.oneview.periodic_check_interval,
enabled=CONF.oneview.enable_periodic_tasks)
def _periodic_check_nodes_taken_on_cleanfail(self, manager, context):
"""Checks failed deploys due to Oneview users taking Server Hardware.
This last driver periodic task will take care of nodes that would be
caught on a race condition between OneView and a deploy by Ironic. In
such cases, the validation will fail, throwing the node on deploy fail
and, afterwards on clean fail.
This task will set the node to maintenance mode with a proper reason
message and move it to manageable state, from where the second task
can rescue the node as soon as the Server Profile is removed.
:param manager: a ConductorManager instance
:param context: request context
:returns: None.
"""
filters = {
'provision_state': states.CLEANFAIL,
'driver': 'oneview'
}
node_iter = manager.iter_nodes(fields=['driver_internal_info'],
filters=filters)
for (node_uuid, driver, conductor_group,
driver_internal_info) in node_iter:
node_oneview_error = driver_internal_info.get('oneview_error')
if node_oneview_error == common.SERVER_HARDWARE_ALLOCATION_ERROR:
node = objects.Node.get(context, node_uuid)
purpose_msg = ('Bringing node %(node_uuid)s back from use '
'by OneView from %(provision_state)s state '
'to %(target_state)s state and '
'maintenance mode %(maintenance)s.')
purpose_dict = {'node_uuid': node_uuid,
'provision_state': states.CLEANFAIL,
'target_state': states.MANAGEABLE,
'maintenance': False}
LOG.info(purpose_msg, purpose_dict)
node.maintenance = True
node.maintenance_reason = common.NODE_IN_USE_BY_ONEVIEW
driver_internal_info = node.driver_internal_info
driver_internal_info.pop('oneview_error', None)
node.driver_internal_info = driver_internal_info
manager.update_node(context, node)
manager.do_provisioning_action(context, node.uuid, 'manage')
class OneViewIscsiDeploy(iscsi_deploy.ISCSIDeploy, OneViewPeriodicTasks):
"""Class for OneView ISCSI deployment driver."""
# NOTE(TheJulia): Marking as unsupported as 3rd party CI was taken down
# shortly before the beginning of the Rocky cycle, and no replies have
# indicated that 3rd party CI will be re-established nor visible
# actions observed regarding re-establishing 3rd party CI.
# TODO(TheJulia): This should be expected to be removed in Stein.
supported = False
def get_properties(self):
return deploy_utils.get_properties()
@METRICS.timer('OneViewIscsiDeploy.validate')
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)
@METRICS.timer('OneViewIscsiDeploy.prepare')
def prepare(self, task):
deploy_utils.prepare(task)
super(OneViewIscsiDeploy, self).prepare(task)
@METRICS.timer('OneViewIscsiDeploy.tear_down')
def tear_down(self, task):
# teardown if automated clean is disabled on the node
# or if general automated clean is not enabled generally
# and not on the node as well
if utils.skip_automated_cleaning(task.node):
deploy_utils.tear_down(task)
return super(OneViewIscsiDeploy, self).tear_down(task)
@METRICS.timer('OneViewIscsiDeploy.prepare_cleaning')
def prepare_cleaning(self, task):
deploy_utils.prepare_cleaning(task)
return super(OneViewIscsiDeploy, self).prepare_cleaning(task)
@METRICS.timer('OneViewIscsiDeploy.tear_down_cleaning')
def tear_down_cleaning(self, task):
deploy_utils.tear_down_cleaning(task)
super(OneViewIscsiDeploy, self).tear_down_cleaning(task)
class OneViewAgentDeploy(agent.AgentDeploy, OneViewPeriodicTasks):
"""Class for OneView Agent deployment driver."""
# NOTE(TheJulia): Marking as unsupported as 3rd party CI was taken down
# shortly before the beginning of the Rocky cycle, and no replies have
# indicated that 3rd party CI will be re-established nor visible
# actions observed regarding re-establishing 3rd party CI.
# TODO(TheJulia): This should be expected to be removed in Stein.
supported = False
def get_properties(self):
return deploy_utils.get_properties()
@METRICS.timer('OneViewAgentDeploy.validate')
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)
@METRICS.timer('OneViewAgentDeploy.prepare')
def prepare(self, task):
deploy_utils.prepare(task)
super(OneViewAgentDeploy, self).prepare(task)
@METRICS.timer('OneViewAgentDeploy.tear_down')
def tear_down(self, task):
# if node specifically has cleanup disabled, or general cleanup
# is disabled and node has not it enabled
if utils.skip_automated_cleaning(task.node):
deploy_utils.tear_down(task)
return super(OneViewAgentDeploy, self).tear_down(task)
@METRICS.timer('OneViewAgentDeploy.prepare_cleaning')
def prepare_cleaning(self, task):
deploy_utils.prepare_cleaning(task)
return super(OneViewAgentDeploy, self).prepare_cleaning(task)
@METRICS.timer('OneViewAgentDeploy.tear_down_cleaning')
def tear_down_cleaning(self, task):
deploy_utils.tear_down_cleaning(task)
super(OneViewAgentDeploy, self).tear_down_cleaning(task)

View File

@ -1,384 +0,0 @@
# Copyright (2015-2017) Hewlett Packard Enterprise Development LP
# Copyright (2015-2017) Universidade Federal de Campina Grande
#
# 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 operator
from oslo_log import log as logging
from oslo_utils import importutils
from ironic.common import exception
from ironic.common.i18n import _
from ironic.common import states
from ironic.drivers.modules.oneview import common
LOG = logging.getLogger(__name__)
client_exception = importutils.try_import('hpOneView.exceptions')
def get_properties():
return common.COMMON_PROPERTIES
def prepare(task):
"""Applies Server Profile and update the node when preparing.
This method is responsible for applying a Server Profile to the Server
Hardware and add the uri of the applied Server Profile in the node's
'applied_server_profile_uri' field on properties/capabilities.
:param task: A TaskManager object
:raises InstanceDeployFailure: If the node doesn't have the needed OneView
informations, if Server Hardware is in use by an OneView user, or
if the Server Profile can't be applied.
"""
if task.node.provision_state == states.DEPLOYING:
try:
instance_display_name = task.node.instance_info.get('display_name')
instance_uuid = task.node.instance_uuid
server_profile_name = (
"%(instance_name)s [%(instance_uuid)s]" %
{"instance_name": instance_display_name,
"instance_uuid": instance_uuid}
)
allocate_server_hardware_to_ironic(task.node, server_profile_name)
except exception.OneViewError as e:
raise exception.InstanceDeployFailure(node=task.node.uuid,
reason=e)
def tear_down(task):
"""Remove Server profile and update the node when tear down.
This method is responsible for power a Server Hardware off, remove a Server
Profile from the Server Hardware and remove the uri of the applied Server
Profile from the node's 'applied_server_profile_uri' in
properties/capabilities.
:param task: A TaskManager object
:raises InstanceDeployFailure: If node has no uri of applied Server
Profile, or if some error occur while deleting Server Profile.
"""
try:
deallocate_server_hardware_from_ironic(task)
except exception.OneViewError as e:
raise exception.InstanceDeployFailure(node=task.node.uuid, reason=e)
def prepare_cleaning(task):
"""Applies Server Profile and update the node when preparing cleaning.
This method is responsible for applying a Server Profile to the Server
Hardware and add the uri of the applied Server Profile in the node's
'applied_server_profile_uri' field on properties/capabilities.
:param task: A TaskManager object
:raises NodeCleaningFailure: If the node doesn't have the needed OneView
informations, if Server Hardware is in use by an OneView user, or
if the Server Profile can't be applied.
"""
try:
server_profile_name = "Ironic Cleaning [%s]" % task.node.uuid
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
driver_internal_info['oneview_error'] = oneview_error
task.node.driver_internal_info = driver_internal_info
task.node.save()
raise exception.NodeCleaningFailure(node=task.node.uuid,
reason=e)
def tear_down_cleaning(task):
"""Remove Server profile and update the node when tear down cleaning.
This method is responsible for power a Server Hardware off, remove a Server
Profile from the Server Hardware and remove the uri of the applied Server
Profile from the node's 'applied_server_profile_uri' in
properties/capabilities.
:param task: A TaskManager object
:raises NodeCleaningFailure: If node has no uri of applied Server Profile,
or if some error occur while deleting Server Profile.
"""
try:
deallocate_server_hardware_from_ironic(task)
except exception.OneViewError as e:
raise exception.NodeCleaningFailure(node=task.node.uuid, reason=e)
def _create_profile_from_template(
oneview_client, server_profile_name,
server_hardware_uri, server_profile_template):
"""Create a server profile from a server profile template.
:param oneview_client: an HPE OneView Client instance
:param server_profile_name: the name of the new server profile
:param server_hardware_uri: the server_hardware assigned to server profile
:param server_profile_template: the server profile template id or uri
:returns: The new server profile generated with the name and server
hardware passed on parameters
:raises OneViewError: if the communication with OneView fails
"""
server_profile = oneview_client.server_profile_templates.get_new_profile(
server_profile_template
)
server_profile['name'] = server_profile_name
server_profile['serverHardwareUri'] = server_hardware_uri
server_profile['serverProfileTemplateUri'] = ""
try:
return oneview_client.server_profiles.create(server_profile)
except client_exception.HPOneViewException as e:
msg = (_("Error while creating a Server Profile for Server Hardware: "
"%(sh_uri)s. Error: %(error)s") %
{'sh_uri': server_hardware_uri, 'error': e})
raise exception.OneViewError(error=msg)
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 server_hardware: Server Hardware object.
:param applied_sp_uri: Server Profile URI applied in the node.
: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.
: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
server_profile_uri = server_hardware.get('serverProfileUri')
return (server_profile_uri
and operation(applied_sp_uri, server_profile_uri))
def is_node_in_use_by_oneview(node):
"""Check if node is in use by OneView user.
:param node: an ironic node object.
: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.
"""
oneview_client = common.get_hponeview_client()
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(oneview_client, 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.
"""
oneview_client = common.get_hponeview_client()
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(oneview_client, node,
predicate, positive, negative)
def _check_applied_server_profile(oneview_client, node,
predicate, positive, negative):
"""Check if node is in use by ironic in OneView.
:param oneview_client: an instance of the OneView client
: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.
"""
oneview_info = common.get_oneview_info(node)
try:
server_hardware = oneview_client.server_hardware.get(
oneview_info.get('server_hardware_uri')
)
except client_exception.HPOneViewResourceNotFound as e:
msg = (_("Error while obtaining Server Hardware from node "
"%(node_uuid)s. Error: %(error)s") %
{'node_uuid': node.uuid, 'error': e})
raise exception.OneViewError(error=msg)
applied_sp_uri = node.driver_info.get('applied_server_profile_uri')
result = predicate(server_hardware, applied_sp_uri)
if result:
LOG.debug(positive)
else:
LOG.debug(negative)
return result
def _add_applied_server_profile_uri_field(node, applied_profile):
"""Adds the applied Server Profile uri to a node.
:param node: an ironic node object
:param applied_profile: the server_profile that will be applied to node
"""
driver_info = node.driver_info
driver_info['applied_server_profile_uri'] = applied_profile.get('uri')
node.driver_info = driver_info
node.save()
def _del_applied_server_profile_uri_field(node):
"""Delete the applied Server Profile uri from a node if it exists.
:param node: an ironic node object
"""
driver_info = node.driver_info
driver_info.pop('applied_server_profile_uri', None)
node.driver_info = driver_info
node.save()
def allocate_server_hardware_to_ironic(node, server_profile_name):
"""Allocate Server Hardware to ironic.
:param node: an ironic node object.
:param server_profile_name: a formatted string with the Server Profile
name.
:raises OneViewError: if an error occurs while allocating the Server
Hardware to ironic or the node is already in use by OneView.
"""
oneview_client = common.get_hponeview_client()
node_in_use_by_oneview = is_node_in_use_by_oneview(node)
if not node_in_use_by_oneview:
oneview_info = common.get_oneview_info(node)
applied_sp_uri = node.driver_info.get('applied_server_profile_uri')
sh_uri = oneview_info.get("server_hardware_uri")
spt_uri = oneview_info.get("server_profile_template_uri")
server_hardware = oneview_client.server_hardware.get(sh_uri)
if not server_hardware:
msg = _("An error occurred during allocating server hardware to "
"ironic. Server hardware: %s not found.") % sh_uri
raise exception.OneViewError(error=msg)
# Don't have Server Profile on OneView but has
# `applied_server_profile_uri` on driver_info
if not server_hardware.get('serverProfileUri') and applied_sp_uri:
_del_applied_server_profile_uri_field(node)
LOG.info(
"Inconsistent 'applied_server_profile_uri' parameter "
"value in driver_info. There is no Server Profile "
"applied to node %(node_uuid)s. Value deleted.",
{"node_uuid": node.uuid}
)
# applied_server_profile_uri exists and is equal to Server profile
# applied on Hardware. Do not apply again.
if (applied_sp_uri and server_hardware.get(
'serverProfileUri') == applied_sp_uri):
LOG.info(
"The Server Profile %(applied_sp_uri)s was already applied "
"by ironic on node %(node_uuid)s. Reusing.",
{"node_uuid": node.uuid, "applied_sp_uri": applied_sp_uri}
)
return
try:
applied_profile = _create_profile_from_template(
oneview_client, server_profile_name, sh_uri, spt_uri
)
_add_applied_server_profile_uri_field(node, applied_profile)
LOG.info(
"Server Profile %(server_profile_uuid)s was successfully"
" applied to node %(node_uuid)s.",
{"node_uuid": node.uuid,
"server_profile_uuid": applied_profile.get('uri')}
)
except client_exception.HPOneViewInvalidResource as e:
LOG.error("An error occurred during allocating server "
"hardware to ironic during prepare: %s", e)
raise exception.OneViewError(error=e)
else:
msg = _("Node %s is already in use by OneView.") % node.uuid
raise exception.OneViewError(error=msg)
def deallocate_server_hardware_from_ironic(task):
"""Deallocate Server Hardware from ironic.
:param task: a TaskManager object
:raises OneViewError: if an error occurs while deallocating the Server
Hardware to ironic
"""
node = task.node
oneview_client = common.get_hponeview_client()
if is_node_in_use_by_ironic(node):
oneview_info = common.get_oneview_info(node)
server_profile_uri = oneview_info.get('applied_server_profile_uri')
try:
task.driver.power.set_power_state(task, states.POWER_OFF)
oneview_client.server_profiles.delete(server_profile_uri)
_del_applied_server_profile_uri_field(node)
LOG.info("Server Profile %(server_profile_uri)s was deleted "
"from node %(node_uuid)s in OneView.",
{'server_profile_uri': server_profile_uri,
'node_uuid': node.uuid})
except client_exception.HPOneViewException as e:
msg = (_("Error while deleting applied Server Profile from node "
"%(node_uuid)s. Error: %(error)s") %
{'node_uuid': node.uuid, 'error': e})
raise exception.OneViewError(error=msg)
else:
LOG.warning("Cannot deallocate node %(node_uuid)s "
"in OneView because it is not in use by "
"ironic.", {'node_uuid': node.uuid})

View File

@ -1,100 +0,0 @@
# Copyright (2015-2017) Hewlett Packard Enterprise Development LP
# Copyright (2015-2017) Universidade Federal de Campina Grande
#
# 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 ironic_lib import metrics_utils
from ironic.common import exception
from ironic.common import states
from ironic.conductor import task_manager
from ironic.conf import CONF
from ironic.drivers.modules import inspector
from ironic.drivers.modules.oneview import common
from ironic.drivers.modules.oneview import deploy_utils
METRICS = metrics_utils.get_metrics_logger(__name__)
class OneViewInspect(inspector.Inspector):
"""Interface for in band inspection."""
# NOTE(TheJulia): Marking as unsupported as 3rd party CI was taken down
# shortly before the beginning of the Rocky cycle, and no replies have
# indicated that 3rd party CI will be re-established nor visible
# actions observed regarding re-establishing 3rd party CI.
# TODO(TheJulia): This should be expected to be removed in Stein.
supported = False
def get_properties(self):
return deploy_utils.get_properties()
@METRICS.timer('OneViewInspect.validate')
def validate(self, task):
"""Checks required info on 'driver_info' and validates node for 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)
@METRICS.timer('OneViewInspect.inspect_hardware')
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)
def _periodic_check_result(self, manager, context):
filters = {'provision_state': states.INSPECTWAIT,
'driver': 'oneview'}
node_iter = manager.iter_nodes(filters=filters)
for node_uuid, driver, conductor_group in node_iter:
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.INSPECTWAIT and state_after in [
states.MANAGEABLE, states.INSPECTFAIL
]:
deploy_utils.deallocate_server_hardware_from_ironic(task.node)
return result

View File

@ -1,325 +0,0 @@
# Copyright (2015-2017) Hewlett Packard Enterprise Development LP
# Copyright (2015-2017) Universidade Federal de Campina Grande
#
# 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 ironic_lib import metrics_utils
from oslo_log import log as logging
from oslo_utils import importutils
from ironic.common import boot_devices
from ironic.common import exception
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
client_exception = importutils.try_import('hpOneView.exceptions')
LOG = logging.getLogger(__name__)
METRICS = metrics_utils.get_metrics_logger(__name__)
BOOT_DEVICE_MAP_ONEVIEW = {
boot_devices.CDROM: 'CD',
boot_devices.DISK: 'HardDisk',
boot_devices.PXE: 'PXE'
}
BOOT_DEVICE_MAP_ONEVIEW_REV = {
v: k for k, v in BOOT_DEVICE_MAP_ONEVIEW.items()}
BOOT_DEVICE_MAP_ILO = {
boot_devices.CDROM: 'Cd',
boot_devices.DISK: 'Hdd',
boot_devices.PXE: 'Pxe'
}
BOOT_DEVICE_MAP_ILO_REV = {
v: k for k, v in BOOT_DEVICE_MAP_ILO.items()}
ILO_SYSTEM_PATH = "/rest/v1/Systems/1"
ILO_REQUEST_HEADERS = {"Content-Type": "application/json"}
def set_onetime_boot(task):
"""Set onetime boot to server hardware.
Change the onetime boot option of an OneView server hardware.
:param task: a task from TaskManager.
"""
driver_internal_info = task.node.driver_internal_info
next_boot_device = driver_internal_info.get('next_boot_device')
if not next_boot_device:
return
boot_device = next_boot_device.get('boot_device')
persistent = next_boot_device.get('persistent')
if persistent:
return
server_hardware = task.node.driver_info.get('server_hardware_uri')
ilo_client = common.get_ilorest_client(server_hardware)
boot_device = BOOT_DEVICE_MAP_ILO.get(boot_device)
body = {
"Boot": {
"BootSourceOverrideTarget": boot_device,
"BootSourceOverrideEnabled": "Once"
}
}
try:
ilo_client.patch(path=ILO_SYSTEM_PATH, body=body,
headers=ILO_REQUEST_HEADERS)
except Exception as e:
msg = (_("Error while trying to set onetime boot on Server Hardware: "
"%(sh_uri)s. Error: %(error)s") %
{'sh_uri': server_hardware, 'error': e})
raise exception.OneViewError(error=msg)
def _is_onetime_boot(task):
"""Check onetime boot from server hardware.
Check if the onetime boot option of an OneView server hardware
is set to 'Once' in iLO.
:param task: a task from TaskManager.
:returns: Boolean value. True if onetime boot is 'Once'
False otherwise.
"""
server_hardware = task.node.driver_info.get('server_hardware_uri')
ilo_client = common.get_ilorest_client(server_hardware)
response = ilo_client.get(path=ILO_SYSTEM_PATH,
headers=ILO_REQUEST_HEADERS)
onetime_boot = None
boot = response.dict.get('Boot', {})
if boot:
onetime_boot = boot.get('BootSourceOverrideEnabled')
return onetime_boot == 'Once'
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: OneViewError if the communication with OneView fails
"""
oneview_client = common.get_hponeview_client()
common.ensure_server_profile(task)
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_MAP_ONEVIEW):
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})
profile = task.node.driver_info.get('applied_server_profile_uri')
boot_device = BOOT_DEVICE_MAP_ONEVIEW.get(boot_device)
try:
server_profile = oneview_client.server_profiles.get(profile)
boot = server_profile.get('boot', {})
order = boot.get('order', [])
if boot_device in order:
order.remove(boot_device)
order.insert(0, boot_device)
boot['order'] = order
server_profile['boot'] = boot
oneview_client.server_profiles.update(server_profile, profile)
set_onetime_boot(task)
driver_internal_info.pop('next_boot_device', None)
task.node.driver_internal_info = driver_internal_info
task.node.save()
except client_exception.HPOneViewException 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):
# NOTE(TheJulia): Marking as unsupported as 3rd party CI was taken down
# shortly before the beginning of the Rocky cycle, and no replies have
# indicated that 3rd party CI will be re-established nor visible
# actions observed regarding re-establishing 3rd party CI.
# TODO(TheJulia): This should be expected to be removed in Stein.
supported = False
def get_properties(self):
return deploy_utils.get_properties()
@METRICS.timer('OneViewManagement.validate')
def validate(self, task):
"""Checks required info on 'driver_info' and validates node for 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, and if
the server hardware attributes (ram, memory, vcpus count) are
consistent with OneView.
: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)
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)
@METRICS.timer('OneViewManagement.get_supported_boot_devices')
def get_supported_boot_devices(self, task):
"""Gets a list of the supported boot devices.
:param task: a task from TaskManager.
:returns: A list with the supported boot devices defined
in :mod:`ironic.common.boot_devices`.
"""
return sorted(BOOT_DEVICE_MAP_ONEVIEW)
@METRICS.timer('OneViewManagement.set_boot_device')
@task_manager.require_exclusive_lock
@common.node_has_server_profile
def set_boot_device(self, task, device, persistent=False):
"""Set the next boot device to 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
listed in :mod:`ironic.common.boot_devices`.
:param persistent: Boolean value. True if the boot device will
persist to all future boots, False if not.
Default: False.
:raises: InvalidParameterValue if an invalid boot device is
specified.
"""
if device not in self.get_supported_boot_devices(task):
raise exception.InvalidParameterValue(
_("Invalid boot device %s specified.") % device)
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 from 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:
:boot_device: the boot device, one of
:mod:`ironic.common.boot_devices` [PXE, DISK, CDROM]
:persistent: Whether the boot device will persist to all
future boots or not, None if it is unknown.
:raises: InvalidParameterValue if the boot device is unknown
:raises: OneViewError if the communication with OneView fails
"""
oneview_client = common.get_hponeview_client()
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
driver_info = task.node.driver_info
server_profile = driver_info.get('applied_server_profile_uri')
try:
profile = oneview_client.server_profiles.get(server_profile)
primary_device = None
boot = profile.get('boot', {})
boot_order = boot.get('order', [])
if boot_order:
primary_device = boot_order[0]
except client_exception.HPOneViewException as exc:
msg = _("Error on node: %(node)s while getting Server Profile: "
"%(profile)s of the from OneView. Error: %(error)s.") % {
'profile': server_profile,
'node': task.node.uuid,
'error': exc
}
raise exception.OneViewError(msg)
if primary_device not in BOOT_DEVICE_MAP_ONEVIEW_REV:
raise exception.InvalidParameterValue(
_("Unsupported boot device %(device)s for node: %(node)s")
% {"device": primary_device, "node": task.node.uuid}
)
boot_device = {
'boot_device': BOOT_DEVICE_MAP_ONEVIEW_REV.get(primary_device),
'persistent': not _is_onetime_boot(task)
}
return boot_device
@METRICS.timer('OneViewManagement.get_sensors_data')
def get_sensors_data(self, task):
"""Get sensors data.
Not implemented by this driver.
:param task: a TaskManager instance.
"""
raise NotImplementedError()

View File

@ -1,224 +0,0 @@
# Copyright (2015-2017) Hewlett Packard Enterprise Development LP
# Copyright (2015-2017) Universidade Federal de Campina Grande
#
# 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 ironic_lib import metrics_utils
from oslo_log import log as logging
from oslo_utils import importutils
from ironic.common import exception
from ironic.common.i18n import _
from ironic.common import states
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
client_exception = importutils.try_import('hpOneView.exceptions')
LOG = logging.getLogger(__name__)
METRICS = metrics_utils.get_metrics_logger(__name__)
POWER_ON = {'powerState': 'On'}
POWER_OFF = {'powerState': 'Off', 'powerControl': 'PressAndHold'}
REBOOT = {'powerState': 'On', 'powerControl': 'ColdBoot'}
SOFT_REBOOT = {'powerState': 'On', 'powerControl': 'Reset'}
SOFT_POWER_OFF = {'powerState': 'Off', 'powerControl': 'MomentaryPress'}
GET_POWER_STATE_MAP = {
'On': states.POWER_ON,
'Off': states.POWER_OFF,
'Resetting': states.REBOOT,
'PoweringOff': states.POWER_ON,
'PoweringOn': states.POWER_OFF
}
SET_POWER_STATE_MAP = {
states.POWER_ON: POWER_ON,
states.POWER_OFF: POWER_OFF,
states.REBOOT: REBOOT,
states.SOFT_REBOOT: SOFT_REBOOT,
states.SOFT_POWER_OFF: SOFT_POWER_OFF
}
class OneViewPower(base.PowerInterface):
# NOTE(TheJulia): Marking as unsupported as 3rd party CI was taken down
# shortly before the beginning of the Rocky cycle, and no replies have
# indicated that 3rd party CI will be re-established nor visible
# actions observed regarding re-establishing 3rd party CI.
# TODO(TheJulia): This should be expected to be removed in Stein.
supported = False
def get_properties(self):
return deploy_utils.get_properties()
@METRICS.timer('OneViewPower.validate')
def validate(self, task):
"""Checks required info on 'driver_info' and validates node for OneView
Validates whether the 'oneview_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, and if
the server hardware attributes (ram, memory, vcpus count) are
consistent with OneView. It validates if the node is being used by
Oneview.
:param task: a task from TaskManager.
:raises: MissingParameterValue if a required parameter is missing.
:raises: InvalidParameterValue if parameters set are inconsistent with
resources in OneView
:raises: InvalidParameterValue if the node in use by OneView.
:raises: OneViewError if not possible to get OneView's information
for the given node, if not possible to retrieve Server
Hardware from OneView.
"""
common.verify_node_info(task.node)
try:
common.validate_oneview_resources_compatibility(task)
if deploy_utils.is_node_in_use_by_oneview(task.node):
raise exception.InvalidParameterValue(
_("Node %s is in use by OneView.") % task.node.uuid)
except exception.OneViewError as oneview_exc:
raise exception.InvalidParameterValue(oneview_exc)
@METRICS.timer('OneViewPower.get_power_state')
def get_power_state(self, task):
"""Gets the current power state.
:param task: a TaskManager instance.
:returns: one of :mod:`ironic.common.states` POWER_OFF,
POWER_ON or ERROR.
:raises: OneViewError if fails to retrieve power state of OneView
resource
"""
oneview_client = common.get_hponeview_client()
server_hardware = task.node.driver_info.get('server_hardware_uri')
try:
server_hardware = oneview_client.server_hardware.get(
server_hardware)
except client_exception.HPOneViewException as exc:
LOG.error(
"Error getting power state for node %(node)s. Error:"
"%(error)s",
{'node': task.node.uuid, 'error': exc}
)
raise exception.OneViewError(error=exc)
else:
power_state = server_hardware.get('powerState')
return GET_POWER_STATE_MAP.get(power_state)
@METRICS.timer('OneViewPower.set_power_state')
@task_manager.require_exclusive_lock
def set_power_state(self, task, power_state, timeout=None):
"""Turn the current power state on or off.
:param task: a TaskManager instance.
:param power_state: The desired power state POWER_ON, POWER_OFF or
REBOOT from :mod:`ironic.common.states`.
:param timeout: timeout (in seconds) positive integer (> 0) for any
power state. ``None`` indicates the default timeout.
:raises: InvalidParameterValue if an invalid power state was specified.
:raises: PowerStateFailure if the power couldn't be set to power_state.
:raises: OneViewError if OneView fails setting the power state.
"""
oneview_client = common.get_hponeview_client()
if deploy_utils.is_node_in_use_by_oneview(task.node):
raise exception.PowerStateFailure(_(
"Cannot set power state '%(power_state)s' to node %(node)s. "
"The node is in use by OneView.") %
{'power_state': power_state,
'node': task.node.uuid})
if power_state not in SET_POWER_STATE_MAP:
raise exception.InvalidParameterValue(
_("set_power_state called with invalid power state %(state)s "
"on node: %(node)s") % {
'state': power_state,
'node': task.node.uuid
})
LOG.debug('Setting power state of node %(node_uuid)s to '
'%(power_state)s',
{'node_uuid': task.node.uuid, 'power_state': power_state})
server_hardware = task.node.driver_info.get('server_hardware_uri')
timeout = -1 if timeout is None else timeout
try:
if power_state == states.POWER_ON:
management.set_boot_device(task)
oneview_client.server_hardware.update_power_state(
SET_POWER_STATE_MAP.get(power_state),
server_hardware, timeout=timeout)
elif (power_state == states.REBOOT
or power_state == states.SOFT_REBOOT):
power_off_mode = (states.POWER_OFF
if power_state == states.REBOOT
else states.SOFT_POWER_OFF)
oneview_client.server_hardware.update_power_state(
SET_POWER_STATE_MAP.get(power_off_mode),
server_hardware, timeout=timeout)
management.set_boot_device(task)
oneview_client.server_hardware.update_power_state(
SET_POWER_STATE_MAP.get(states.POWER_ON),
server_hardware, timeout=timeout)
else:
oneview_client.server_hardware.update_power_state(
SET_POWER_STATE_MAP.get(power_state),
server_hardware, timeout=timeout)
except client_exception.HPOneViewException as exc:
raise exception.OneViewError(
_("Failed to setting power state on node: %(node)s. "
"Error: %(error)s.") % {
'node': task.node.uuid,
'error': exc
})
@METRICS.timer('OneViewPower.reboot')
@task_manager.require_exclusive_lock
def reboot(self, task, timeout=None):
"""Reboot the node.
:param task: a TaskManager instance.
:param timeout: timeout (in seconds) positive integer (> 0) for any
power state. ``None`` indicates to use default timeout.
:raises: PowerStateFailure if the final state of the node is not
POWER_ON.
"""
current_power_state = self.get_power_state(task)
if current_power_state == states.POWER_ON:
self.set_power_state(task, states.REBOOT, timeout=timeout)
else:
self.set_power_state(task, states.POWER_ON, timeout=timeout)
@METRICS.timer('OneViewPower.get_supported_power_states')
def get_supported_power_states(self, task):
"""Get a list of the supported power states.
:param task: A TaskManager instance containing the node to act on.
Currently not used.
:returns: A list with the supported power states defined
in :mod:`ironic.common.states`.
"""
return [states.POWER_ON, states.POWER_OFF, states.REBOOT,
states.SOFT_REBOOT, states.SOFT_POWER_OFF]

View File

@ -1,58 +0,0 @@
# Copyright (2015-2017) Hewlett Packard Enterprise Development LP
# Copyright (2015-2017) Universidade Federal de Campina Grande
#
# 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.
"""
OneView hardware type.
"""
from ironic.drivers import generic
from ironic.drivers.modules import noop
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
class OneViewHardware(generic.GenericHardware):
"""OneView hardware type.
OneView hardware type is targeted for OneView
"""
# NOTE(TheJulia): Marking as unsupported as 3rd party CI was taken down
# shortly before the beginning of the Rocky cycle, and no replies have
# indicated that 3rd party CI will be re-established nor visible
# actions observed regarding re-establishing 3rd party CI.
# TODO(TheJulia): This should be expected to be removed in Stein.
supported = False
@property
def supported_deploy_interfaces(self):
"""List of supported deploy interfaces."""
return [deploy.OneViewIscsiDeploy, deploy.OneViewAgentDeploy]
@property
def supported_inspect_interfaces(self):
"""List of supported inspect interfaces."""
return [inspect.OneViewInspect, noop.NoInspect]
@property
def supported_management_interfaces(self):
"""List of supported management interfaces."""
return [management.OneViewManagement]
@property
def supported_power_interfaces(self):
"""List of supported power interfaces."""
return [power.OneViewPower]

View File

@ -423,24 +423,6 @@ def get_test_cimc_info():
}
def get_test_oneview_properties():
return {
"cpu_arch": "x86_64",
"cpus": "8",
"local_gb": "10",
"memory_mb": "4096",
"capabilities": ("server_hardware_type_uri:fake_sht_uri,"
"enclosure_group_uri:fake_eg_uri,"
"server_profile_template_uri:fake_spt_uri"),
}
def get_test_oneview_driver_info():
return {
'server_hardware_uri': 'fake_sh_uri',
}
def get_test_redfish_info():
return {
"redfish_address": "https://example.com",

View File

@ -1,406 +0,0 @@
# Copyright (2015-2017) Hewlett Packard Enterprise Development LP
# Copyright (2015-2017) Universidade Federal de Campina Grande
#
# 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 oslo_utils import importutils
from ironic.common import exception
from ironic.conductor import task_manager
from ironic.drivers.modules.oneview import common
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
hponeview_client = importutils.try_import('hpOneView.oneview_client')
class BaseOneViewTest(db_base.DbTestCase):
deploy_interface = None
def setUp(self):
super(BaseOneViewTest, self).setUp()
self.config(enabled_hardware_types=['oneview', 'fake-hardware'],
enabled_deploy_interfaces=['oneview-direct',
'oneview-iscsi', 'fake'],
enabled_management_interfaces=['oneview', 'fake'],
enabled_inspect_interfaces=['oneview', 'fake',
'no-inspect'],
enabled_power_interfaces=['oneview', 'fake'])
self.node = obj_utils.create_test_node(
self.context, driver='oneview',
deploy_interface=self.deploy_interface,
properties=db_utils.get_test_oneview_properties(),
driver_info=db_utils.get_test_oneview_driver_info(),
)
class OneViewCommonTestCase(BaseOneViewTest):
def setUp(self):
super(OneViewCommonTestCase, 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')
self.config(tls_cacert_file='ca_file', group='oneview')
self.config(allow_insecure_connections=False, group='oneview')
def test_prepare_manager_url(self):
self.assertEqual(
common.prepare_manager_url("https://1.2.3.4/"), "1.2.3.4")
self.assertEqual(
common.prepare_manager_url("http://oneview"), "oneview")
self.assertEqual(
common.prepare_manager_url("http://oneview:8080"), "oneview:8080")
self.assertEqual(
common.prepare_manager_url("http://oneview/something"), "oneview")
self.assertEqual(
common.prepare_manager_url("oneview/something"), "oneview")
self.assertEqual(
common.prepare_manager_url("oneview"), "oneview")
@mock.patch.object(hponeview_client, 'OneViewClient', autospec=True)
def test_get_hponeview_client(self, mock_hponeview_client):
common.get_hponeview_client()
mock_hponeview_client.assert_called_once_with(self.config)
def test_get_hponeview_client_insecure_false(self):
self.config(tls_cacert_file=None, group='oneview')
self.assertRaises(exception.OneViewError, common.get_hponeview_client)
@mock.patch.object(hponeview_client, 'OneViewClient', autospec=True)
def test_get_hponeview_client_insecure_cafile(self, mock_oneview):
self.config(allow_insecure_connections=True, group='oneview')
credentials = {
"ip": 'https://1.2.3.4',
"credentials": {
"userName": 'user',
"password": 'password'
},
"ssl_certificate": None
}
mock_oneview.assert_called_once_with(credentials)
def test_get_ilo_access(self):
url = ("hplocons://addr=1.2.3.4&sessionkey"
"=a79659e3b3b7c8209c901ac3509a6719")
remote_console = {'remoteConsoleUrl': url}
host_ip, token = common._get_ilo_access(remote_console)
self.assertEqual(host_ip, "1.2.3.4")
self.assertEqual(token, "a79659e3b3b7c8209c901ac3509a6719")
def test_verify_node_info(self):
common.verify_node_info(self.node)
def test_verify_node_info_missing_node_properties(self):
self.node.properties = {
"cpu_arch": "x86_64",
"cpus": "8",
"local_gb": "10",
"memory_mb": "4096",
"capabilities": ("enclosure_group_uri:fake_eg_uri,"
"server_profile_template_uri:fake_spt_uri")
}
with self.assertRaisesRegex(exception.MissingParameterValue,
"server_hardware_type_uri"):
common.verify_node_info(self.node)
def test_verify_node_info_missing_node_driver_info(self):
self.node.driver_info = {}
with self.assertRaisesRegex(exception.MissingParameterValue,
"server_hardware_uri"):
common.verify_node_info(self.node)
def test_verify_node_info_missing_spt(self):
properties = db_utils.get_test_oneview_properties()
properties["capabilities"] = ("server_hardware_type_uri:fake_sht_uri,"
"enclosure_group_uri:fake_eg_uri")
self.node.properties = properties
with self.assertRaisesRegex(exception.MissingParameterValue,
"server_profile_template_uri"):
common.verify_node_info(self.node)
def test_verify_node_info_missing_sh(self):
driver_info = db_utils.get_test_oneview_driver_info()
del driver_info["server_hardware_uri"]
properties = db_utils.get_test_oneview_properties()
properties["capabilities"] = (
"server_hardware_type_uri:fake_sht_uri,"
"enclosure_group_uri:fake_eg_uri,"
"server_profile_template_uri:fake_spt_uri"
)
self.node.properties = properties
self.node.driver_info = driver_info
with self.assertRaisesRegex(exception.MissingParameterValue,
"server_hardware_uri"):
common.verify_node_info(self.node)
def test_verify_node_info_missing_sht(self):
driver_info = db_utils.get_test_oneview_driver_info()
properties = db_utils.get_test_oneview_properties()
properties["capabilities"] = (
"enclosure_group_uri:fake_eg_uri,"
"server_profile_template_uri:fake_spt_uri"
)
self.node.properties = properties
self.node.driver_info = driver_info
with self.assertRaisesRegex(exception.MissingParameterValue,
"server_hardware_type_uri"):
common.verify_node_info(self.node)
def test_get_oneview_info(self):
complete_node = self.node
expected_node_info = {
'server_hardware_uri': 'fake_sh_uri',
'server_hardware_type_uri': 'fake_sht_uri',
'enclosure_group_uri': 'fake_eg_uri',
'server_profile_template_uri': 'fake_spt_uri',
'applied_server_profile_uri': None,
}
self.assertEqual(
expected_node_info,
common.get_oneview_info(complete_node)
)
def test_get_oneview_info_missing_spt(self):
driver_info = db_utils.get_test_oneview_driver_info()
properties = db_utils.get_test_oneview_properties()
properties["capabilities"] = ("server_hardware_type_uri:fake_sht_uri,"
"enclosure_group_uri:fake_eg_uri")
self.node.driver_info = driver_info
self.node.properties = properties
incomplete_node = self.node
expected_node_info = {
'server_hardware_uri': 'fake_sh_uri',
'server_hardware_type_uri': 'fake_sht_uri',
'enclosure_group_uri': 'fake_eg_uri',
'server_profile_template_uri': None,
'applied_server_profile_uri': None,
}
self.assertEqual(
expected_node_info,
common.get_oneview_info(incomplete_node)
)
def test_get_oneview_info_missing_sh(self):
driver_info = db_utils.get_test_oneview_driver_info()
del driver_info["server_hardware_uri"]
properties = db_utils.get_test_oneview_properties()
properties["capabilities"] = (
"server_hardware_type_uri:fake_sht_uri,"
"enclosure_group_uri:fake_eg_uri,"
"server_profile_template_uri:fake_spt_uri"
)
self.node.driver_info = driver_info
self.node.properties = properties
incomplete_node = self.node
expected_node_info = {
'server_hardware_uri': None,
'server_hardware_type_uri': 'fake_sht_uri',
'enclosure_group_uri': 'fake_eg_uri',
'server_profile_template_uri': 'fake_spt_uri',
'applied_server_profile_uri': None,
}
self.assertEqual(
expected_node_info,
common.get_oneview_info(incomplete_node)
)
def test_get_oneview_info_malformed_capabilities(self):
driver_info = db_utils.get_test_oneview_driver_info()
del driver_info["server_hardware_uri"]
properties = db_utils.get_test_oneview_properties()
properties["capabilities"] = "anything,000"
self.node.driver_info = driver_info
self.node.properties = properties
self.assertRaises(exception.OneViewInvalidNodeParameter,
common.get_oneview_info,
self.node)
def test__verify_node_info(self):
common._verify_node_info("properties",
{"a": True,
"b": False,
"c": 0,
"d": "something",
"e": "somethingelse"},
["a", "b", "c", "e"])
def test__verify_node_info_fails(self):
self.assertRaises(
exception.MissingParameterValue,
common._verify_node_info,
"properties",
{"a": 1, "b": 2, "c": 3},
["x"]
)
def test__verify_node_info_missing_values_empty_string(self):
with self.assertRaisesRegex(exception.MissingParameterValue,
"'properties:a', 'properties:b'"):
common._verify_node_info("properties",
{"a": '', "b": None, "c": "something"},
["a", "b", "c"])
@mock.patch.object(common, 'get_hponeview_client', autospec=True)
@mock.patch.object(common, '_validate_node_server_profile_template')
@mock.patch.object(common, '_validate_node_server_hardware_type')
@mock.patch.object(common, '_validate_node_enclosure_group')
@mock.patch.object(common, '_validate_node_port_mac_server_hardware')
@mock.patch.object(common, '_validate_server_profile_template_mac_type')
def test_validate_oneview_resources_compatibility(
self, mock_spt_mac_type, mock_port_mac_sh, mock_enclosure,
mock_sh_type, mock_sp_template, mock_hponeview):
"""Validate compatibility of resources.
1) Check _validate_node_server_profile_template method is called
2) Check _validate_node_server_hardware_type method is called
3) Check _validate_node_enclosure_group method is called
4) Check _validate_node_port_mac_server_hardware method is called
5) Check _validate_server_profile_template_mac_type method is called
"""
oneview_client = mock_hponeview()
fake_port = db_utils.create_test_port()
fake_port.address = 'AA:BB:CC:DD:EE'
fake_device = {'physicalPorts': [
{'type': 'Ethernet',
'virtualPorts': [
{'portFunction': 'a',
'mac': 'AA:BB:CC:DD:EE'}
]}
]}
fake_spt = {
'serverHardwareTypeUri': 'fake_sht_uri',
'enclosureGroupUri': 'fake_eg_uri',
'macType': 'Physical',
'boot': {'manageBoot': True}
}
fake_sh = {
'serverHardwareTypeUri': 'fake_sht_uri',
'serverGroupUri': 'fake_eg_uri',
'processorCoreCount': 4,
'processorCount': 2,
'memoryMb': 4096,
'portMap': {'deviceSlots': [fake_device]}
}
oneview_client.server_profile_templates.get.return_value = fake_spt
oneview_client.server_hardware.get.return_value = fake_sh
with task_manager.acquire(self.context, self.node.uuid) as task:
task.ports = [fake_port]
common.validate_oneview_resources_compatibility(task)
self.assertTrue(mock_sp_template.called)
self.assertTrue(mock_sh_type.called)
self.assertTrue(mock_enclosure.called)
self.assertTrue(mock_port_mac_sh.called)
self.assertTrue(mock_spt_mac_type.called)
@mock.patch.object(common, 'get_hponeview_client', autospec=True)
def test__validate_server_profile_template_mac_type_virtual(
self, mock_hponeview):
oneview_client = mock_hponeview()
fake_spt = {'macType': 'Virtual'}
oneview_client.server_hardware.get.return_value = fake_spt
oneview_info = {'server_profile_template_uri': 'fake_uri'}
self.assertRaises(exception.OneViewError,
common._validate_server_profile_template_mac_type,
oneview_client, oneview_info)
@mock.patch.object(common, 'get_hponeview_client', autospec=True)
def test__validate_node_port_mac_server_hardware_invalid(
self, mock_hponeview):
oneview_client = mock_hponeview()
fake_device = {
'physicalPorts': [
{'type': 'notEthernet',
'mac': '00:11:22:33:44',
'virtualPorts': [{
'portFunction': 'a',
'mac': 'AA:BB:CC:DD:EE'}]},
{'type': 'Ethernet',
'mac': '11:22:33:44:55',
'virtualPorts': [{
'portFunction': 'a',
'mac': 'BB:CC:DD:EE:FF'}]}]}
fake_sh = {'portMap': {'deviceSlots': [fake_device]}}
fake_port = db_utils.create_test_port(address='AA:BB:CC:DD:EE')
oneview_client.server_hardware.get.return_value = fake_sh
oneview_info = db_utils.get_test_oneview_driver_info()
self.assertRaises(exception.OneViewError,
common._validate_node_port_mac_server_hardware,
oneview_client, oneview_info, [fake_port])
@mock.patch.object(common, 'get_hponeview_client', autospec=True)
def test__validate_node_enclosure_group_invalid(self, mock_hponeview):
oneview_client = mock_hponeview()
fake_sh = {'serverGroupUri': 'invalid_fake_eg_uri'}
oneview_client.server_hardware.get.return_value = fake_sh
oneview_info = {'server_hardware_uri': 'fake_sh_uri',
'enclosure_group_uri': 'fake_eg_uri'}
self.assertRaises(exception.OneViewError,
common._validate_node_enclosure_group,
oneview_client, oneview_info)
@mock.patch.object(common, 'get_hponeview_client', autospec=True)
def test__validate_node_server_hardware_type(self, mock_hponeview):
oneview_client = mock_hponeview()
fake_sh = {'serverHardwareTypeUri': 'invalid_fake_sh_uri'}
oneview_client.server_hardware.get.return_value = fake_sh
oneview_info = {'server_hardware_uri': 'fake_sh_uri',
'server_hardware_type_uri': 'fake_sht_uri'}
self.assertRaises(exception.OneViewError,
common._validate_node_server_hardware_type,
oneview_client, oneview_info)
def test__validate_server_profile_template_manage_boot_false(self):
fake_spt = {'boot': {'manageBoot': False}}
self.assertRaises(exception.OneViewError,
common._validate_server_profile_template_manage_boot,
fake_spt)
def test__validate_spt_enclosure_group_invalid(self):
fake_spt = {'enclosureGroupUri': 'fake_eg_uri'}
fake_sh = {'serverGroupUri': 'invalid_fake_eg_uri'}
self.assertRaises(exception.OneViewError,
common._validate_spt_enclosure_group,
fake_spt, fake_sh)
def test__validate_server_profile_template_server_hardware_type(self):
fake_spt = {'serverHardwareTypeUri': 'fake_sht_uri'}
fake_sh = {'serverHardwareTypeUri': 'invalid_fake_sht_uri'}
self.assertRaises(
exception.OneViewError,
common._validate_server_profile_template_server_hardware_type,
fake_spt, fake_sh)

View File

@ -1,456 +0,0 @@
# Copyright (2015-2017) Hewlett Packard Enterprise Development LP
# Copyright (2015-2017) Universidade Federal de Campina Grande
#
# 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.common import exception
from ironic.common import states
from ironic.conductor import task_manager
from ironic.conf import CONF
from ironic.drivers.modules import agent
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.tests.unit.drivers.modules.oneview import test_common
from ironic.tests.unit.objects import utils as obj_utils
METHODS = ['iter_nodes', 'update_node', 'do_provisioning_action']
oneview_error = common.SERVER_HARDWARE_ALLOCATION_ERROR
maintenance_reason = common.NODE_IN_USE_BY_ONEVIEW
driver_internal_info = {'oneview_error': oneview_error}
nodes_taken_by_oneview = [(1, 'oneview', '')]
nodes_freed_by_oneview = [(1, 'oneview', '', maintenance_reason)]
nodes_taken_on_cleanfail = [(1, 'oneview', '', driver_internal_info)]
nodes_taken_on_cleanfail_no_info = [(1, 'oneview', '', {})]
GET_POWER_STATE_RETRIES = 5
def _setup_node_in_available_state(node):
node.provision_state = states.AVAILABLE
node.maintenance = False
node.maintenance_reason = None
node.save()
def _setup_node_in_manageable_state(node):
node.provision_state = states.MANAGEABLE
node.maintenance = True
node.maintenance_reason = common.NODE_IN_USE_BY_ONEVIEW
node.save()
def _setup_node_in_cleanfailed_state_with_oneview_error(node):
node.provision_state = states.CLEANFAIL
node.maintenance = False
node.maintenance_reason = None
driver_internal_info = node.driver_internal_info
oneview_error = common.SERVER_HARDWARE_ALLOCATION_ERROR
driver_internal_info['oneview_error'] = oneview_error
node.driver_internal_info = driver_internal_info
node.save()
def _setup_node_in_cleanfailed_state_without_oneview_error(node):
node.provision_state = states.CLEANFAIL
node.maintenance = False
node.maintenance_reason = None
node.save()
class OneViewDriverDeploy(deploy.OneViewPeriodicTasks):
oneview_driver = 'oneview'
@mock.patch('ironic.objects.Node', spec_set=True, autospec=True)
@mock.patch.object(deploy_utils, 'is_node_in_use_by_oneview')
class OneViewPeriodicTasks(test_common.BaseOneViewTest):
def setUp(self):
super(OneViewPeriodicTasks, 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')
self.deploy = OneViewDriverDeploy()
self.os_primary = mock.MagicMock(spec=METHODS)
def test_node_manageable_maintenance_when_in_use_by_oneview(
self, mock_is_node_in_use_by_oneview, mock_node_get
):
mock_node_get.get.return_value = self.node
_setup_node_in_available_state(self.node)
self.os_primary.iter_nodes.return_value = nodes_taken_by_oneview
mock_is_node_in_use_by_oneview.return_value = True
self.deploy._periodic_check_nodes_taken_by_oneview(
self.os_primary, self.context
)
mock_is_node_in_use_by_oneview.assert_called_once_with(self.node)
self.assertTrue(self.os_primary.update_node.called)
self.assertTrue(self.os_primary.do_provisioning_action.called)
self.assertTrue(self.node.maintenance)
self.assertEqual(common.NODE_IN_USE_BY_ONEVIEW,
self.node.maintenance_reason)
def test_node_stay_available_when_not_in_use_by_oneview(
self, mock_is_node_in_use_by_oneview, mock_node_get
):
mock_node_get.get.return_value = self.node
_setup_node_in_available_state(self.node)
mock_node_get.return_value = self.node
mock_is_node_in_use_by_oneview.return_value = False
self.os_primary.iter_nodes.return_value = nodes_taken_by_oneview
self.deploy._periodic_check_nodes_taken_by_oneview(
self.os_primary, self.context
)
mock_is_node_in_use_by_oneview.assert_called_once_with(self.node)
self.assertFalse(self.os_primary.update_node.called)
self.assertFalse(self.os_primary.do_provisioning_action.called)
self.assertFalse(self.node.maintenance)
self.assertIsNone(self.node.maintenance_reason)
def test_node_stay_available_when_raise_exception(
self, mock_is_node_in_use_by_oneview, mock_node_get
):
mock_node_get.get.return_value = self.node
_setup_node_in_available_state(self.node)
side_effect = exception.OneViewError('boom')
mock_is_node_in_use_by_oneview.side_effect = side_effect
self.os_primary.iter_nodes.return_value = nodes_taken_by_oneview
self.deploy._periodic_check_nodes_taken_by_oneview(
self.os_primary, self.context
)
mock_is_node_in_use_by_oneview.assert_called_once_with(self.node)
self.assertFalse(self.os_primary.update_node.called)
self.assertFalse(self.os_primary.do_provisioning_action.called)
self.assertFalse(self.node.maintenance)
self.assertNotEqual(common.NODE_IN_USE_BY_ONEVIEW,
self.node.maintenance_reason)
def test_node_available_when_not_in_use_by_oneview(
self, mock_is_node_in_use_by_oneview, mock_node_get
):
mock_node_get.get.return_value = self.node
_setup_node_in_manageable_state(self.node)
self.os_primary.iter_nodes.return_value = nodes_freed_by_oneview
mock_is_node_in_use_by_oneview.return_value = False
self.deploy._periodic_check_nodes_freed_by_oneview(
self.os_primary, self.context
)
mock_is_node_in_use_by_oneview.assert_called_once_with(self.node)
self.assertTrue(self.os_primary.update_node.called)
self.assertTrue(self.os_primary.do_provisioning_action.called)
self.assertFalse(self.node.maintenance)
self.assertIsNone(self.node.maintenance_reason)
def test_node_stay_manageable_when_in_use_by_oneview(
self, mock_is_node_in_use_by_oneview, mock_node_get
):
mock_node_get.get.return_value = self.node
_setup_node_in_manageable_state(self.node)
mock_is_node_in_use_by_oneview.return_value = True
self.os_primary.iter_nodes.return_value = nodes_freed_by_oneview
self.deploy._periodic_check_nodes_freed_by_oneview(
self.os_primary, self.context
)
mock_is_node_in_use_by_oneview.assert_called_once_with(self.node)
self.assertFalse(self.os_primary.update_node.called)
self.assertFalse(self.os_primary.do_provisioning_action.called)
self.assertTrue(self.node.maintenance)
self.assertEqual(common.NODE_IN_USE_BY_ONEVIEW,
self.node.maintenance_reason)
def test_node_stay_manageable_maintenance_when_raise_exception(
self, mock_is_node_in_use_by_oneview, mock_node_get
):
mock_node_get.get.return_value = self.node
_setup_node_in_manageable_state(self.node)
side_effect = exception.OneViewError('boom')
mock_is_node_in_use_by_oneview.side_effect = side_effect
self.os_primary.iter_nodes.return_value = nodes_freed_by_oneview
self.deploy._periodic_check_nodes_freed_by_oneview(
self.os_primary, self.context
)
mock_is_node_in_use_by_oneview.assert_called_once_with(self.node)
self.assertFalse(self.os_primary.update_node.called)
self.assertFalse(self.os_primary.do_provisioning_action.called)
self.assertTrue(self.node.maintenance)
self.assertEqual(common.NODE_IN_USE_BY_ONEVIEW,
self.node.maintenance_reason)
def test_node_manageable_maintenance_when_oneview_error(
self, mock_is_node_in_use_by_oneview, mock_node_get
):
mock_node_get.get.return_value = self.node
_setup_node_in_cleanfailed_state_with_oneview_error(self.node)
self.os_primary.iter_nodes.return_value = nodes_taken_on_cleanfail
self.deploy._periodic_check_nodes_taken_on_cleanfail(
self.os_primary, self.context
)
self.assertTrue(self.os_primary.update_node.called)
self.assertTrue(self.os_primary.do_provisioning_action.called)
self.assertTrue(self.node.maintenance)
self.assertEqual(common.NODE_IN_USE_BY_ONEVIEW,
self.node.maintenance_reason)
self.assertNotIn('oneview_error', self.node.driver_internal_info)
def test_node_stay_clean_failed_when_no_oneview_error(
self, mock_is_node_in_use_by_oneview, mock_node_get
):
mock_node_get.get.return_value = self.node
_setup_node_in_cleanfailed_state_without_oneview_error(self.node)
self.os_primary.iter_nodes.return_value = (
nodes_taken_on_cleanfail_no_info)
self.deploy._periodic_check_nodes_taken_on_cleanfail(
self.os_primary, self.context
)
self.assertFalse(self.os_primary.update_node.called)
self.assertFalse(self.os_primary.do_provisioning_action.called)
self.assertFalse(self.node.maintenance)
self.assertNotEqual(common.NODE_IN_USE_BY_ONEVIEW,
self.node.maintenance_reason)
self.assertNotIn('oneview_error', self.node.driver_internal_info)
class OneViewIscsiDeployTestCase(test_common.BaseOneViewTest):
deploy_interface = 'oneview-iscsi'
def setUp(self):
super(OneViewIscsiDeployTestCase, 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')
self.port = obj_utils.create_test_port(self.context,
node_id=self.node.id)
self.info = common.get_oneview_info(self.node)
def test_get_properties(self):
expected = common.COMMON_PROPERTIES
self.assertEqual(expected,
deploy.OneViewIscsiDeploy().get_properties())
@mock.patch.object(common, 'validate_oneview_resources_compatibility',
spect_set=True, autospec=True)
@mock.patch.object(iscsi_deploy.ISCSIDeploy, 'validate',
spec_set=True, autospec=True)
def test_validate(
self, iscsi_deploy_validate_mock, mock_validate):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.driver.deploy.validate(task)
self.assertTrue(mock_validate.called)
iscsi_deploy_validate_mock.assert_called_once_with(mock.ANY, task)
@mock.patch.object(iscsi_deploy.ISCSIDeploy, 'prepare', autospec=True)
@mock.patch.object(deploy_utils, 'allocate_server_hardware_to_ironic')
def test_prepare(self, allocate_server_hardware_mock,
iscsi_deploy_prepare_mock):
self.node.provision_state = states.DEPLOYING
self.node.save()
with task_manager.acquire(self.context, self.node.uuid) as task:
task.driver.deploy.prepare(task)
iscsi_deploy_prepare_mock.assert_called_once_with(mock.ANY, task)
self.assertTrue(allocate_server_hardware_mock.called)
@mock.patch.object(iscsi_deploy.ISCSIDeploy, 'prepare',
spec_set=True, autospec=True)
def test_prepare_active_node(self, iscsi_deploy_prepare_mock):
"""Ensure nodes in running states are not inadvertently changed"""
test_states = list(states.STABLE_STATES)
test_states.extend([states.CLEANING,
states.CLEANWAIT,
states.INSPECTING])
for state in test_states:
self.node.provision_state = state
self.node.save()
iscsi_deploy_prepare_mock.reset_mock()
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.driver.deploy.prepare(task)
iscsi_deploy_prepare_mock.assert_called_once_with(
mock.ANY, task)
@mock.patch.object(iscsi_deploy.ISCSIDeploy, 'deploy',
spec_set=True, autospec=True)
def test_deploy(self, iscsi_deploy_mock):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.driver.deploy.deploy(task)
iscsi_deploy_mock.assert_called_once_with(mock.ANY, task)
@mock.patch.object(iscsi_deploy.ISCSIDeploy, 'tear_down', spec_set=True,
autospec=True)
def test_tear_down(self, iscsi_tear_down_mock):
iscsi_tear_down_mock.return_value = states.DELETED
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
returned_state = task.driver.deploy.tear_down(task)
iscsi_tear_down_mock.assert_called_once_with(mock.ANY, task)
self.assertEqual(states.DELETED, returned_state)
@mock.patch.object(iscsi_deploy.ISCSIDeploy, 'tear_down', spec_set=True,
autospec=True)
@mock.patch.object(deploy_utils, 'deallocate_server_hardware_from_ironic')
def test_tear_down_with_automated_clean_disabled(
self, deallocate_server_hardware_mock, iscsi_tear_down_mock):
CONF.conductor.automated_clean = False
iscsi_tear_down_mock.return_value = states.DELETED
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
returned_state = task.driver.deploy.tear_down(task)
iscsi_tear_down_mock.assert_called_once_with(mock.ANY, task)
self.assertEqual(states.DELETED, returned_state)
self.assertTrue(deallocate_server_hardware_mock.called)
@mock.patch.object(iscsi_deploy.ISCSIDeploy, 'prepare_cleaning',
spec_set=True, autospec=True)
@mock.patch.object(deploy_utils, 'allocate_server_hardware_to_ironic')
def test_prepare_cleaning(
self, allocate_server_hardware_mock, iscsi_prep_clean_mock):
iscsi_prep_clean_mock.return_value = states.CLEANWAIT
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
ret = task.driver.deploy.prepare_cleaning(task)
self.assertEqual(states.CLEANWAIT, ret)
iscsi_prep_clean_mock.assert_called_once_with(mock.ANY, task)
self.assertTrue(allocate_server_hardware_mock.called)
@mock.patch.object(iscsi_deploy.ISCSIDeploy, 'tear_down_cleaning',
spec_set=True, autospec=True)
@mock.patch.object(deploy_utils, 'deallocate_server_hardware_from_ironic')
def test_tear_down_cleaning(
self, deallocate_server_hardware_mock, iscsi_tear_down_clean_mock):
iscsi_tear_down_clean_mock.return_value = states.CLEANWAIT
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.driver.deploy.tear_down_cleaning(task)
iscsi_tear_down_clean_mock.assert_called_once_with(mock.ANY, task)
self.assertTrue(deallocate_server_hardware_mock.called)
class OneViewAgentDeployTestCase(test_common.BaseOneViewTest):
deploy_interface = 'oneview-direct'
def setUp(self):
super(OneViewAgentDeployTestCase, 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')
self.port = obj_utils.create_test_port(self.context,
node_id=self.node.id)
self.info = common.get_oneview_info(self.node)
def test_get_properties(self):
expected = common.COMMON_PROPERTIES
self.assertEqual(expected,
deploy.OneViewAgentDeploy().get_properties())
@mock.patch.object(common, 'validate_oneview_resources_compatibility',
spect_set=True, autospec=True)
@mock.patch.object(agent.AgentDeploy, 'validate',
spec_set=True, autospec=True)
def test_validate(
self, agent_deploy_validate_mock, mock_validate):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.driver.deploy.validate(task)
self.assertTrue(mock_validate.called)
@mock.patch.object(agent.AgentDeploy, 'prepare',
spec_set=True, autospec=True)
@mock.patch.object(deploy_utils, 'allocate_server_hardware_to_ironic')
def test_prepare(
self, allocate_server_hardware_mock, agent_deploy_prepare_mock):
self.node.provision_state = states.DEPLOYING
self.node.save()
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.driver.deploy.prepare(task)
agent_deploy_prepare_mock.assert_called_once_with(mock.ANY, task)
self.assertTrue(allocate_server_hardware_mock.called)
@mock.patch.object(agent.AgentDeploy, 'prepare',
spec_set=True, autospec=True)
def test_prepare_active_node(self, agent_deploy_prepare_mock):
"""Ensure nodes in running states are not inadvertently changed"""
test_states = list(states.STABLE_STATES)
test_states.extend([states.CLEANING,
states.CLEANWAIT,
states.INSPECTING])
for state in test_states:
self.node.provision_state = state
self.node.save()
agent_deploy_prepare_mock.reset_mock()
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.driver.deploy.prepare(task)
agent_deploy_prepare_mock.assert_called_once_with(
mock.ANY, task)
@mock.patch.object(agent.AgentDeploy, 'deploy',
spec_set=True, autospec=True)
def test_deploy(self, agent_deploy_mock):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.driver.deploy.deploy(task)
agent_deploy_mock.assert_called_once_with(mock.ANY, task)
@mock.patch.object(agent.AgentDeploy, 'tear_down', spec_set=True,
autospec=True)
@mock.patch.object(deploy_utils, 'deallocate_server_hardware_from_ironic')
def test_tear_down_with_automated_clean_disabled(
self, deallocate_server_hardware_mock, agent_tear_down_mock):
CONF.conductor.automated_clean = False
agent_tear_down_mock.return_value = states.DELETED
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
returned_state = task.driver.deploy.tear_down(task)
agent_tear_down_mock.assert_called_once_with(mock.ANY, task)
self.assertEqual(states.DELETED, returned_state)
self.assertTrue(deallocate_server_hardware_mock.called)
@mock.patch.object(agent.AgentDeploy, 'prepare_cleaning',
spec_set=True, autospec=True)
@mock.patch.object(deploy_utils, 'allocate_server_hardware_to_ironic')
def test_prepare_cleaning(
self, allocate_server_hardware_mock, agent_prep_clean_mock):
agent_prep_clean_mock.return_value = states.CLEANWAIT
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
ret = task.driver.deploy.prepare_cleaning(task)
self.assertEqual(states.CLEANWAIT, ret)
agent_prep_clean_mock.assert_called_once_with(mock.ANY, task)
self.assertTrue(allocate_server_hardware_mock.called)
@mock.patch.object(agent.AgentDeploy, 'tear_down_cleaning',
spec_set=True, autospec=True)
@mock.patch.object(deploy_utils, 'deallocate_server_hardware_from_ironic')
def test_tear_down_cleaning(
self, deallocate_server_hardware_mock, agent_tear_down_clean_mock):
agent_tear_down_clean_mock.return_value = states.CLEANWAIT
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.driver.deploy.tear_down_cleaning(task)
agent_tear_down_clean_mock.assert_called_once_with(mock.ANY, task)
self.assertTrue(deallocate_server_hardware_mock.called)

View File

@ -1,327 +0,0 @@
# Copyright (2015-2017) Hewlett Packard Enterprise Development LP
# Copyright (2015-2017) Universidade Federal de Campina Grande
#
# 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 oslo_utils import importutils
from ironic.common import exception
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 import objects
from ironic.tests.unit.drivers.modules.oneview import test_common
oneview_models = importutils.try_import('oneview_client.models')
@mock.patch.object(common, 'get_hponeview_client')
class OneViewDeployUtilsTestCase(test_common.BaseOneViewTest):
def setUp(self):
super(OneViewDeployUtilsTestCase, 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')
self.info = common.get_oneview_info(self.node)
deploy_utils.is_node_in_use_by_oneview = mock.Mock(return_value=False)
deploy_utils.is_node_in_use_by_ironic = mock.Mock(return_value=True)
# Tests for prepare
def test_prepare_node_is_in_use_by_oneview(self, mock_oneview_client):
"""`prepare` behavior when the node has a Profile on OneView."""
deploy_utils.is_node_in_use_by_oneview.return_value = True
with task_manager.acquire(self.context, self.node.uuid) as task:
task.node.provision_state = states.DEPLOYING
self.assertRaises(
exception.InstanceDeployFailure,
deploy_utils.prepare,
task
)
@mock.patch.object(objects.Node, 'save')
def test_prepare_node_is_successfuly_allocated_to_ironic(
self, mock_save, mock_oneview_client):
"""`prepare` behavior when the node is free from OneView standpoint."""
with task_manager.acquire(self.context, self.node.uuid) as task:
task.node.provision_state = states.DEPLOYING
deploy_utils.prepare(task)
self.assertTrue(mock_save.called)
# Tests for tear_down
def test_tear_down(self, mock_oneview_client):
"""`tear_down` behavior when node already has Profile applied."""
oneview_client = mock_oneview_client()
with task_manager.acquire(self.context, self.node.uuid) as task:
task.node.driver_info['applied_server_profile_uri'] = (
'/rest/server-profiles/1234556789'
)
self.assertTrue(
'applied_server_profile_uri' in task.node.driver_info
)
deploy_utils.tear_down(task)
self.assertFalse(
'applied_server_profile_uri' in task.node.driver_info
)
self.assertTrue(oneview_client.server_profiles.delete.called)
# Tests for prepare_cleaning
@mock.patch.object(objects.Node, 'save')
def test_prepare_cleaning_when_node_does_not_have_sp_applied(
self, mock_save, mock_oneview_client):
"""`prepare_cleaning` behavior when node is free."""
with task_manager.acquire(self.context, self.node.uuid) as task:
self.assertFalse(
'applied_server_profile_uri' in task.node.driver_info
)
deploy_utils.prepare_cleaning(task)
self.assertTrue(
'applied_server_profile_uri' in task.node.driver_info
)
@mock.patch.object(objects.Node, 'save')
def test_prepare_cleaning_when_node_has_sp_applied(
self, mock_node_save, mock_oneview_client):
"""`prepare_cleaning` behavior when node has Profile applied."""
oneview_client = mock_oneview_client()
oneview_client.server_hardware.get.return_value = {
'serverProfileUri': 'same/sp_applied'
}
with task_manager.acquire(self.context, self.node.uuid) as task:
task.node.driver_info['applied_server_profile_uri'] = (
'same/sp_applied'
)
deploy_utils.prepare_cleaning(task)
self.assertFalse(mock_node_save.called)
def test_prepare_cleaning_node_is_in_use_by_oneview(
self, mock_oneview_client):
"""`prepare_cleaning` behavior when node has Profile on OneView."""
deploy_utils.is_node_in_use_by_oneview.return_value = True
with task_manager.acquire(self.context, self.node.uuid) as task:
self.assertRaises(
exception.NodeCleaningFailure,
deploy_utils.prepare_cleaning,
task
)
# Tests for tear_down_cleaning
def test_tear_down_cleaning(self, mock_oneview_client):
"""Check if Server Profile was deleted and its uri removed."""
oneview_client = mock_oneview_client()
with task_manager.acquire(self.context, self.node.uuid) as task:
task.node.driver_info['applied_server_profile_uri'] = (
'/rest/server-profiles/1234556789'
)
self.assertTrue(
'applied_server_profile_uri' in task.node.driver_info
)
deploy_utils.tear_down_cleaning(task)
self.assertFalse(
'applied_server_profile_uri' in task.node.driver_info
)
self.assertTrue(oneview_client.server_profiles.delete.called)
# Tests for is_node_in_use_by_oneview
def test_is_node_in_use_by_oneview(self, mock_oneview_client):
"""Node has a Server Profile applied by a third party user."""
server_hardware = {
'serverProfileUri': '/rest/server-profile/123456789'
}
with task_manager.acquire(self.context, self.node.uuid) as task:
task.node.driver_info['applied_server_profile_uri'] = (
'/rest/server-profile/987654321'
)
self.assertTrue(
deploy_utils._is_node_in_use(
server_hardware,
task.node.driver_info['applied_server_profile_uri'],
by_oneview=True
)
)
def test_is_node_in_use_by_oneview_no_server_profile(
self, mock_oneview_client):
"""Node has no Server Profile."""
server_hardware = {'serverProfileUri': None}
with task_manager.acquire(self.context, self.node.uuid) as task:
task.node.driver_info['applied_server_profile_uri'] = (
'/rest/server-profile/123456789'
)
self.assertFalse(
deploy_utils._is_node_in_use(
server_hardware,
task.node.driver_info['applied_server_profile_uri'],
by_oneview=True
)
)
def test_is_node_in_use_by_oneview_same_server_profile_applied(
self, mock_oneview_client):
"""Check if node's Server Profile uri is the same applied by ironic."""
server_hardware = {
'serverProfileUri': '/rest/server-profile/123456789'
}
with task_manager.acquire(self.context, self.node.uuid) as task:
task.node.driver_info['applied_server_profile_uri'] = (
'/rest/server-profile/123456789'
)
self.assertFalse(
deploy_utils._is_node_in_use(
server_hardware,
task.node.driver_info['applied_server_profile_uri'],
by_oneview=True
)
)
# Tests for is_node_in_use_by_ironic
def test_is_node_in_use_by_ironic(self, mock_oneview_client):
"""Node has a Server Profile applied by ironic."""
server_hardware = {'serverProfileUri': 'same/applied_sp_uri/'}
with task_manager.acquire(self.context, self.node.uuid) as task:
task.node.driver_info['applied_server_profile_uri'] = (
'same/applied_sp_uri/'
)
self.assertTrue(
deploy_utils._is_node_in_use(
server_hardware,
task.node.driver_info['applied_server_profile_uri'],
by_oneview=False
)
)
def test_is_node_in_use_by_ironic_no_server_profile(
self, mock_oneview_client):
"""Node has no Server Profile."""
server_hardware = {'serverProfileUri': None}
with task_manager.acquire(self.context, self.node.uuid) as task:
task.node.driver_info['applied_server_profile_uri'] = (
'/applied_sp_uri/'
)
self.assertFalse(
deploy_utils._is_node_in_use(
server_hardware,
task.node.driver_info['applied_server_profile_uri'],
by_oneview=False
)
)
def test__create_profile_from_template(self, mock_oneview_client):
"""Check if the server_profile was created from template."""
server_hardware_uri = "server_hardware/12456789"
sp_template_uri = "server_profile_template_uri/13245798"
oneview_client = mock_oneview_client()
oneview_client.server_profile_templates.\
get_new_profile.return_value = {}
server_profile = {"name": "server_profile_name",
"serverHardwareUri": server_hardware_uri,
"serverProfileTemplateUri": ""}
deploy_utils._create_profile_from_template(
oneview_client,
"server_profile_name",
server_hardware_uri,
sp_template_uri
)
oneview_client.server_profiles.create.assert_called_with(
server_profile)
# Tests for _add_applied_server_profile_uri_field
@mock.patch.object(objects.Node, 'save')
def test__add_applied_server_profile_uri_field(
self, save, mock_oneview_client):
"""Check if applied_server_profile_uri was added to driver_info."""
server_profile = {'uri': 'any/applied_sp_uri/'}
with task_manager.acquire(self.context, self.node.uuid) as task:
task.node.driver_info.pop('applied_server_profile_uri', None)
self.assertNotIn(
'applied_server_profile_uri', task.node.driver_info
)
deploy_utils._add_applied_server_profile_uri_field(
task.node,
server_profile
)
self.assertIn('applied_server_profile_uri', task.node.driver_info)
# Tests for _del_applied_server_profile_uri_field
@mock.patch.object(objects.Node, 'save')
def test__del_applied_server_profile_uri_field(
self, save, mock_oneview_client):
"""Check if applied_server_profile_uri was removed from driver_info."""
with task_manager.acquire(self.context, self.node.uuid) as task:
task.node.driver_info['applied_server_profile_uri'] = (
'any/applied_sp_uri/'
)
self.assertIn('applied_server_profile_uri', task.node.driver_info)
deploy_utils._del_applied_server_profile_uri_field(task.node)
self.assertNotIn(
'applied_server_profile_uri', task.node.driver_info
)
# Tests for allocate_server_hardware_to_ironic
@mock.patch.object(objects.Node, 'save')
def test_allocate_server_hardware_to_ironic(
self, mock_node_save, mock_oneview_client):
"""Check if a Profile was created and its uri is in driver_info."""
oneview_client = mock_oneview_client()
server_hardware = {'serverProfileUri': None}
oneview_client.server_hardware.get.return_value = server_hardware
with task_manager.acquire(self.context, self.node.uuid) as task:
deploy_utils.allocate_server_hardware_to_ironic(
task.node, 'serverProfileName'
)
self.assertTrue(mock_node_save.called)
self.assertIn('applied_server_profile_uri', task.node.driver_info)
@mock.patch.object(objects.Node, 'save')
def test_allocate_server_hardware_to_ironic_node_has_server_profile(
self, mock_node_save, mock_oneview_client):
"""Test profile allocation when applied_server_profile_uri exists.
This test consider that no Server Profile is applied on the Server
Hardware but the applied_server_profile_uri remained on the node. Thus,
the conductor should remove the value and apply a new server profile to
use the node.
"""
oneview_client = mock_oneview_client()
server_hardware = {'serverProfileUri': None}
oneview_client.server_hardware.get.return_value = server_hardware
with task_manager.acquire(self.context, self.node.uuid) as task:
task.node.driver_info['applied_server_profile_uri'] = (
'any/applied_sp_uri/'
)
deploy_utils.allocate_server_hardware_to_ironic(
task.node, 'serverProfileName'
)
self.assertTrue(mock_node_save.called)
# Tests for deallocate_server_hardware_from_ironic
@mock.patch.object(objects.Node, 'save')
def test_deallocate_server_hardware_from_ironic(
self, mock_node_save, mock_oneview_client):
oneview_client = mock_oneview_client()
server_hardware = {'serverProfileUri': 'any/applied_sp_uri/'}
oneview_client.server_hardware.get.return_value = server_hardware
with task_manager.acquire(self.context, self.node.uuid) as task:
task.node.driver_info['applied_server_profile_uri'] = (
'any/applied_sp_uri/'
)
deploy_utils.deallocate_server_hardware_from_ironic(task)
self.assertTrue(mock_node_save.called)
self.assertTrue(
'applied_server_profile_uri' not in task.node.driver_info
)

View File

@ -1,51 +0,0 @@
# Copyright (2015-2017) Hewlett Packard Enterprise Development LP
# Copyright (2015-2017) Universidade Federal de Campina Grande
#
# 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 ov_common
from ironic.drivers.modules.oneview import deploy_utils
from ironic.tests.unit.drivers.modules.oneview import test_common
class OneViewInspectTestCase(test_common.BaseOneViewTest):
def setUp(self):
super(OneViewInspectTestCase, self).setUp()
self.config(enabled=True, group='inspector')
self.config(manager_url='https://1.2.3.4', group='oneview')
def test_get_properties(self):
expected = deploy_utils.get_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(ov_common, 'validate_oneview_resources_compatibility',
autospect=True)
def test_validate(self, mock_validate):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.driver.inspect.validate(task)
self.assertTrue(mock_validate.called)
@mock.patch.object(deploy_utils, 'allocate_server_hardware_to_ironic',
autospect=True)
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

@ -1,365 +0,0 @@
# Copyright (2015-2017) Hewlett Packard Enterprise Development LP
# Copyright (2015-2017) Universidade Federal de Campina Grande
#
# 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 oslo_utils import importutils
from oslo_utils import uuidutils
from ironic.common import boot_devices
from ironic.common import exception
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.drivers.modules.oneview import test_common
from ironic.tests.unit.objects import utils as obj_utils
client_exception = importutils.try_import('hpOneView.exceptions')
@mock.patch.object(common, 'get_hponeview_client')
class OneViewManagementDriverFunctionsTestCase(test_common.BaseOneViewTest):
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')
self.info = common.get_oneview_info(self.node)
@mock.patch.object(common, 'get_ilorest_client')
def test_set_boot_device(
self, mock_get_ilo_client, mock_get_ov_client):
ilo_client = mock_get_ilo_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)
self.assertFalse(ilo_client.called)
patch = ilo_client.patch
self.assertFalse(patch.called)
driver_internal_info = task.node.driver_internal_info
self.assertNotIn('next_boot_device', driver_internal_info)
@mock.patch.object(common, 'get_ilorest_client')
def test_set_boot_device_not_persistent(
self, mock_get_ilo_client, mock_get_ov_client):
ilo_client = mock_get_ilo_client()
client = mock_get_ov_client()
server_profile = {'boot': {'order':
list(management.BOOT_DEVICE_MAP_ONEVIEW_REV)}}
client.server_profiles.get.return_value = server_profile
boot_device_map_ilo = management.BOOT_DEVICE_MAP_ILO
boot_device = boot_device_map_ilo.get(boot_devices.PXE)
body = {
"Boot": {
"BootSourceOverrideTarget": boot_device,
"BootSourceOverrideEnabled": "Once"
}
}
with task_manager.acquire(self.context, self.node.uuid) as task:
driver_info = task.node.driver_info
profile_uri = driver_info.get('applied_server_profile_uri')
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)
update = client.server_profiles.update
update.assert_called_once_with(server_profile, profile_uri)
patch = ilo_client.patch
patch.assert_called_once_with(
path=management.ILO_SYSTEM_PATH,
body=body,
headers=management.ILO_REQUEST_HEADERS
)
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):
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(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):
client = mock_get_ov_client()
exc = client_exception.HPOneViewException()
client.server_profiles.get.side_effect = exc
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
self.assertRaises(
exception.OneViewError,
management.set_boot_device,
task
)
self.assertIn('next_boot_device', driver_internal_info)
@mock.patch.object(common, 'get_ilorest_client')
def test_set_onetime_boot_persistent(
self, mock_iloclient, mock_get_ov_client):
ilo_client = mock_iloclient()
driver_internal_info = self.node.driver_internal_info
next_boot_device = {'device': 'disk', 'persistent': False}
driver_internal_info['next_boot_device'] = next_boot_device
with task_manager.acquire(self.context, self.node.uuid) as task:
management.set_onetime_boot(task)
self.assertFalse(ilo_client.called)
self.assertFalse(ilo_client.patch.called)
@mock.patch.object(common, 'get_ilorest_client')
def test_set_onetime_boot_not_persistent(
self, mock_iloclient, mock_get_ov_client):
ilo_client = mock_iloclient()
boot_device = management.BOOT_DEVICE_MAP_ILO.get(boot_devices.DISK)
body = {
"Boot": {
"BootSourceOverrideTarget": boot_device,
"BootSourceOverrideEnabled": "Once"
}
}
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': False}
driver_internal_info['next_boot_device'] = next_boot_device
task.node.driver_internal_info = driver_internal_info
management.set_onetime_boot(task)
self.assertTrue(mock_iloclient.called)
ilo_client.patch.assert_called_once_with(
path=management.ILO_SYSTEM_PATH,
body=body,
headers=management.ILO_REQUEST_HEADERS
)
@mock.patch.object(common, 'get_ilorest_client')
def test__is_onetime_boot_true(
self, mock_iloclient, mock_get_ov_client):
class RestResponse(object):
@property
def dict(self):
return {'Boot': {'BootSourceOverrideEnabled': "Once"}}
ilo_client = mock_iloclient()
ilo_client.get.return_value = RestResponse()
with task_manager.acquire(self.context, self.node.uuid) as task:
self.assertTrue(management._is_onetime_boot(task))
self.assertTrue(mock_iloclient.called)
ilo_client.get.assert_called_with(
path=management.ILO_SYSTEM_PATH,
headers=management.ILO_REQUEST_HEADERS
)
@mock.patch.object(common, 'get_ilorest_client')
def test__is_onetime_boot_false(
self, mock_iloclient, mock_get_ov_client):
class RestResponse(object):
@property
def dict(self):
return {'Boot': {'BootSourceOverrideEnabled': "Disabled"}}
ilo_client = mock_iloclient()
ilo_client.get.return_value = RestResponse()
with task_manager.acquire(self.context, self.node.uuid) as task:
self.assertFalse(management._is_onetime_boot(task))
self.assertTrue(mock_iloclient.called)
ilo_client.get.assert_called_with(
path=management.ILO_SYSTEM_PATH,
headers=management.ILO_REQUEST_HEADERS
)
class OneViewManagementDriverTestCase(test_common.BaseOneViewTest):
def setUp(self):
super(OneViewManagementDriverTestCase, 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')
self.config(tls_cacert_file='ca_file', group='oneview')
self.config(allow_insecure_connections=False, group='oneview')
self.info = common.get_oneview_info(self.node)
@mock.patch.object(deploy_utils, 'is_node_in_use_by_ironic',
spect_set=True, autospec=True)
@mock.patch.object(common, 'validate_oneview_resources_compatibility',
spect_set=True, autospec=True)
def test_validate(self, mock_validate, mock_ironic_node):
mock_ironic_node.return_value = True
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.driver.management.validate(task)
self.assertTrue(mock_validate.called)
@mock.patch.object(deploy_utils, 'is_node_in_use_by_ironic',
spect_set=True, autospec=True)
def test_validate_for_node_not_in_use_by_ironic(self, mock_ironic_node):
mock_ironic_node.return_value = False
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):
node = obj_utils.create_test_node(
self.context, uuid=uuidutils.generate_uuid(),
id=999, driver='oneview'
)
with task_manager.acquire(self.context, node.uuid) as task:
self.assertRaises(exception.MissingParameterValue,
task.driver.management.validate, task)
@mock.patch.object(common, 'validate_oneview_resources_compatibility')
def test_validate_fail_exception(self, mock_validate):
mock_validate.side_effect = exception.OneViewError('message')
with task_manager.acquire(self.context, self.node.uuid) as task:
self.assertRaises(exception.InvalidParameterValue,
task.driver.management.validate,
task)
def test_get_properties(self):
expected = common.COMMON_PROPERTIES
self.assertItemsEqual(expected,
management.OneViewManagement().get_properties())
def test_set_boot_device_persistent_true(self):
with task_manager.acquire(self.context, self.node.uuid) as task:
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):
with task_manager.acquire(self.context, self.node.uuid) as task:
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):
with task_manager.acquire(self.context, self.node.uuid) as task:
self.assertRaises(exception.InvalidParameterValue,
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):
with task_manager.acquire(self.context, self.node.uuid) as task:
expected = [
boot_devices.PXE, boot_devices.DISK, boot_devices.CDROM
]
self.assertItemsEqual(
expected,
task.driver.management.get_supported_boot_devices(task),
)
@mock.patch.object(common, 'get_hponeview_client')
@mock.patch.object(common, 'get_ilorest_client')
def test_get_boot_device(self, mock_iloclient, mock_get_ov_client):
ilo_client = mock_iloclient()
oneview_client = mock_get_ov_client()
device_mapping = management.BOOT_DEVICE_MAP_ONEVIEW.items()
with task_manager.acquire(self.context, self.node.uuid) as task:
# For each known device on OneView, Ironic should return its
# counterpart value
for ironic_device, oneview_device in device_mapping:
profile = {'boot': {'order': [oneview_device]}}
oneview_client.server_profiles.get.return_value = profile
expected = {'boot_device': ironic_device, 'persistent': True}
response = management.OneViewManagement().get_boot_device(task)
self.assertEqual(expected, response)
self.assertTrue(oneview_client.server_profiles.get.called)
self.assertTrue(ilo_client.get.called)
@mock.patch.object(common, 'get_ilorest_client')
def test_get_boot_device_from_next_boot_device(self, mock_iloclient):
ilo_client = mock_iloclient()
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 = management.OneViewManagement().get_boot_device(task)
self.assertEqual(expected_response, response)
self.assertFalse(ilo_client.get.called)
@mock.patch.object(common, 'get_hponeview_client')
@mock.patch.object(common, 'get_ilorest_client')
def test_get_boot_device_fail(self, mock_iloclient, mock_get_ov_client):
client = mock_get_ov_client()
ilo_client = mock_iloclient()
exc = client_exception.HPOneViewException()
client.server_profiles.get.side_effect = exc
with task_manager.acquire(self.context, self.node.uuid) as task:
self.assertRaises(
exception.OneViewError,
management.OneViewManagement().get_boot_device,
task
)
self.assertTrue(client.server_profiles.get.called)
self.assertFalse(ilo_client.get.called)
@mock.patch.object(common, 'get_ilorest_client')
def test_get_boot_device_unknown_device(self, mock_iloclient):
ilo_client = mock_iloclient()
with task_manager.acquire(self.context, self.node.uuid) as task:
self.assertRaises(
exception.InvalidParameterValue,
task.driver.management.get_boot_device,
task
)
self.assertFalse(ilo_client.get.called)
def test_get_sensors_data_not_implemented(self):
with task_manager.acquire(self.context, self.node.uuid) as task:
self.assertRaises(
NotImplementedError,
task.driver.management.get_sensors_data,
task
)

View File

@ -1,308 +0,0 @@
# Copyright (2015-2017) Hewlett Packard Enterprise Development LP
# Copyright (2015-2017) Universidade Federal de Campina Grande
#
# 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 oslo_utils import importutils
from oslo_utils import uuidutils
from ironic.common import exception
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.drivers.modules.oneview import power
from ironic.tests.unit.drivers.modules.oneview import test_common
from ironic.tests.unit.objects import utils as obj_utils
client_exception = importutils.try_import('hpOneView.exceptions')
class OneViewPowerDriverTestCase(test_common.BaseOneViewTest):
def setUp(self):
super(OneViewPowerDriverTestCase, 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')
self.config(tls_cacert_file='ca_file', group='oneview')
self.config(allow_insecure_connections=False, group='oneview')
self.info = common.get_oneview_info(self.node)
deploy_utils.is_node_in_use_by_oneview = mock.Mock(return_value=False)
@mock.patch.object(common, 'validate_oneview_resources_compatibility')
def test_validate(self, mock_validate):
with task_manager.acquire(self.context, self.node.uuid) as task:
task.driver.power.validate(task)
self.assertTrue(mock_validate.called)
def test_validate_missing_parameter(self):
node = obj_utils.create_test_node(
self.context, uuid=uuidutils.generate_uuid(),
id=999, driver='oneview')
with task_manager.acquire(self.context, node.uuid) as task:
self.assertRaises(
exception.MissingParameterValue,
task.driver.power.validate,
task)
@mock.patch.object(common, 'validate_oneview_resources_compatibility')
def test_validate_exception(self, mock_validate):
mock_validate.side_effect = exception.OneViewError('message')
with task_manager.acquire(self.context, self.node.uuid) as task:
self.assertRaises(
exception.InvalidParameterValue,
task.driver.power.validate,
task)
def test_validate_node_in_use_by_oneview(self):
deploy_utils.is_node_in_use_by_oneview.return_value = True
with task_manager.acquire(self.context, self.node.uuid) as task:
self.assertRaises(
exception.InvalidParameterValue,
task.driver.power.validate,
task)
def test_get_properties(self):
expected = common.COMMON_PROPERTIES
self.assertEqual(expected, power.OneViewPower().get_properties())
@mock.patch.object(common, 'get_hponeview_client')
def test_get_power_state(self, mock_get_ov_client):
client = mock_get_ov_client()
server_hardware = {'powerState': 'On'}
client.server_hardware.get.return_value = server_hardware
with task_manager.acquire(self.context, self.node.uuid) as task:
power_state = power.OneViewPower().get_power_state(task)
self.assertEqual(states.POWER_ON, power_state)
@mock.patch.object(common, 'get_hponeview_client')
def test_get_power_state_fail(self, mock_get_ov_client):
client = mock_get_ov_client()
exc = client_exception.HPOneViewException()
client.server_hardware.get.side_effect = exc
with task_manager.acquire(self.context, self.node.uuid) as task:
self.assertRaises(
exception.OneViewError,
power.OneViewPower().get_power_state,
task)
@mock.patch.object(common, 'get_hponeview_client')
@mock.patch.object(management, 'set_boot_device')
def test_set_power_on(self, mock_set_boot_device, mock_get_ov_client):
client = mock_get_ov_client()
server_hardware = self.node.driver_info.get('server_hardware_uri')
with task_manager.acquire(self.context, self.node.uuid) as task:
power.OneViewPower().set_power_state(task, states.POWER_ON)
self.assertTrue(mock_set_boot_device.called)
update = client.server_hardware.update_power_state
update.assert_called_once_with(power.POWER_ON, server_hardware,
timeout=-1)
@mock.patch.object(common, 'get_hponeview_client')
@mock.patch.object(management, 'set_boot_device')
def test_set_power_on_with_timeout(
self, mock_set_boot_device, mock_get_ov_client):
client = mock_get_ov_client()
server_hardware = self.node.driver_info.get('server_hardware_uri')
with task_manager.acquire(self.context, self.node.uuid) as task:
power.OneViewPower().set_power_state(task, states.POWER_ON,
timeout=2)
self.assertTrue(mock_set_boot_device.called)
update = client.server_hardware.update_power_state
update.assert_called_once_with(power.POWER_ON, server_hardware,
timeout=2)
@mock.patch.object(common, 'get_hponeview_client')
@mock.patch.object(management, 'set_boot_device')
def test_set_power_off(self, mock_set_boot_device, mock_get_ov_client):
client = mock_get_ov_client()
server_hardware = self.node.driver_info.get('server_hardware_uri')
with task_manager.acquire(self.context, self.node.uuid) as task:
power.OneViewPower().set_power_state(task, states.POWER_OFF)
self.assertFalse(mock_set_boot_device.called)
update = client.server_hardware.update_power_state
update.assert_called_once_with(power.POWER_OFF, server_hardware,
timeout=-1)
@mock.patch.object(common, 'get_hponeview_client')
@mock.patch.object(management, 'set_boot_device')
def test_set_power_off_with_timeout(
self, mock_set_boot_device, mock_get_ov_client):
client = mock_get_ov_client()
server_hardware = self.node.driver_info.get('server_hardware_uri')
with task_manager.acquire(self.context, self.node.uuid) as task:
power.OneViewPower().set_power_state(task, states.POWER_OFF,
timeout=2)
self.assertFalse(mock_set_boot_device.called)
update = client.server_hardware.update_power_state
update.assert_called_once_with(power.POWER_OFF, server_hardware,
timeout=2)
@mock.patch.object(common, 'get_hponeview_client')
@mock.patch.object(management, 'set_boot_device')
def test_set_power_reboot(self, mock_set_boot_device, mock_get_ov_client):
client = mock_get_ov_client()
server_hardware = self.node.driver_info.get('server_hardware_uri')
with task_manager.acquire(self.context, self.node.uuid) as task:
power.OneViewPower().set_power_state(task, states.REBOOT)
calls = [mock.call(power.POWER_OFF, server_hardware, timeout=-1),
mock.call(power.POWER_ON, server_hardware, timeout=-1)]
update = client.server_hardware.update_power_state
update.assert_has_calls(calls)
@mock.patch.object(common, 'get_hponeview_client')
@mock.patch.object(management, 'set_boot_device')
def test_set_power_soft_reboot(
self, mock_set_boot_device, mock_get_ov_client):
client = mock_get_ov_client()
interface = power.OneViewPower()
interface.client = client
server_hardware = self.node.driver_info.get('server_hardware_uri')
with task_manager.acquire(self.context, self.node.uuid) as task:
interface.set_power_state(task, states.SOFT_REBOOT)
calls = [mock.call(power.SOFT_POWER_OFF, server_hardware,
timeout=-1),
mock.call(power.POWER_ON, server_hardware, timeout=-1)]
update = client.server_hardware.update_power_state
update.assert_has_calls(calls)
@mock.patch.object(common, 'get_hponeview_client')
@mock.patch.object(management, 'set_boot_device')
def test_set_power_on_fail(self, mock_set_boot_device, mock_get_ov_client):
client = mock_get_ov_client()
exc = client_exception.HPOneViewException()
client.server_hardware.update_power_state.side_effect = exc
with task_manager.acquire(self.context, self.node.uuid) as task:
self.assertRaises(
exception.OneViewError,
power.OneViewPower().set_power_state,
task,
states.POWER_ON)
mock_set_boot_device.assert_called_once_with(task)
@mock.patch.object(common, 'get_hponeview_client')
@mock.patch.object(management, 'set_boot_device')
def test_set_power_off_fail(
self, mock_set_boot_device, mock_get_ov_client):
client = mock_get_ov_client()
exc = client_exception.HPOneViewException()
client.server_hardware.update_power_state.side_effect = exc
with task_manager.acquire(self.context, self.node.uuid) as task:
self.assertRaises(
exception.OneViewError,
power.OneViewPower().set_power_state,
task,
states.POWER_OFF)
self.assertFalse(mock_set_boot_device.called)
@mock.patch.object(common, 'get_hponeview_client')
@mock.patch.object(management, 'set_boot_device')
def test_reboot_fail_with_hardware_on(
self, mock_set_boot_device, mock_get_ov_client):
client = mock_get_ov_client()
server_hardware = {'powerState': 'On'}
client.server_hardware.get.return_value = server_hardware
exc = client_exception.HPOneViewException()
client.server_hardware.update_power_state.side_effect = exc
interface = power.OneViewPower()
interface.client = client
with task_manager.acquire(self.context, self.node.uuid) as task:
self.assertRaises(
exception.OneViewError,
interface.reboot,
task)
self.assertFalse(mock_set_boot_device.called)
@mock.patch.object(common, 'get_hponeview_client')
@mock.patch.object(management, 'set_boot_device')
def test_reboot_fail_with_hardware_off(
self, mock_set_boot_device, mock_get_ov_client):
client = mock_get_ov_client()
server_hardware = {'powerState': 'Off'}
client.server_hardware.get.return_value = server_hardware
exc = client_exception.HPOneViewException()
client.server_hardware.update_power_state.side_effect = exc
with task_manager.acquire(self.context, self.node.uuid) as task:
self.assertRaises(
exception.OneViewError,
power.OneViewPower().reboot,
task)
mock_set_boot_device.assert_called_once_with(task)
@mock.patch.object(management, 'set_boot_device')
def test_set_power_invalid_state(self, mock_set_boot_device):
with task_manager.acquire(self.context, self.node.uuid) as task:
self.assertRaises(
exception.InvalidParameterValue,
power.OneViewPower().set_power_state,
task,
'fake_state')
self.assertFalse(mock_set_boot_device.called)
@mock.patch.object(common, 'get_hponeview_client')
@mock.patch.object(management, 'set_boot_device')
def test_set_power_reboot_with_hardware_on(
self, mock_set_boot_device, mock_get_ov_client):
client = mock_get_ov_client()
server_hardware = {'powerState': 'On'}
client.server_hardware.get.return_value = server_hardware
server_hardware = self.node.driver_info.get('server_hardware_uri')
with task_manager.acquire(self.context, self.node.uuid) as task:
power.OneViewPower().reboot(task)
calls = [mock.call(power.POWER_OFF, server_hardware, timeout=-1),
mock.call(power.POWER_ON, server_hardware, timeout=-1)]
update = client.server_hardware.update_power_state
update.assert_has_calls(calls)
mock_set_boot_device.assert_called_once_with(task)
@mock.patch.object(common, 'get_hponeview_client')
@mock.patch.object(management, 'set_boot_device')
def test_set_power_reboot_with_hardware_off(
self, mock_set_boot_device, mock_get_ov_client):
client = mock_get_ov_client()
server_hardware = {'powerState': 'Off'}
client.server_hardware.get.return_value = server_hardware
server_hardware = self.node.driver_info.get('server_hardware_uri')
with task_manager.acquire(self.context, self.node.uuid) as task:
power.OneViewPower().reboot(task, timeout=-1)
update = client.server_hardware.update_power_state
update.assert_called_once_with(power.POWER_ON, server_hardware,
timeout=-1)
mock_set_boot_device.assert_called_once_with(task)
@mock.patch.object(common, 'get_hponeview_client')
@mock.patch.object(management, 'set_boot_device')
def test_set_power_reboot_with_hardware_off_with_timeout(
self, mock_set_boot_device, mock_get_ov_client):
client = mock_get_ov_client()
server_hardware = {'powerState': 'Off'}
client.server_hardware.get.return_value = server_hardware
server_hardware = self.node.driver_info.get('server_hardware_uri')
with task_manager.acquire(self.context, self.node.uuid) as task:
power.OneViewPower().reboot(task, timeout=2)
update = client.server_hardware.update_power_state
update.assert_called_once_with(power.POWER_ON, server_hardware,
timeout=2)
mock_set_boot_device.assert_called_once_with(task)
def test_get_supported_power_states(self):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
supported_power_states = (
task.driver.power.get_supported_power_states(task))
self.assertEqual(set(power.SET_POWER_STATE_MAP),
set(supported_power_states))

View File

@ -1,126 +0,0 @@
# Copyright (2015-2017) Hewlett Packard Enterprise Development LP
# Copyright (2015-2017) Universidade Federal de Campina Grande
#
# 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.
"""Test class for HPE OneView Drivers."""
from ironic.conductor import task_manager
from ironic.drivers.modules import agent
from ironic.drivers.modules import noop
from ironic.drivers.modules import pxe
from ironic.drivers.modules.storage import noop as noop_storage
from ironic.drivers import oneview
from ironic.tests.unit.db import base as db_base
from ironic.tests.unit.objects import utils as obj_utils
class OneViewHardwareTestCase(db_base.DbTestCase):
def setUp(self):
super(OneViewHardwareTestCase, self).setUp()
self.config(enabled_hardware_types=['oneview'],
enabled_deploy_interfaces=[
'oneview-direct', 'oneview-iscsi'],
enabled_inspect_interfaces=['oneview'],
enabled_management_interfaces=['oneview'],
enabled_power_interfaces=['oneview'],
enabled_raid_interfaces=['no-raid', 'agent'],
enabled_console_interfaces=['no-console'],
enabled_vendor_interfaces=['no-vendor'])
def test_default_interfaces(self):
node = obj_utils.create_test_node(self.context,
driver='oneview')
with task_manager.acquire(self.context, node.id) as task:
self.assertIsInstance(task.driver.boot,
pxe.PXEBoot)
self.assertIsInstance(task.driver.deploy,
oneview.deploy.OneViewIscsiDeploy)
self.assertIsInstance(task.driver.inspect,
oneview.inspect.OneViewInspect)
self.assertIsInstance(task.driver.management,
oneview.management.OneViewManagement)
self.assertIsInstance(task.driver.power,
oneview.power.OneViewPower),
self.assertIsInstance(task.driver.storage,
noop_storage.NoopStorage),
self.assertIsInstance(task.driver.console,
noop.NoConsole),
self.assertIsInstance(task.driver.raid,
noop.NoRAID)
self.assertIsInstance(task.driver.vendor,
noop.NoVendor)
def test_default_with_inspector_interface_enabled(self):
self.config(enabled_inspect_interfaces=['inspector', 'oneview'])
node = obj_utils.create_test_node(
self.context, driver='oneview',
deploy_interface='oneview-direct',
inspect_interface='oneview',
raid_interface='agent')
with task_manager.acquire(self.context, node.id) as task:
self.assertIsInstance(task.driver.boot,
pxe.PXEBoot)
self.assertIsInstance(task.driver.deploy,
oneview.deploy.OneViewAgentDeploy)
self.assertIsInstance(task.driver.inspect,
oneview.inspect.OneViewInspect)
self.assertIsInstance(task.driver.management,
oneview.management.OneViewManagement)
self.assertIsInstance(task.driver.power,
oneview.power.OneViewPower)
self.assertIsInstance(task.driver.raid,
agent.AgentRAID)
self.assertIsInstance(task.driver.vendor,
noop.NoVendor)
def test_override_with_direct(self):
node = obj_utils.create_test_node(
self.context, driver='oneview',
deploy_interface='oneview-direct',
boot_interface='pxe',
raid_interface='agent')
with task_manager.acquire(self.context, node.id) as task:
self.assertIsInstance(task.driver.boot,
pxe.PXEBoot)
self.assertIsInstance(task.driver.deploy,
oneview.deploy.OneViewAgentDeploy)
self.assertIsInstance(task.driver.inspect,
oneview.inspect.OneViewInspect)
self.assertIsInstance(task.driver.management,
oneview.management.OneViewManagement)
self.assertIsInstance(task.driver.power,
oneview.power.OneViewPower)
self.assertIsInstance(task.driver.raid,
agent.AgentRAID)
def test_override_with_iscsi(self):
node = obj_utils.create_test_node(
self.context, driver='oneview',
deploy_interface='oneview-iscsi',
boot_interface='pxe',
raid_interface='agent')
with task_manager.acquire(self.context, node.id) as task:
self.assertIsInstance(task.driver.boot,
pxe.PXEBoot)
self.assertIsInstance(task.driver.deploy,
oneview.deploy.OneViewIscsiDeploy)
self.assertIsInstance(task.driver.inspect,
oneview.inspect.OneViewInspect)
self.assertIsInstance(task.driver.management,
oneview.management.OneViewManagement)
self.assertIsInstance(task.driver.power,
oneview.power.OneViewPower)
self.assertIsInstance(task.driver.raid,
agent.AgentRAID)

View File

@ -123,24 +123,6 @@ SCCICLIENT_VIOM_CONF_SPEC = (
'terminate',
)
HPE_ONEVIEW_SPEC = (
'oneview_client',
'resources',
'exceptions',
)
HPE_ONEVIEW_CLS_SPEC = (
)
HPE_ONEVIEW_STATES_SPEC = (
'ONEVIEW_POWER_OFF',
'ONEVIEW_POWERING_OFF',
'ONEVIEW_POWER_ON',
'ONEVIEW_POWERING_ON',
'ONEVIEW_RESETTING',
'ONEVIEW_ERROR',
)
REDFISH_SPEC = (
'redfish',
)

View File

@ -25,7 +25,6 @@ Current list of mocked libraries:
- proliantutils
- pysnmp
- scciclient
- hpOneView
- pywsman
- python-dracclient
"""
@ -69,30 +68,13 @@ if not proliantutils:
if 'ironic.drivers.ilo' in sys.modules:
six.moves.reload_module(sys.modules['ironic.drivers.ilo'])
hpOneView = importutils.try_import('hpOneView')
if not hpOneView:
hpOneView = mock.MagicMock(spec_set=mock_specs.HPE_ONEVIEW_SPEC)
sys.modules['hpOneView'] = hpOneView
sys.modules['hpOneView.oneview_client'] = hpOneView.oneview_client
sys.modules['hpOneView.resources'] = hpOneView.resources
sys.modules['hpOneView.exceptions'] = hpOneView.exceptions
hpOneView.exceptions.HPOneViewException = type('HPOneViewException',
(Exception,), {})
sys.modules['hpOneView.oneview_client'].OneViewClient = mock.MagicMock(
spec_set=mock_specs.HPE_ONEVIEW_CLS_SPEC
)
if 'ironic.drivers.oneview' in sys.modules:
six.moves.reload_module(sys.modules['ironic.drivers.modules.oneview'])
redfish = importutils.try_import('redfish')
if not redfish:
redfish = mock.MagicMock(spec_set=mock_specs.REDFISH_SPEC)
sys.modules['redfish'] = redfish
if 'ironic.drivers.oneview' in sys.modules:
six.moves.reload_module(sys.modules['ironic.drivers.modules.oneview'])
if 'ironic.drivers.redfish' in sys.modules:
six.moves.reload_module(sys.modules['ironic.drivers.modules.redfish'])
# attempt to load the external 'python-dracclient' library, which is required
# by the optional drivers.modules.drac module

View File

@ -0,0 +1,7 @@
---
other:
- |
The ``oneview`` hardware type and related interfaces have been
removed due to a lack of maintainer and 3rd-party CI. Please see
`story 2001924 <https://storyboard.openstack.org/#!/story/2001924>`_
for additional information.

View File

@ -79,8 +79,6 @@ ironic.hardware.interfaces.deploy =
direct = ironic.drivers.modules.agent:AgentDeploy
fake = ironic.drivers.modules.fake:FakeDeploy
iscsi = ironic.drivers.modules.iscsi_deploy:ISCSIDeploy
oneview-direct = ironic.drivers.modules.oneview.deploy:OneViewAgentDeploy
oneview-iscsi = ironic.drivers.modules.oneview.deploy:OneViewIscsiDeploy
ramdisk = ironic.drivers.modules.pxe:PXERamdiskDeploy
ironic.hardware.interfaces.inspect =
@ -90,7 +88,6 @@ ironic.hardware.interfaces.inspect =
inspector = ironic.drivers.modules.inspector:Inspector
irmc = ironic.drivers.modules.irmc.inspect:IRMCInspect
no-inspect = ironic.drivers.modules.noop:NoInspect
oneview = ironic.drivers.modules.oneview.inspect:OneViewInspect
ironic.hardware.interfaces.management =
cimc = ironic.drivers.modules.cimc.management:CIMCManagement
@ -100,7 +97,6 @@ ironic.hardware.interfaces.management =
ipmitool = ironic.drivers.modules.ipmitool:IPMIManagement
irmc = ironic.drivers.modules.irmc.management:IRMCManagement
noop = ironic.drivers.modules.noop_mgmt:NoopManagement
oneview = ironic.drivers.modules.oneview.management:OneViewManagement
redfish = ironic.drivers.modules.redfish.management:RedfishManagement
ucsm = ironic.drivers.modules.ucs.management:UcsManagement
xclarity = ironic.drivers.modules.xclarity.management:XClarityManagement
@ -117,7 +113,6 @@ ironic.hardware.interfaces.power =
ilo = ironic.drivers.modules.ilo.power:IloPower
ipmitool = ironic.drivers.modules.ipmitool:IPMIPower
irmc = ironic.drivers.modules.irmc.power:IRMCPower
oneview = ironic.drivers.modules.oneview.power:OneViewPower
redfish = ironic.drivers.modules.redfish.power:RedfishPower
snmp = ironic.drivers.modules.snmp:SNMPPower
ucsm = ironic.drivers.modules.ucs.power:Power
@ -157,7 +152,6 @@ ironic.hardware.types =
ipmi = ironic.drivers.ipmi:IPMIHardware
irmc = ironic.drivers.irmc:IRMCHardware
manual-management = ironic.drivers.generic:ManualManagementHardware
oneview = ironic.drivers.oneview:OneViewHardware
redfish = ironic.drivers.redfish:RedfishHardware
snmp = ironic.drivers.snmp:SNMPHardware
xclarity = ironic.drivers.xclarity:XClarityHardware