Remove iLO hardware type and interfaces

As early as 2024 we've been warning operators the iLO driver was going
away, and it was formally deprecated in 2025.2. We now remove it fully.

iLO 5 and newer devices are still supported by redfish driver.

Generated-by: claude-code
Change-Id: Iccc45da6eb3b8109009e3217028cc07f5782dde0
Signed-off-by: Jay Faulkner <jay@jvf.cc>
This commit is contained in:
Jay Faulkner
2026-04-07 10:12:18 -07:00
parent 7ceef452de
commit afb64cf26c
67 changed files with 45 additions and 17882 deletions
-12
View File
@@ -973,11 +973,6 @@ function is_deployed_by_ipmi {
return 1
}
function is_deployed_by_ilo {
[[ "${IRONIC_DEPLOY_DRIVER}" == ilo ]] && return 0
return 1
}
function is_deployed_by_drac {
[[ "${IRONIC_DEPLOY_DRIVER}" == idrac ]] && return 0
return 1
@@ -3345,13 +3340,6 @@ function enroll_nodes {
node_options+=" --driver-info ipmi_address=$bmc_address \
--driver-info ipmi_password=$bmc_passwd \
--driver-info ipmi_username=$bmc_username"
elif is_deployed_by_ilo; then
node_options+=" --driver-info ilo_address=$bmc_address \
--driver-info ilo_password=$bmc_passwd \
--driver-info ilo_username=$bmc_username"
if [[ $IRONIC_ENABLED_BOOT_INTERFACES == *"ilo-virtual-media"* ]]; then
node_options+=" --driver-info deploy_iso=$IRONIC_DEPLOY_ISO_ID"
fi
elif is_deployed_by_drac; then
node_options+=" --driver-info drac_address=$bmc_address \
--driver-info drac_password=$bmc_passwd \
+5 -5
View File
@@ -24,11 +24,11 @@ the node OR the iPXE boot templates such that the node CAN be booted.
.. figure:: ./../images/boot-from-volume.svg
:width: 100%
In this example, the boot interface does the heavy lifting. For the
``ilo`` hardware type with its hardware type-specific boot
interface, it is able to signal via an out-of-band mechanism to the
baremetal node's BMC that the integrated iSCSI initiators are to connect
to the supplied volume target information.
In this example, the boot interface does the heavy lifting. Some
hardware types with vendor-specific boot interfaces are able to
signal via an out-of-band mechanism to the baremetal node's BMC
that the integrated iSCSI initiators are to connect to the supplied
volume target information.
In most hardware, this would be the network cards of the machine.
+4 -8
View File
@@ -471,13 +471,10 @@ Hardware Manager.
Out-of-band
-----------
Out-of-band are actions performed by your management controller, such as IPMI,
iLO, or DRAC. Out-of-band steps will be performed by Ironic using a power or
management interface. Which steps are performed depends on the hardware type
and hardware itself.
For Out-of-Band cleaning operations supported by iLO hardware types, refer to
:ref:`ilo_node_cleaning`.
Out-of-band are actions performed by your management controller, such as
IPMI or DRAC. Out-of-band steps will be performed by Ironic using a
power or management interface. Which steps are performed depends on the
hardware type and hardware itself.
FAQ
===
@@ -524,7 +521,6 @@ multiple configuration values:
[conductor]
clean_step_priority_override=deploy.erase_devices_metadata:123
clean_step_priority_override=management.reset_bios_to_default:234
clean_step_priority_override=management.clean_priority_reset_ilo:345
This parameter can be specified as many times as required to define priorities
for several cleaning steps - the values will be combined.
-1
View File
@@ -33,7 +33,6 @@ Hardware type support
This feature is known to work with the following hardware types:
* :doc:`Redfish </admin/drivers/redfish>` with ``redfish-virtual-media`` boot
* :doc:`iLO </admin/drivers/ilo>` with ``ilo-virtual-media`` boot
Configuring network data
------------------------
-1
View File
@@ -25,7 +25,6 @@ Hardware Types
:maxdepth: 1
drivers/idrac
drivers/ilo
drivers/intel-ipmi
drivers/ipmitool
drivers/redfish
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -6,7 +6,7 @@ Capabilities discovery
This is an incomplete list of capabilities we want to discover during
inspection. The exact support is hardware and hardware type specific though,
the most complete list is provided by the iLO :ref:`ilo-inspection`.
the exact support depends on the hardware type in use.
``secure_boot`` (``true`` or ``false``)
whether secure boot is supported for the node
+1 -1
View File
@@ -13,7 +13,7 @@ discovered ethernet MACs.
There are two kinds of inspection supported by Bare Metal service:
#. Out-of-band inspection is currently implemented by several hardware types,
including ``redfish``, ``ilo`` and ``idrac``.
including ``redfish`` and ``idrac``.
#. In-band inspection, also known as Agent inspection
utilizing Ironic Python Agent to collect information.
+1 -2
View File
@@ -33,8 +33,7 @@ process.
architectures that do not have BIOS support at all.
The ``ipxe`` boot interface is used by default for many hardware types,
including ``ipmi``. Some hardware types, notably ``ilo``, have
their specific implementations of the PXE boot interface.
including ``ipmi``.
Additional configuration is required for this boot interface - see
:doc:`/install/configure-pxe` for details.
+1 -2
View File
@@ -42,8 +42,7 @@ Build agent ramdisk which supports RAID configuration
For doing in-band hardware RAID configuration, Ironic needs an agent ramdisk
bundled with a hardware manager which supports RAID configuration for your
hardware. For example, the :ref:`DIB_raid_support` should be used for HPE
Proliant Servers.
hardware.
.. note::
For in-band software RAID, the agent ramdisk does not need to be bundled
+2 -2
View File
@@ -5,8 +5,8 @@ Ironic supports booting a user provided ramdisk or an ISO image (starting with
the Victoria release) instead of deploying a node.
Most commonly this is performed when an instance is booted via PXE, iPXE or
Virtual Media, with the only local storage contents being those in memory.
It is supported by ``pxe``, ``ipxe``, ``redfish-virtual-media`` and
``ilo-virtual-media`` boot interfaces.
It is supported by ``pxe``, ``ipxe`` and ``redfish-virtual-media``
boot interfaces.
Configuration
-------------
-17
View File
@@ -368,23 +368,6 @@ glance:
swift_temp_url_key = ***
timeout = None
ilo:
ca_file = None
clean_priority_clear_secure_boot_keys = 0
clean_priority_erase_devices = None
clean_priority_reset_bios_to_default = 10
clean_priority_reset_ilo = 0
clean_priority_reset_ilo_credential = 30
clean_priority_reset_secure_boot_keys_to_default = 20
client_port = 443
client_timeout = 60
default_boot_mode = auto
power_retry = 6
power_wait = 2
swift_ilo_container = ironic_ilo_container
swift_object_expiry_timeout = 900
use_web_server_for_images = False
inspector:
auth_section = None
auth_type = password
+1 -2
View File
@@ -226,8 +226,7 @@ Driver support for Deployment with Secure Boot
----------------------------------------------
Some hardware types support turning `UEFI secure boot`_ dynamically when
deploying an instance. Currently these are :doc:`/admin/drivers/ilo`
and :doc:`/admin/drivers/redfish`.
deploying an instance. Currently this is :doc:`/admin/drivers/redfish`.
Other drivers, such as :doc:`/admin/drivers/ipmitool`, may be able to be manually
configured on the host, but as there is not standardization of Secure Boot
-7
View File
@@ -1538,13 +1538,6 @@ For example, with iDRAC drivers...
The ``drac_username`` and ``drac_password`` parameters were used by WSMAN
Dell iDRAC drivers. Newer versions of the drivers utilize Redfish natively.
For example, with iLO drivers...
.. code-block:: console
$ openstack baremetal node set --driver-info ilo_username=<new_user> --driver-info ilo_password=<new_pass> <node_uuid>
$ openstack baremetal node maintenance unset <node_uuid>
.. note::
Ironic generally does not manage or rotate the remote BMC credentials due
to the risk of user lockout if the account is not for the specific use of
@@ -1,34 +0,0 @@
diagram {
Glance; Conductor; Baremetal; Swift; IPA; iLO;
activation = none;
span_height = 1;
edge_length = 250;
default_note_color = white;
default_fontsize = 14;
Conductor -> iLO [label = "Powers off the node"];
Conductor -> Glance [label = "Get the metadata for deploy ISO"];
Glance -> Conductor [label = "Returns the metadata for deploy ISO"];
Conductor -> Conductor [label = "Generates swift tempURL for deploy ISO"];
Conductor -> Conductor [label = "Creates the FAT32 image containing ironic API URL and driver name"];
Conductor -> Swift [label = "Uploads the FAT32 image"];
Conductor -> Conductor [label = "Generates swift tempURL for FAT32 image"];
Conductor -> iLO [label = "Attaches the FAT32 image swift tempURL as virtual media floppy"];
Conductor -> iLO [label = "Attaches the deploy ISO swift tempURL as virtual media CDROM"];
Conductor -> iLO [label = "Sets one time boot to CDROM"];
Conductor -> iLO [label = "Reboot the node"];
iLO -> Swift [label = "Downloads deploy ISO"];
Baremetal -> iLO [label = "Boots deploy kernel/ramdisk from iLO virtual media CDROM"];
IPA -> Conductor [label = "Lookup node"];
Conductor -> IPA [label = "Provides node UUID"];
IPA -> Conductor [label = "Heartbeat"];
Conductor -> IPA [label = "Sends the user image HTTP(S) URL"];
IPA -> Swift [label = "Retrieves the user image on bare metal"];
IPA -> IPA [label = "Writes user image to root partition"];
IPA -> IPA [label = "Installs boot loader"];
IPA -> Conductor [label = "Heartbeat"];
Conductor -> Baremetal [label = "Sets boot device to disk"];
Conductor -> IPA [label = "Power off the node"];
Conductor -> iLO [label = "Power on the node"];
Baremetal -> Baremetal [label = "Boot user image from disk"];
}
@@ -1,169 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg viewBox="0 0 1506 1127" xmlns="http://www.w3.org/2000/svg" xmlns:inkspace="http://www.inkscape.org/namespaces/inkscape" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs id="defs_block">
<filter height="1.504" id="filter_blur" inkspace:collect="always" width="1.1575" x="-0.07875" y="-0.252">
<feGaussianBlur id="feGaussianBlur3780" inkspace:collect="always" stdDeviation="4.2" />
</filter>
</defs>
<title>blockdiag</title>
<desc>diagram {
Glance; Conductor; Baremetal; Swift; IPA; iLO;
activation = none;
span_height = 1;
edge_length = 250;
default_note_color = white;
default_fontsize = 14;
Conductor -&gt; iLO [label = "Powers off the node"];
Conductor -&gt; Glance [label = "Get the metadata for deploy ISO"];
Glance -&gt; Conductor [label = "Returns the metadata for deploy ISO"];
Conductor -&gt; Conductor [label = "Generates swift tempURL for deploy ISO"];
Conductor -&gt; Conductor [label = "Creates the FAT32 image containing ironic API URL and driver name"];
Conductor -&gt; Swift [label = "Uploads the FAT32 image"];
Conductor -&gt; Conductor [label = "Generates swift tempURL for FAT32 image"];
Conductor -&gt; iLO [label = "Attaches the FAT32 image swift tempURL as virtual media floppy"];
Conductor -&gt; iLO [label = "Attaches the deploy ISO swift tempURL as virtual media CDROM"];
Conductor -&gt; iLO [label = "Sets one time boot to CDROM"];
Conductor -&gt; iLO [label = "Reboot the node"];
iLO -&gt; Swift [label = "Downloads deploy ISO"];
Baremetal -&gt; iLO [label = "Boots deploy kernel/ramdisk from iLO virtual media CDROM"];
IPA -&gt; Conductor [label = "Lookup node"];
Conductor -&gt; IPA [label = "Provides node UUID"];
IPA -&gt; Conductor [label = "Heartbeat"];
Conductor -&gt; IPA [label = "Sends the user image HTTP(S) URL"];
IPA -&gt; Swift [label = "Retrieves the user image on bare metal"];
IPA -&gt; IPA [label = "Writes user image to root partition"];
IPA -&gt; IPA [label = "Installs boot loader"];
IPA -&gt; Conductor [label = "Heartbeat"];
Conductor -&gt; Baremetal [label = "Sets boot device to disk"];
Conductor -&gt; IPA [label = "Power off the node"];
Conductor -&gt; iLO [label = "Power on the node"];
Baremetal -&gt; Baremetal [label = "Boot user image from disk"];
}
</desc>
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="67" y="7" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="317" y="7" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="567" y="7" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="817" y="7" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="1067" y="7" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="1317" y="7" />
<path d="M 128 41 L 128 1134" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<path d="M 378 41 L 378 1134" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<path d="M 628 41 L 628 1134" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<path d="M 878 41 L 878 1134" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<path d="M 1128 41 L 1128 1134" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<path d="M 1378 41 L 1378 1134" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="64" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="45" x="128.5" y="28">Glance</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="314" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="68" x="378.0" y="28">Conductor</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="564" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="68" x="628.0" y="28">Baremetal</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="814" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="38" x="878.0" y="28">Swift</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="1064" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="22" x="1128.0" y="28">IPA</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="1314" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="22" x="1378.0" y="28">iLO</text>
<path d="M 386 60 L 1370 60" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,56 1370,60 1362,64" stroke="rgb(0,0,0)" />
<path d="M 136 105 L 370 105" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="144,101 136,105 144,109" stroke="rgb(0,0,0)" />
<path d="M 136 150 L 370 150" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="362,146 370,150 362,154" stroke="rgb(0,0,0)" />
<path d="M 386 211 L 503 211" fill="none" stroke="rgb(0,0,0)" />
<path d="M 503 211 L 503 227" fill="none" stroke="rgb(0,0,0)" />
<path d="M 503 227 L 386 227" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="394,223 386,227 394,231" stroke="rgb(0,0,0)" />
<path d="M 386 320 L 503 320" fill="none" stroke="rgb(0,0,0)" />
<path d="M 503 320 L 503 336" fill="none" stroke="rgb(0,0,0)" />
<path d="M 503 336 L 386 336" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="394,332 386,336 394,340" stroke="rgb(0,0,0)" />
<path d="M 386 365 L 870 365" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="862,361 870,365 862,369" stroke="rgb(0,0,0)" />
<path d="M 386 426 L 503 426" fill="none" stroke="rgb(0,0,0)" />
<path d="M 503 426 L 503 442" fill="none" stroke="rgb(0,0,0)" />
<path d="M 503 442 L 386 442" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="394,438 386,442 394,446" stroke="rgb(0,0,0)" />
<path d="M 386 471 L 1370 471" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,467 1370,471 1362,475" stroke="rgb(0,0,0)" />
<path d="M 386 500 L 1370 500" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,496 1370,500 1362,504" stroke="rgb(0,0,0)" />
<path d="M 386 529 L 1370 529" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,525 1370,529 1362,533" stroke="rgb(0,0,0)" />
<path d="M 386 558 L 1370 558" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,554 1370,558 1362,562" stroke="rgb(0,0,0)" />
<path d="M 886 587 L 1370 587" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="894,583 886,587 894,591" stroke="rgb(0,0,0)" />
<path d="M 636 616 L 1370 616" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,612 1370,616 1362,620" stroke="rgb(0,0,0)" />
<path d="M 386 645 L 1120 645" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="394,641 386,645 394,649" stroke="rgb(0,0,0)" />
<path d="M 386 674 L 1120 674" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1112,670 1120,674 1112,678" stroke="rgb(0,0,0)" />
<path d="M 386 703 L 1120 703" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="394,699 386,703 394,707" stroke="rgb(0,0,0)" />
<path d="M 386 732 L 1120 732" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1112,728 1120,732 1112,736" stroke="rgb(0,0,0)" />
<path d="M 886 777 L 1120 777" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="894,773 886,777 894,781" stroke="rgb(0,0,0)" />
<path d="M 1136 838 L 1253 838" fill="none" stroke="rgb(0,0,0)" />
<path d="M 1253 838 L 1253 854" fill="none" stroke="rgb(0,0,0)" />
<path d="M 1253 854 L 1136 854" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1144,850 1136,854 1144,858" stroke="rgb(0,0,0)" />
<path d="M 1136 899 L 1253 899" fill="none" stroke="rgb(0,0,0)" />
<path d="M 1253 899 L 1253 915" fill="none" stroke="rgb(0,0,0)" />
<path d="M 1253 915 L 1136 915" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1144,911 1136,915 1144,919" stroke="rgb(0,0,0)" />
<path d="M 386 944 L 1120 944" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="394,940 386,944 394,948" stroke="rgb(0,0,0)" />
<path d="M 386 973 L 620 973" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="612,969 620,973 612,977" stroke="rgb(0,0,0)" />
<path d="M 386 1002 L 1120 1002" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1112,998 1120,1002 1112,1006" stroke="rgb(0,0,0)" />
<path d="M 386 1031 L 1370 1031" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,1027 1370,1031 1362,1035" stroke="rgb(0,0,0)" />
<path d="M 636 1076 L 753 1076" fill="none" stroke="rgb(0,0,0)" />
<path d="M 753 1076 L 753 1092" fill="none" stroke="rgb(0,0,0)" />
<path d="M 753 1092 L 636 1092" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="644,1088 636,1092 644,1096" stroke="rgb(0,0,0)" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="145" x="466.5" y="56">Powers off the node</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="229" x="251.5" y="85">Get the metadata for deploy IS</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="7" x="362.5" y="101">O</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="229" x="258.5" y="130">Returns the metadata for deplo</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="38" x="163.0" y="146">y ISO</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="458.5" y="175">Generates swift te</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="458.5" y="191">mpURL for deploy I</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="15" x="397.5" y="207">SO</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="458.5" y="260">Creates the FAT32 </text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="458.5" y="276">image containing i</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="458.5" y="292">ronic API URL and </text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="84" x="432.0" y="308">driver name</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="175" x="481.5" y="361">Uploads the FAT32 image</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="458.5" y="390">Generates swift te</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="458.5" y="406">mpURL for FAT32 im</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="22" x="401.0" y="422">age</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="473" x="630.5" y="467">Attaches the FAT32 image swift tempURL as virtual media floppy</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="458" x="623.0" y="496">Attaches the deploy ISO swift tempURL as virtual media CDROM</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="206" x="497.0" y="525">Sets one time boot to CDROM</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="114" x="451.0" y="554">Reboot the node</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="152" x="1290.0" y="583">Downloads deploy ISO</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="427" x="857.5" y="612">Boots deploy kernel/ramdisk from iLO virtual media CDROM</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="84" x="1074.0" y="641">Lookup node</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="462.5" y="670">Provides node UUID</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="68" x="1082.0" y="699">Heartbeat</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="244" x="516.0" y="728">Sends the user image HTTP(S) URL</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="229" x="1001.5" y="757">Retrieves the user image on ba</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="61" x="1085.5" y="773">re metal</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="1208.5" y="810">Writes user image </text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="129" x="1204.5" y="826">to root partition</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="1208.5" y="879">Installs boot load</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="15" x="1147.5" y="895">er</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="68" x="1082.0" y="940">Heartbeat</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="183" x="485.5" y="969">Sets boot device to disk</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="462.5" y="998">Power off the node</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="129" x="458.5" y="1027">Power on the node</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="708.5" y="1056">Boot user image fr</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="53" x="666.5" y="1072">om disk</text>
</svg>

Before

Width:  |  Height:  |  Size: 17 KiB

@@ -1,33 +0,0 @@
diagram {
Glance; Conductor; Baremetal; Swift; IPA; iLO;
activation = none;
span_height = 1;
edge_length = 250;
default_note_color = white;
default_fontsize = 14;
Conductor -> iLO [label = "Powers off the node"];
Conductor -> Glance [label = "Get the metadata for deploy ISO"];
Glance -> Conductor [label = "Returns the metadata for deploy ISO"];
Conductor -> Conductor [label = "Generates swift tempURL for deploy ISO"];
Conductor -> Conductor [label = "Creates the FAT32 image containing ironic API URL and driver name"];
Conductor -> Swift [label = "Uploads the FAT32 image"];
Conductor -> Conductor [label = "Generates swift tempURL for FAT32 image"];
Conductor -> iLO [label = "Attaches the FAT32 image swift tempURL as virtual media floppy"];
Conductor -> iLO [label = "Attaches the deploy ISO swift tempURL as virtual media CDROM"];
Conductor -> iLO [label = "Sets one time boot to CDROM"];
Conductor -> iLO [label = "Reboot the node"];
iLO -> Swift [label = "Downloads deploy ISO"];
Baremetal -> iLO [label = "Boots deploy kernel/ramdisk from iLO virtual media CDROM"];
IPA -> Conductor [label = "Lookup node"];
Conductor -> IPA [label = "Provides node UUID"];
IPA -> Conductor [label = "Heartbeat"];
Conductor -> IPA [label = "Sends the user image HTTP(S) URL"];
IPA -> Swift [label = "Retrieves the user image on bare metal"];
IPA -> IPA [label = "Writes user image to disk"];
IPA -> Conductor [label = "Heartbeat"];
Conductor -> Baremetal [label = "Sets boot device to disk"];
Conductor -> IPA [label = "Power off the node"];
Conductor -> iLO [label = "Power on the node"];
Baremetal -> Baremetal [label = "Boot user image from disk"];
}
@@ -1,162 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg viewBox="0 0 1506 1050" xmlns="http://www.w3.org/2000/svg" xmlns:inkspace="http://www.inkscape.org/namespaces/inkscape" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs id="defs_block">
<filter height="1.504" id="filter_blur" inkspace:collect="always" width="1.1575" x="-0.07875" y="-0.252">
<feGaussianBlur id="feGaussianBlur3780" inkspace:collect="always" stdDeviation="4.2" />
</filter>
</defs>
<title>blockdiag</title>
<desc>diagram {
Glance; Conductor; Baremetal; Swift; IPA; iLO;
activation = none;
span_height = 1;
edge_length = 250;
default_note_color = white;
default_fontsize = 14;
Conductor -&gt; iLO [label = "Powers off the node"];
Conductor -&gt; Glance [label = "Get the metadata for deploy ISO"];
Glance -&gt; Conductor [label = "Returns the metadata for deploy ISO"];
Conductor -&gt; Conductor [label = "Generates swift tempURL for deploy ISO"];
Conductor -&gt; Conductor [label = "Creates the FAT32 image containing ironic API URL and driver name"];
Conductor -&gt; Swift [label = "Uploads the FAT32 image"];
Conductor -&gt; Conductor [label = "Generates swift tempURL for FAT32 image"];
Conductor -&gt; iLO [label = "Attaches the FAT32 image swift tempURL as virtual media floppy"];
Conductor -&gt; iLO [label = "Attaches the deploy ISO swift tempURL as virtual media CDROM"];
Conductor -&gt; iLO [label = "Sets one time boot to CDROM"];
Conductor -&gt; iLO [label = "Reboot the node"];
iLO -&gt; Swift [label = "Downloads deploy ISO"];
Baremetal -&gt; iLO [label = "Boots deploy kernel/ramdisk from iLO virtual media CDROM"];
IPA -&gt; Conductor [label = "Lookup node"];
Conductor -&gt; IPA [label = "Provides node UUID"];
IPA -&gt; Conductor [label = "Heartbeat"];
Conductor -&gt; IPA [label = "Sends the user image HTTP(S) URL"];
IPA -&gt; Swift [label = "Retrieves the user image on bare metal"];
IPA -&gt; IPA [label = "Writes user image to disk"];
IPA -&gt; Conductor [label = "Heartbeat"];
Conductor -&gt; Baremetal [label = "Sets boot device to disk"];
Conductor -&gt; IPA [label = "Power off the node"];
Conductor -&gt; iLO [label = "Power on the node"];
Baremetal -&gt; Baremetal [label = "Boot user image from disk"];
}
</desc>
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="67" y="7" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="317" y="7" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="567" y="7" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="817" y="7" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="1067" y="7" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="1317" y="7" />
<path d="M 128 41 L 128 1057" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<path d="M 378 41 L 378 1057" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<path d="M 628 41 L 628 1057" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<path d="M 878 41 L 878 1057" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<path d="M 1128 41 L 1128 1057" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<path d="M 1378 41 L 1378 1057" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="64" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="45" x="128.5" y="28">Glance</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="314" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="68" x="378.0" y="28">Conductor</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="564" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="68" x="628.0" y="28">Baremetal</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="814" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="38" x="878.0" y="28">Swift</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="1064" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="22" x="1128.0" y="28">IPA</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="1314" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="22" x="1378.0" y="28">iLO</text>
<path d="M 386 60 L 1370 60" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,56 1370,60 1362,64" stroke="rgb(0,0,0)" />
<path d="M 136 105 L 370 105" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="144,101 136,105 144,109" stroke="rgb(0,0,0)" />
<path d="M 136 150 L 370 150" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="362,146 370,150 362,154" stroke="rgb(0,0,0)" />
<path d="M 386 211 L 503 211" fill="none" stroke="rgb(0,0,0)" />
<path d="M 503 211 L 503 227" fill="none" stroke="rgb(0,0,0)" />
<path d="M 503 227 L 386 227" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="394,223 386,227 394,231" stroke="rgb(0,0,0)" />
<path d="M 386 320 L 503 320" fill="none" stroke="rgb(0,0,0)" />
<path d="M 503 320 L 503 336" fill="none" stroke="rgb(0,0,0)" />
<path d="M 503 336 L 386 336" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="394,332 386,336 394,340" stroke="rgb(0,0,0)" />
<path d="M 386 365 L 870 365" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="862,361 870,365 862,369" stroke="rgb(0,0,0)" />
<path d="M 386 426 L 503 426" fill="none" stroke="rgb(0,0,0)" />
<path d="M 503 426 L 503 442" fill="none" stroke="rgb(0,0,0)" />
<path d="M 503 442 L 386 442" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="394,438 386,442 394,446" stroke="rgb(0,0,0)" />
<path d="M 386 471 L 1370 471" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,467 1370,471 1362,475" stroke="rgb(0,0,0)" />
<path d="M 386 500 L 1370 500" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,496 1370,500 1362,504" stroke="rgb(0,0,0)" />
<path d="M 386 529 L 1370 529" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,525 1370,529 1362,533" stroke="rgb(0,0,0)" />
<path d="M 386 558 L 1370 558" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,554 1370,558 1362,562" stroke="rgb(0,0,0)" />
<path d="M 886 587 L 1370 587" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="894,583 886,587 894,591" stroke="rgb(0,0,0)" />
<path d="M 636 616 L 1370 616" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,612 1370,616 1362,620" stroke="rgb(0,0,0)" />
<path d="M 386 645 L 1120 645" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="394,641 386,645 394,649" stroke="rgb(0,0,0)" />
<path d="M 386 674 L 1120 674" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1112,670 1120,674 1112,678" stroke="rgb(0,0,0)" />
<path d="M 386 703 L 1120 703" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="394,699 386,703 394,707" stroke="rgb(0,0,0)" />
<path d="M 386 732 L 1120 732" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1112,728 1120,732 1112,736" stroke="rgb(0,0,0)" />
<path d="M 886 777 L 1120 777" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="894,773 886,777 894,781" stroke="rgb(0,0,0)" />
<path d="M 1136 822 L 1253 822" fill="none" stroke="rgb(0,0,0)" />
<path d="M 1253 822 L 1253 838" fill="none" stroke="rgb(0,0,0)" />
<path d="M 1253 838 L 1136 838" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1144,834 1136,838 1144,842" stroke="rgb(0,0,0)" />
<path d="M 386 867 L 1120 867" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="394,863 386,867 394,871" stroke="rgb(0,0,0)" />
<path d="M 386 896 L 620 896" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="612,892 620,896 612,900" stroke="rgb(0,0,0)" />
<path d="M 386 925 L 1120 925" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1112,921 1120,925 1112,929" stroke="rgb(0,0,0)" />
<path d="M 386 954 L 1370 954" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,950 1370,954 1362,958" stroke="rgb(0,0,0)" />
<path d="M 636 999 L 753 999" fill="none" stroke="rgb(0,0,0)" />
<path d="M 753 999 L 753 1015" fill="none" stroke="rgb(0,0,0)" />
<path d="M 753 1015 L 636 1015" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="644,1011 636,1015 644,1019" stroke="rgb(0,0,0)" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="145" x="466.5" y="56">Powers off the node</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="229" x="251.5" y="85">Get the metadata for deploy IS</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="7" x="362.5" y="101">O</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="229" x="258.5" y="130">Returns the metadata for deplo</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="38" x="163.0" y="146">y ISO</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="458.5" y="175">Generates swift te</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="458.5" y="191">mpURL for deploy I</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="15" x="397.5" y="207">SO</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="458.5" y="260">Creates the FAT32 </text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="458.5" y="276">image containing i</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="458.5" y="292">ronic API URL and </text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="84" x="432.0" y="308">driver name</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="175" x="481.5" y="361">Uploads the FAT32 image</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="458.5" y="390">Generates swift te</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="458.5" y="406">mpURL for FAT32 im</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="22" x="401.0" y="422">age</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="473" x="630.5" y="467">Attaches the FAT32 image swift tempURL as virtual media floppy</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="458" x="623.0" y="496">Attaches the deploy ISO swift tempURL as virtual media CDROM</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="206" x="497.0" y="525">Sets one time boot to CDROM</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="114" x="451.0" y="554">Reboot the node</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="152" x="1290.0" y="583">Downloads deploy ISO</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="427" x="857.5" y="612">Boots deploy kernel/ramdisk from iLO virtual media CDROM</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="84" x="1074.0" y="641">Lookup node</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="462.5" y="670">Provides node UUID</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="68" x="1082.0" y="699">Heartbeat</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="244" x="516.0" y="728">Sends the user image HTTP(S) URL</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="229" x="1001.5" y="757">Retrieves the user image on ba</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="61" x="1085.5" y="773">re metal</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="1208.5" y="802">Writes user image </text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="53" x="1166.5" y="818">to disk</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="68" x="1082.0" y="863">Heartbeat</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="183" x="485.5" y="892">Sets boot device to disk</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="462.5" y="921">Power off the node</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="129" x="458.5" y="950">Power on the node</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="708.5" y="979">Boot user image fr</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="53" x="666.5" y="995">om disk</text>
</svg>

Before

Width:  |  Height:  |  Size: 16 KiB

-30
View File
@@ -1,30 +0,0 @@
diagram {
Webserver; Conductor; Baremetal; Swift; IPA; iLO;
activation = none;
span_height = 1;
edge_length = 250;
default_note_color = white;
default_fontsize = 14;
Conductor -> iLO [label = "Powers off the node"];
Conductor -> Conductor [label = "Creates the FAT32 image containing ironic API URL and driver name"];
Conductor -> Swift [label = "Uploads the FAT32 image"];
Conductor -> Conductor [label = "Generates swift tempURL for FAT32 image"];
Conductor -> iLO [label = "Attaches the FAT32 image swift tempURL as virtual media floppy"];
Conductor -> iLO [label = "Attaches the deploy ISO URL as virtual media CDROM"];
Conductor -> iLO [label = "Sets one time boot to CDROM"];
Conductor -> iLO [label = "Reboot the node"];
iLO -> Webserver [label = "Downloads deploy ISO"];
Baremetal -> iLO [label = "Boots deploy kernel/ramdisk from iLO virtual media CDROM"];
IPA -> Conductor [label = "Lookup node"];
Conductor -> IPA [label = "Provides node UUID"];
IPA -> Conductor [label = "Heartbeat"];
Conductor -> IPA [label = "Sends the user image HTTP(S) URL"];
IPA -> Webserver [label = "Retrieves the user image on bare metal"];
IPA -> IPA [label = "Writes user image to disk"];
IPA -> Conductor [label = "Heartbeat"];
Conductor -> Baremetal [label = "Sets boot device to disk"];
Conductor -> IPA [label = "Power off the node"];
Conductor -> Baremetal [label = "Power on the node"];
Baremetal -> Baremetal [label = "Boot user image from disk"];
}
-143
View File
@@ -1,143 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg viewBox="0 0 1506 867" xmlns="http://www.w3.org/2000/svg" xmlns:inkspace="http://www.inkscape.org/namespaces/inkscape" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs id="defs_block">
<filter height="1.504" id="filter_blur" inkspace:collect="always" width="1.1575" x="-0.07875" y="-0.252">
<feGaussianBlur id="feGaussianBlur3780" inkspace:collect="always" stdDeviation="4.2" />
</filter>
</defs>
<title>blockdiag</title>
<desc>diagram {
Webserver; Conductor; Baremetal; Swift; IPA; iLO;
activation = none;
span_height = 1;
edge_length = 250;
default_note_color = white;
default_fontsize = 14;
Conductor -&gt; iLO [label = "Powers off the node"];
Conductor -&gt; Conductor [label = "Creates the FAT32 image containing ironic API URL and driver name"];
Conductor -&gt; Swift [label = "Uploads the FAT32 image"];
Conductor -&gt; Conductor [label = "Generates swift tempURL for FAT32 image"];
Conductor -&gt; iLO [label = "Attaches the FAT32 image swift tempURL as virtual media floppy"];
Conductor -&gt; iLO [label = "Attaches the deploy ISO URL as virtual media CDROM"];
Conductor -&gt; iLO [label = "Sets one time boot to CDROM"];
Conductor -&gt; iLO [label = "Reboot the node"];
iLO -&gt; Webserver [label = "Downloads deploy ISO"];
Baremetal -&gt; iLO [label = "Boots deploy kernel/ramdisk from iLO virtual media CDROM"];
IPA -&gt; Conductor [label = "Lookup node"];
Conductor -&gt; IPA [label = "Provides node UUID"];
IPA -&gt; Conductor [label = "Heartbeat"];
Conductor -&gt; IPA [label = "Sends the user image HTTP(S) URL"];
IPA -&gt; Webserver [label = "Retrieves the user image on bare metal"];
IPA -&gt; IPA [label = "Writes user image to disk"];
IPA -&gt; Conductor [label = "Heartbeat"];
Conductor -&gt; Baremetal [label = "Sets boot device to disk"];
Conductor -&gt; IPA [label = "Power off the node"];
Conductor -&gt; Baremetal [label = "Power on the node"];
Baremetal -&gt; Baremetal [label = "Boot user image from disk"];
}
</desc>
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="67" y="7" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="317" y="7" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="567" y="7" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="817" y="7" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="1067" y="7" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="1317" y="7" />
<path d="M 128 41 L 128 874" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<path d="M 378 41 L 378 874" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<path d="M 628 41 L 628 874" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<path d="M 878 41 L 878 874" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<path d="M 1128 41 L 1128 874" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<path d="M 1378 41 L 1378 874" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="64" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="68" x="128.0" y="28">Webserver</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="314" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="68" x="378.0" y="28">Conductor</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="564" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="68" x="628.0" y="28">Baremetal</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="814" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="38" x="878.0" y="28">Swift</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="1064" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="22" x="1128.0" y="28">IPA</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="1314" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="22" x="1378.0" y="28">iLO</text>
<path d="M 386 60 L 1370 60" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,56 1370,60 1362,64" stroke="rgb(0,0,0)" />
<path d="M 386 153 L 503 153" fill="none" stroke="rgb(0,0,0)" />
<path d="M 503 153 L 503 169" fill="none" stroke="rgb(0,0,0)" />
<path d="M 503 169 L 386 169" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="394,165 386,169 394,173" stroke="rgb(0,0,0)" />
<path d="M 386 198 L 870 198" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="862,194 870,198 862,202" stroke="rgb(0,0,0)" />
<path d="M 386 259 L 503 259" fill="none" stroke="rgb(0,0,0)" />
<path d="M 503 259 L 503 275" fill="none" stroke="rgb(0,0,0)" />
<path d="M 503 275 L 386 275" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="394,271 386,275 394,279" stroke="rgb(0,0,0)" />
<path d="M 386 304 L 1370 304" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,300 1370,304 1362,308" stroke="rgb(0,0,0)" />
<path d="M 386 333 L 1370 333" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,329 1370,333 1362,337" stroke="rgb(0,0,0)" />
<path d="M 386 362 L 1370 362" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,358 1370,362 1362,366" stroke="rgb(0,0,0)" />
<path d="M 386 391 L 1370 391" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,387 1370,391 1362,395" stroke="rgb(0,0,0)" />
<path d="M 136 420 L 1370 420" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="144,416 136,420 144,424" stroke="rgb(0,0,0)" />
<path d="M 636 449 L 1370 449" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,445 1370,449 1362,453" stroke="rgb(0,0,0)" />
<path d="M 386 478 L 1120 478" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="394,474 386,478 394,482" stroke="rgb(0,0,0)" />
<path d="M 386 507 L 1120 507" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1112,503 1120,507 1112,511" stroke="rgb(0,0,0)" />
<path d="M 386 536 L 1120 536" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="394,532 386,536 394,540" stroke="rgb(0,0,0)" />
<path d="M 386 565 L 1120 565" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1112,561 1120,565 1112,569" stroke="rgb(0,0,0)" />
<path d="M 136 594 L 1120 594" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="144,590 136,594 144,598" stroke="rgb(0,0,0)" />
<path d="M 1136 639 L 1253 639" fill="none" stroke="rgb(0,0,0)" />
<path d="M 1253 639 L 1253 655" fill="none" stroke="rgb(0,0,0)" />
<path d="M 1253 655 L 1136 655" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1144,651 1136,655 1144,659" stroke="rgb(0,0,0)" />
<path d="M 386 684 L 1120 684" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="394,680 386,684 394,688" stroke="rgb(0,0,0)" />
<path d="M 386 713 L 620 713" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="612,709 620,713 612,717" stroke="rgb(0,0,0)" />
<path d="M 386 742 L 1120 742" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1112,738 1120,742 1112,746" stroke="rgb(0,0,0)" />
<path d="M 386 771 L 620 771" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="612,767 620,771 612,775" stroke="rgb(0,0,0)" />
<path d="M 636 816 L 753 816" fill="none" stroke="rgb(0,0,0)" />
<path d="M 753 816 L 753 832" fill="none" stroke="rgb(0,0,0)" />
<path d="M 753 832 L 636 832" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="644,828 636,832 644,836" stroke="rgb(0,0,0)" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="145" x="466.5" y="56">Powers off the node</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="458.5" y="93">Creates the FAT32 </text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="458.5" y="109">image containing i</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="458.5" y="125">ronic API URL and </text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="84" x="432.0" y="141">driver name</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="175" x="481.5" y="194">Uploads the FAT32 image</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="458.5" y="223">Generates swift te</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="458.5" y="239">mpURL for FAT32 im</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="22" x="401.0" y="255">age</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="473" x="630.5" y="300">Attaches the FAT32 image swift tempURL as virtual media floppy</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="381" x="584.5" y="329">Attaches the deploy ISO URL as virtual media CDROM</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="206" x="497.0" y="358">Sets one time boot to CDROM</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="114" x="451.0" y="387">Reboot the node</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="152" x="1290.0" y="416">Downloads deploy ISO</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="427" x="857.5" y="445">Boots deploy kernel/ramdisk from iLO virtual media CDROM</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="84" x="1074.0" y="474">Lookup node</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="462.5" y="503">Provides node UUID</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="68" x="1082.0" y="532">Heartbeat</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="244" x="516.0" y="561">Sends the user image HTTP(S) URL</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="290" x="971.0" y="590">Retrieves the user image on bare metal</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="1208.5" y="619">Writes user image </text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="53" x="1166.5" y="635">to disk</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="68" x="1082.0" y="680">Heartbeat</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="183" x="485.5" y="709">Sets boot device to disk</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="462.5" y="738">Power off the node</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="129" x="458.5" y="767">Power on the node</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="708.5" y="796">Boot user image fr</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="53" x="666.5" y="812">om disk</text>
</svg>

Before

Width:  |  Height:  |  Size: 14 KiB

-30
View File
@@ -1,30 +0,0 @@
diagram {
Webserver; Conductor; Baremetal; ConductorWebserver; IPA; iLO;
activation = none;
span_height = 1;
edge_length = 250;
default_note_color = white;
default_fontsize = 14;
Conductor -> iLO [label = "Powers off the node"];
Conductor -> Conductor [label = "Creates the FAT32 image containing Ironic API URL and driver name"];
Conductor -> ConductorWebserver [label = "Uploads the FAT32 image"];
Conductor -> Conductor [label = "Generates URL for FAT32 image"];
Conductor -> iLO [label = "Attaches the FAT32 image URL as virtual media floppy"];
Conductor -> iLO [label = "Attaches the deploy ISO URL as virtual media CDROM"];
Conductor -> iLO [label = "Sets one time boot to CDROM"];
Conductor -> iLO [label = "Reboot the node"];
iLO -> Webserver [label = "Downloads deploy ISO"];
Baremetal -> iLO [label = "Boots deploy kernel/ramdisk from iLO virtual media CDROM"];
IPA -> Conductor [label = "Lookup node"];
Conductor -> IPA [label = "Provides node UUID"];
IPA -> Conductor [label = "Heartbeat"];
Conductor -> IPA [label = "Sends the user image HTTP(S) URL"];
IPA -> Webserver [label = "Retrieves the user image on bare metal"];
IPA -> IPA [label = "Writes user image to disk"];
IPA -> Conductor [label = "Heartbeat"];
Conductor -> Baremetal [label = "Sets boot device to disk"];
Conductor -> IPA [label = "Power off the node"];
Conductor -> Baremetal [label = "Power on the node"];
Baremetal -> Baremetal [label = "Boot user image from disk"];
}
-143
View File
@@ -1,143 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg viewBox="0 0 1506 851" xmlns="http://www.w3.org/2000/svg" xmlns:inkspace="http://www.inkscape.org/namespaces/inkscape" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs id="defs_block">
<filter height="1.504" id="filter_blur" inkspace:collect="always" width="1.1575" x="-0.07875" y="-0.252">
<feGaussianBlur id="feGaussianBlur3780" inkspace:collect="always" stdDeviation="4.2" />
</filter>
</defs>
<title>blockdiag</title>
<desc>diagram {
Webserver; Conductor; Baremetal; ConductorWebserver; IPA; iLO;
activation = none;
span_height = 1;
edge_length = 250;
default_note_color = white;
default_fontsize = 14;
Conductor -&gt; iLO [label = "Powers off the node"];
Conductor -&gt; Conductor [label = "Creates the FAT32 image containing Ironic API URL and driver name"];
Conductor -&gt; ConductorWebserver [label = "Uploads the FAT32 image"];
Conductor -&gt; Conductor [label = "Generates URL for FAT32 image"];
Conductor -&gt; iLO [label = "Attaches the FAT32 image URL as virtual media floppy"];
Conductor -&gt; iLO [label = "Attaches the deploy ISO URL as virtual media CDROM"];
Conductor -&gt; iLO [label = "Sets one time boot to CDROM"];
Conductor -&gt; iLO [label = "Reboot the node"];
iLO -&gt; Webserver [label = "Downloads deploy ISO"];
Baremetal -&gt; iLO [label = "Boots deploy kernel/ramdisk from iLO virtual media CDROM"];
IPA -&gt; Conductor [label = "Lookup node"];
Conductor -&gt; IPA [label = "Provides node UUID"];
IPA -&gt; Conductor [label = "Heartbeat"];
Conductor -&gt; IPA [label = "Sends the user image HTTP(S) URL"];
IPA -&gt; Webserver [label = "Retrieves the user image on bare metal"];
IPA -&gt; IPA [label = "Writes user image to disk"];
IPA -&gt; Conductor [label = "Heartbeat"];
Conductor -&gt; Baremetal [label = "Sets boot device to disk"];
Conductor -&gt; IPA [label = "Power off the node"];
Conductor -&gt; Baremetal [label = "Power on the node"];
Baremetal -&gt; Baremetal [label = "Boot user image from disk"];
}
</desc>
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="67" y="7" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="317" y="7" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="567" y="7" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="817" y="7" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="1067" y="7" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="1317" y="7" />
<path d="M 128 41 L 128 858" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<path d="M 378 41 L 378 858" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<path d="M 628 41 L 628 858" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<path d="M 878 41 L 878 858" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<path d="M 1128 41 L 1128 858" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<path d="M 1378 41 L 1378 858" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="64" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="68" x="128.0" y="28">Webserver</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="314" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="68" x="378.0" y="28">Conductor</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="564" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="68" x="628.0" y="28">Baremetal</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="814" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="122" x="878.0" y="20">ConductorWebserv</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="15" x="878.5" y="36">er</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="1064" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="22" x="1128.0" y="28">IPA</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="1314" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="22" x="1378.0" y="28">iLO</text>
<path d="M 386 60 L 1370 60" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,56 1370,60 1362,64" stroke="rgb(0,0,0)" />
<path d="M 386 153 L 503 153" fill="none" stroke="rgb(0,0,0)" />
<path d="M 503 153 L 503 169" fill="none" stroke="rgb(0,0,0)" />
<path d="M 503 169 L 386 169" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="394,165 386,169 394,173" stroke="rgb(0,0,0)" />
<path d="M 386 198 L 870 198" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="862,194 870,198 862,202" stroke="rgb(0,0,0)" />
<path d="M 386 243 L 503 243" fill="none" stroke="rgb(0,0,0)" />
<path d="M 503 243 L 503 259" fill="none" stroke="rgb(0,0,0)" />
<path d="M 503 259 L 386 259" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="394,255 386,259 394,263" stroke="rgb(0,0,0)" />
<path d="M 386 288 L 1370 288" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,284 1370,288 1362,292" stroke="rgb(0,0,0)" />
<path d="M 386 317 L 1370 317" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,313 1370,317 1362,321" stroke="rgb(0,0,0)" />
<path d="M 386 346 L 1370 346" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,342 1370,346 1362,350" stroke="rgb(0,0,0)" />
<path d="M 386 375 L 1370 375" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,371 1370,375 1362,379" stroke="rgb(0,0,0)" />
<path d="M 136 404 L 1370 404" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="144,400 136,404 144,408" stroke="rgb(0,0,0)" />
<path d="M 636 433 L 1370 433" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,429 1370,433 1362,437" stroke="rgb(0,0,0)" />
<path d="M 386 462 L 1120 462" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="394,458 386,462 394,466" stroke="rgb(0,0,0)" />
<path d="M 386 491 L 1120 491" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1112,487 1120,491 1112,495" stroke="rgb(0,0,0)" />
<path d="M 386 520 L 1120 520" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="394,516 386,520 394,524" stroke="rgb(0,0,0)" />
<path d="M 386 549 L 1120 549" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1112,545 1120,549 1112,553" stroke="rgb(0,0,0)" />
<path d="M 136 578 L 1120 578" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="144,574 136,578 144,582" stroke="rgb(0,0,0)" />
<path d="M 1136 623 L 1253 623" fill="none" stroke="rgb(0,0,0)" />
<path d="M 1253 623 L 1253 639" fill="none" stroke="rgb(0,0,0)" />
<path d="M 1253 639 L 1136 639" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1144,635 1136,639 1144,643" stroke="rgb(0,0,0)" />
<path d="M 386 668 L 1120 668" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="394,664 386,668 394,672" stroke="rgb(0,0,0)" />
<path d="M 386 697 L 620 697" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="612,693 620,697 612,701" stroke="rgb(0,0,0)" />
<path d="M 386 726 L 1120 726" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1112,722 1120,726 1112,730" stroke="rgb(0,0,0)" />
<path d="M 386 755 L 620 755" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="612,751 620,755 612,759" stroke="rgb(0,0,0)" />
<path d="M 636 800 L 753 800" fill="none" stroke="rgb(0,0,0)" />
<path d="M 753 800 L 753 816" fill="none" stroke="rgb(0,0,0)" />
<path d="M 753 816 L 636 816" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="644,812 636,816 644,820" stroke="rgb(0,0,0)" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="145" x="466.5" y="56">Powers off the node</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="458.5" y="93">Creates the FAT32 </text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="458.5" y="109">image containing I</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="458.5" y="125">ronic API URL and </text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="84" x="432.0" y="141">driver name</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="175" x="481.5" y="194">Uploads the FAT32 image</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="458.5" y="223">Generates URL for </text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="84" x="432.0" y="239">FAT32 image</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="397" x="592.5" y="284">Attaches the FAT32 image URL as virtual media floppy</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="381" x="584.5" y="313">Attaches the deploy ISO URL as virtual media CDROM</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="206" x="497.0" y="342">Sets one time boot to CDROM</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="114" x="451.0" y="371">Reboot the node</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="152" x="1290.0" y="400">Downloads deploy ISO</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="427" x="857.5" y="429">Boots deploy kernel/ramdisk from iLO virtual media CDROM</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="84" x="1074.0" y="458">Lookup node</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="462.5" y="487">Provides node UUID</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="68" x="1082.0" y="516">Heartbeat</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="244" x="516.0" y="545">Sends the user image HTTP(S) URL</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="290" x="971.0" y="574">Retrieves the user image on bare metal</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="1208.5" y="603">Writes user image </text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="53" x="1166.5" y="619">to disk</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="68" x="1082.0" y="664">Heartbeat</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="183" x="485.5" y="693">Sets boot device to disk</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="462.5" y="722">Power off the node</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="129" x="458.5" y="751">Power on the node</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="708.5" y="780">Boot user image fr</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="53" x="666.5" y="796">om disk</text>
</svg>

Before

Width:  |  Height:  |  Size: 14 KiB

-32
View File
@@ -1,32 +0,0 @@
diagram {
Glance; Conductor; Baremetal; ConductorWebserver; IPA; iLO;
activation = none;
span_height = 1;
edge_length = 250;
default_note_color = white;
default_fontsize = 14;
Conductor -> iLO [label = "Powers off the node"];
Conductor -> Glance [label = "Get the metadata for deploy ISO"];
Glance -> Conductor [label = "Returns the metadata for deploy ISO"];
Conductor -> Conductor [label = "Generates swift tempURL for deploy ISO"];
Conductor -> Conductor [label = "Creates the FAT32 image containing Ironic API URL and driver name"];
Conductor -> ConductorWebserver [label = "Uploads the FAT32 image"];
Conductor -> iLO [label = "Attaches the FAT32 image URL as virtual media floppy"];
Conductor -> iLO [label = "Attaches the deploy ISO swift tempURL as virtual media CDROM"];
Conductor -> iLO [label = "Sets one time boot to CDROM"];
Conductor -> iLO [label = "Reboot the node"];
iLO -> Swift [label = "Downloads deploy ISO"];
Baremetal -> iLO [label = "Boots deploy kernel/ramdisk from iLO virtual media CDROM"];
IPA -> Conductor [label = "Lookup node"];
Conductor -> IPA [label = "Provides node UUID"];
IPA -> Conductor [label = "Heartbeat"];
Conductor -> IPA [label = "Sends the user image HTTP(S) URL"];
IPA -> Swift [label = "Retrieves the user image on bare metal"];
IPA -> IPA [label = "Writes user image to disk"];
IPA -> Conductor [label = "Heartbeat"];
Conductor -> Baremetal [label = "Sets boot device to disk"];
Conductor -> IPA [label = "Power off the node"];
Conductor -> Baremetal [label = "Power on the node"];
Baremetal -> Baremetal [label = "Boot user image from disk"];
}
-158
View File
@@ -1,158 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg viewBox="0 0 1756 957" xmlns="http://www.w3.org/2000/svg" xmlns:inkspace="http://www.inkscape.org/namespaces/inkscape" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs id="defs_block">
<filter height="1.504" id="filter_blur" inkspace:collect="always" width="1.1575" x="-0.07875" y="-0.252">
<feGaussianBlur id="feGaussianBlur3780" inkspace:collect="always" stdDeviation="4.2" />
</filter>
</defs>
<title>blockdiag</title>
<desc>diagram {
Glance; Conductor; Baremetal; ConductorWebserver; IPA; iLO;
activation = none;
span_height = 1;
edge_length = 250;
default_note_color = white;
default_fontsize = 14;
Conductor -&gt; iLO [label = "Powers off the node"];
Conductor -&gt; Glance [label = "Get the metadata for deploy ISO"];
Glance -&gt; Conductor [label = "Returns the metadata for deploy ISO"];
Conductor -&gt; Conductor [label = "Generates swift tempURL for deploy ISO"];
Conductor -&gt; Conductor [label = "Creates the FAT32 image containing Ironic API URL and driver name"];
Conductor -&gt; ConductorWebserver [label = "Uploads the FAT32 image"];
Conductor -&gt; iLO [label = "Attaches the FAT32 image URL as virtual media floppy"];
Conductor -&gt; iLO [label = "Attaches the deploy ISO swift tempURL as virtual media CDROM"];
Conductor -&gt; iLO [label = "Sets one time boot to CDROM"];
Conductor -&gt; iLO [label = "Reboot the node"];
iLO -&gt; Swift [label = "Downloads deploy ISO"];
Baremetal -&gt; iLO [label = "Boots deploy kernel/ramdisk from iLO virtual media CDROM"];
IPA -&gt; Conductor [label = "Lookup node"];
Conductor -&gt; IPA [label = "Provides node UUID"];
IPA -&gt; Conductor [label = "Heartbeat"];
Conductor -&gt; IPA [label = "Sends the user image HTTP(S) URL"];
IPA -&gt; Swift [label = "Retrieves the user image on bare metal"];
IPA -&gt; IPA [label = "Writes user image to disk"];
IPA -&gt; Conductor [label = "Heartbeat"];
Conductor -&gt; Baremetal [label = "Sets boot device to disk"];
Conductor -&gt; IPA [label = "Power off the node"];
Conductor -&gt; Baremetal [label = "Power on the node"];
Baremetal -&gt; Baremetal [label = "Boot user image from disk"];
}
</desc>
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="67" y="7" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="317" y="7" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="567" y="7" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="817" y="7" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="1067" y="7" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="1317" y="7" />
<rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="1567" y="7" />
<path d="M 128 41 L 128 964" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<path d="M 378 41 L 378 964" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<path d="M 628 41 L 628 964" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<path d="M 878 41 L 878 964" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<path d="M 1128 41 L 1128 964" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<path d="M 1378 41 L 1378 964" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<path d="M 1628 41 L 1628 964" fill="none" stroke="rgb(0,0,0)" stroke-dasharray="8 4" />
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="64" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="45" x="128.5" y="28">Glance</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="314" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="68" x="378.0" y="28">Conductor</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="564" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="68" x="628.0" y="28">Baremetal</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="814" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="122" x="878.0" y="20">ConductorWebserv</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="15" x="878.5" y="36">er</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="1064" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="22" x="1128.0" y="28">IPA</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="1314" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="22" x="1378.0" y="28">iLO</text>
<rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="1564" y="1" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="38" x="1628.0" y="28">Swift</text>
<path d="M 386 60 L 1370 60" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,56 1370,60 1362,64" stroke="rgb(0,0,0)" />
<path d="M 136 105 L 370 105" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="144,101 136,105 144,109" stroke="rgb(0,0,0)" />
<path d="M 136 150 L 370 150" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="362,146 370,150 362,154" stroke="rgb(0,0,0)" />
<path d="M 386 211 L 503 211" fill="none" stroke="rgb(0,0,0)" />
<path d="M 503 211 L 503 227" fill="none" stroke="rgb(0,0,0)" />
<path d="M 503 227 L 386 227" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="394,223 386,227 394,231" stroke="rgb(0,0,0)" />
<path d="M 386 320 L 503 320" fill="none" stroke="rgb(0,0,0)" />
<path d="M 503 320 L 503 336" fill="none" stroke="rgb(0,0,0)" />
<path d="M 503 336 L 386 336" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="394,332 386,336 394,340" stroke="rgb(0,0,0)" />
<path d="M 386 365 L 870 365" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="862,361 870,365 862,369" stroke="rgb(0,0,0)" />
<path d="M 386 394 L 1370 394" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,390 1370,394 1362,398" stroke="rgb(0,0,0)" />
<path d="M 386 423 L 1370 423" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,419 1370,423 1362,427" stroke="rgb(0,0,0)" />
<path d="M 386 452 L 1370 452" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,448 1370,452 1362,456" stroke="rgb(0,0,0)" />
<path d="M 386 481 L 1370 481" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,477 1370,481 1362,485" stroke="rgb(0,0,0)" />
<path d="M 1386 510 L 1620 510" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1612,506 1620,510 1612,514" stroke="rgb(0,0,0)" />
<path d="M 636 539 L 1370 539" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1362,535 1370,539 1362,543" stroke="rgb(0,0,0)" />
<path d="M 386 568 L 1120 568" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="394,564 386,568 394,572" stroke="rgb(0,0,0)" />
<path d="M 386 597 L 1120 597" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1112,593 1120,597 1112,601" stroke="rgb(0,0,0)" />
<path d="M 386 626 L 1120 626" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="394,622 386,626 394,630" stroke="rgb(0,0,0)" />
<path d="M 386 655 L 1120 655" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1112,651 1120,655 1112,659" stroke="rgb(0,0,0)" />
<path d="M 1136 684 L 1620 684" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1612,680 1620,684 1612,688" stroke="rgb(0,0,0)" />
<path d="M 1136 729 L 1253 729" fill="none" stroke="rgb(0,0,0)" />
<path d="M 1253 729 L 1253 745" fill="none" stroke="rgb(0,0,0)" />
<path d="M 1253 745 L 1136 745" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1144,741 1136,745 1144,749" stroke="rgb(0,0,0)" />
<path d="M 386 774 L 1120 774" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="394,770 386,774 394,778" stroke="rgb(0,0,0)" />
<path d="M 386 803 L 620 803" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="612,799 620,803 612,807" stroke="rgb(0,0,0)" />
<path d="M 386 832 L 1120 832" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="1112,828 1120,832 1112,836" stroke="rgb(0,0,0)" />
<path d="M 386 861 L 620 861" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="612,857 620,861 612,865" stroke="rgb(0,0,0)" />
<path d="M 636 906 L 753 906" fill="none" stroke="rgb(0,0,0)" />
<path d="M 753 906 L 753 922" fill="none" stroke="rgb(0,0,0)" />
<path d="M 753 922 L 636 922" fill="none" stroke="rgb(0,0,0)" />
<polygon fill="rgb(0,0,0)" points="644,918 636,922 644,926" stroke="rgb(0,0,0)" />
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="145" x="466.5" y="56">Powers off the node</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="229" x="251.5" y="85">Get the metadata for deploy IS</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="7" x="362.5" y="101">O</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="229" x="258.5" y="130">Returns the metadata for deplo</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="38" x="163.0" y="146">y ISO</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="458.5" y="175">Generates swift te</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="458.5" y="191">mpURL for deploy I</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="15" x="397.5" y="207">SO</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="458.5" y="260">Creates the FAT32 </text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="458.5" y="276">image containing I</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="458.5" y="292">ronic API URL and </text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="84" x="432.0" y="308">driver name</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="175" x="481.5" y="361">Uploads the FAT32 image</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="397" x="592.5" y="390">Attaches the FAT32 image URL as virtual media floppy</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="458" x="623.0" y="419">Attaches the deploy ISO swift tempURL as virtual media CDROM</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="206" x="497.0" y="448">Sets one time boot to CDROM</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="114" x="451.0" y="477">Reboot the node</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="152" x="1470.0" y="506">Downloads deploy ISO</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="427" x="857.5" y="535">Boots deploy kernel/ramdisk from iLO virtual media CDROM</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="84" x="1074.0" y="564">Lookup node</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="462.5" y="593">Provides node UUID</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="68" x="1082.0" y="622">Heartbeat</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="244" x="516.0" y="651">Sends the user image HTTP(S) URL</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="290" x="1289.0" y="680">Retrieves the user image on bare metal</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="1208.5" y="709">Writes user image </text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="53" x="1166.5" y="725">to disk</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="68" x="1082.0" y="770">Heartbeat</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="183" x="485.5" y="799">Sets boot device to disk</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="462.5" y="828">Power off the node</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="129" x="458.5" y="857">Power on the node</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="137" x="708.5" y="886">Boot user image fr</text>
<text fill="rgb(0,0,0)" font-family="sans-serif" font-size="14" font-style="normal" font-weight="normal" text-anchor="middle" textLength="53" x="666.5" y="902">om disk</text>
</svg>

Before

Width:  |  Height:  |  Size: 16 KiB

+1 -1
View File
@@ -77,7 +77,7 @@ Collecting sensor data
~~~~~~~~~~~~~~~~~~~~~~
Bare Metal service supports sending IPMI sensor data to Telemetry with
certain hardware types, such as ``ipmi`` and ``ilo``. By default,
certain hardware types, such as ``ipmi``. By default,
support for sending IPMI sensor data to Telemetry is disabled. If you want
to enable it, you should make the following two changes in ``ironic.conf``:
+3 -3
View File
@@ -214,9 +214,9 @@ the PXE UEFI environment.
boot device is set to network/pxe.
.. note::
Some drivers, e.g. ``ilo`` and ``redfish``, support automatic
setting of the boot mode during deployment. This step is not required
for them. Please check :doc:`../admin/drivers` for information on whether
Some drivers, e.g. ``redfish``, support automatic setting of the
boot mode during deployment. This step is not required for them.
Please check :doc:`../admin/drivers` for information on whether
your driver requires manual UEFI configuration.
iPXE setup
+11 -11
View File
@@ -8,7 +8,7 @@ The Bare Metal service delegates actual hardware management to **drivers**.
*Drivers*, also called *hardware types*, consist of *hardware interfaces*:
sets of functionality dealing with some aspect of bare metal provisioning
in a vendor-specific way. There are generic **hardware types** (eg.
``redfish`` and ``ipmi``), and vendor-specific one (eg. ``ilo``).
``redfish`` and ``ipmi``), and vendor-specific ones.
.. note::
The terminologies *driver*, *dynamic driver*, and *hardware type*
@@ -64,8 +64,8 @@ boot
.. code-block:: ini
[DEFAULT]
enabled_hardware_types = ipmi,ilo
enabled_boot_interfaces = pxe,ilo-virtual-media
enabled_hardware_types = ipmi
enabled_boot_interfaces = pxe
Boot interfaces with ``pxe`` in their name require :doc:`configure-pxe`.
There are also a few hardware-specific boot interfaces - see
@@ -97,8 +97,8 @@ inspect
.. code-block:: ini
[DEFAULT]
enabled_hardware_types = ipmi,ilo
enabled_inspect_interfaces = ilo,agent
enabled_hardware_types = ipmi
enabled_inspect_interfaces = agent
See :doc:`/admin/inspection` for more details.
management
@@ -110,8 +110,8 @@ management
.. code-block:: ini
[DEFAULT]
enabled_hardware_types = ipmi,redfish,ilo
enabled_management_interfaces = ipmitool,redfish,ilo
enabled_hardware_types = ipmi,redfish
enabled_management_interfaces = ipmitool,redfish
Using ``ipmitool`` requires :doc:`configure-ipmi`. See
:doc:`/admin/drivers` for the required configuration of each driver.
@@ -126,8 +126,8 @@ power
.. code-block:: ini
[DEFAULT]
enabled_hardware_types = ipmi,redfish,ilo
enabled_power_interfaces = ipmitool,redfish,ilo
enabled_hardware_types = ipmi,redfish
enabled_power_interfaces = ipmitool,redfish
Using ``ipmitool`` requires :doc:`configure-ipmi`. See
:doc:`/admin/drivers` for the required configuration of each driver.
@@ -139,7 +139,7 @@ raid
.. code-block:: ini
[DEFAULT]
enabled_hardware_types = ipmi,redfish,ilo
enabled_hardware_types = ipmi,redfish
enabled_raid_interfaces = agent,no-raid
storage
manages the interaction with a remote storage subsystem, such as the
@@ -167,7 +167,7 @@ vendor
.. code-block:: ini
[DEFAULT]
enabled_hardware_types = ipmi,redfish,ilo
enabled_hardware_types = ipmi,redfish
enabled_vendor_interfaces = ipmitool,no-vendor
Here is a complete configuration example, enabling two generic protocols,
+2 -2
View File
@@ -3,8 +3,8 @@
Boot mode support
-----------------
Some of the bare metal hardware types (namely, ``redfish``, ``ilo`` and
generic ``ipmi``) support setting boot mode (Legacy BIOS or UEFI).
Some of the bare metal hardware types (namely, ``redfish`` and
generic ``ipmi``) support setting boot mode (Legacy BIOS or UEFI).
.. note::
-3
View File
@@ -3,9 +3,6 @@
# It is intended to help package maintainers to discover additional
# python projects they should package as optional dependencies for Ironic.
# These are available on pypi
proliantutils>=2.16.2,<2.17.0
# Ansible-deploy interface
ansible>=2.7
-1
View File
@@ -52,7 +52,6 @@ def config(token, node=None):
# Out-of-band interfaces that don't need BMC detection
skip_bmc_detect = mgmt_iface in (
'redfish', 'idrac-redfish',
'ilo', 'ilo5', 'ilo6',
)
if skip_bmc_detect:
LOG.debug('Skipping BMC detection for node %(node)s with '
-41
View File
@@ -183,45 +183,6 @@ class Checks(upgradecheck.UpgradeCommands):
else:
return upgradecheck.Result(upgradecheck.Code.SUCCESS)
def _check_ilo_driver_usage(self):
"""Check for nodes using iLO/iLO5 hardware types or interfaces.
The iLO driver is retired.
"""
dbapi = db_api.get_instance()
ilo_interface_types = [
'bios', 'boot', 'console', 'inspect',
'management', 'power', 'raid', 'vendor'
]
affected_nodes = []
for node in dbapi.get_node_list():
issues = []
node_driver = node.driver
if node_driver and node_driver.lower() in ['ilo', 'ilo5']:
issues.append(f"hardware type '{node_driver}'")
for iface_type in ilo_interface_types:
value = getattr(node, f"{iface_type}_interface")
if value and 'ilo' in value.lower():
issues.append(f"{iface_type} interface '{value}'")
if issues:
affected_nodes.append(
f"Node {node.uuid} uses {', '.join(issues)}")
if not affected_nodes:
return upgradecheck.Result(upgradecheck.Code.SUCCESS)
msg = (
"The following nodes are using iLO/iLO5 hardware types and/or "
"interfaces which have been retired as of the 2026.1 release."
+ ". ".join(affected_nodes)
)
return upgradecheck.Result(upgradecheck.Code.WARNING, details=msg)
# A tuple of check tuples of (<name of check>, <check function>).
# The name of the check will be used in the output of this command.
# The check function takes no arguments and returns an
@@ -240,8 +201,6 @@ class Checks(upgradecheck.UpgradeCommands):
(common_checks.check_policy_json, {'conf': CONF})),
(_('Hardware Types and Interfaces Check'),
_check_hardware_types_interfaces),
(_('iLO/iLO5 Driver Usage Check'),
_check_ilo_driver_usage),
)
-8
View File
@@ -605,14 +605,6 @@ class PasswordFileFailedToCreate(IronicException):
_msg_fmt = _("Failed to create the password file. %(error)s")
class IloOperationError(DriverOperationError):
_msg_fmt = _("%(operation)s failed, error: %(error)s")
class IloOperationNotSupported(DriverOperationError):
_msg_fmt = _("%(operation)s not supported. error: %(error)s")
class DracOperationError(DriverOperationError):
_msg_fmt = _('DRAC operation failed. Reason: %(error)s')
-2
View File
@@ -37,7 +37,6 @@ from ironic.conf import exception
from ironic.conf import fake
from ironic.conf import glance
from ironic.conf import healthcheck
from ironic.conf import ilo
from ironic.conf import inspector
from ironic.conf import inventory
from ironic.conf import ipmi
@@ -80,7 +79,6 @@ exception.register_opts(CONF)
fake.register_opts(CONF)
glance.register_opts(CONF)
healthcheck.register_opts(CONF)
ilo.register_opts(CONF)
inspector.register_opts(CONF)
inventory.register_opts(CONF)
ipmi.register_opts(CONF)
-132
View File
@@ -1,132 +0,0 @@
# Copyright 2016 Intel Corporation
# Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# 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.IntOpt('client_timeout',
default=60,
help=_('Timeout (in seconds) for iLO operations')),
cfg.PortOpt('client_port',
default=443,
help=_('Port to be used for iLO operations')),
cfg.StrOpt('swift_ilo_container',
default='ironic_ilo_container',
help=_('The Swift iLO container to store data.')),
cfg.IntOpt('swift_object_expiry_timeout',
default=900,
help=_('Amount of time in seconds for Swift objects to '
'auto-expire.')),
cfg.BoolOpt('use_web_server_for_images',
default=False,
help=_('Set this to True to use http web server to host '
'floppy images and generated boot ISO. This '
'requires http_root and http_url to be configured '
'in the [deploy] section of the config file. If this '
'is set to False, then Ironic will use Swift '
'to host the floppy images and generated '
'boot_iso.')),
cfg.IntOpt('clean_priority_reset_ilo',
default=0,
help=_('Priority for reset_ilo clean step.')),
cfg.IntOpt('clean_priority_reset_bios_to_default',
default=10,
help=_('Priority for reset_bios_to_default clean step.')),
cfg.IntOpt('clean_priority_reset_secure_boot_keys_to_default',
default=20,
help=_('Priority for reset_secure_boot_keys clean step. This '
'step will reset the secure boot keys to manufacturing '
'defaults.')),
cfg.IntOpt('clean_priority_clear_secure_boot_keys',
default=0,
help=_('Priority for clear_secure_boot_keys clean step. This '
'step is not enabled by default. It can be enabled to '
'clear all secure boot keys enrolled with iLO.')),
cfg.IntOpt('clean_priority_reset_ilo_credential',
default=30,
help=_('Priority for reset_ilo_credential clean step. This '
'step requires "ilo_change_password" parameter to be '
'updated in nodes\'s driver_info with the new '
'password.')),
cfg.IntOpt('power_wait',
default=2,
help=_('Amount of time in seconds to wait in between power '
'operations')),
cfg.IntOpt('oob_erase_devices_job_status_interval',
min=10,
default=300,
help=_('Interval (in seconds) between periodic erase-devices '
'status checks to determine whether the asynchronous '
'out-of-band erase-devices was successfully finished or '
'not. On an average, a 300GB HDD with default pattern '
'"overwrite" would take approximately 9 hours and '
'300GB SSD with default pattern "block" would take '
'approx. 30 seconds to complete sanitize disk erase.')),
cfg.StrOpt('ca_file',
deprecated_for_removal=True,
deprecated_reason=_('Its being replaced by new configuration '
'parameter "verify_ca".'),
help=_('CA certificate file to validate iLO.')),
cfg.StrOpt('verify_ca',
default='True',
help=_('CA certificate to validate iLO. This can be either '
'a Boolean value, a path to a CA_BUNDLE file or '
'directory with certificates of trusted CAs. If set '
'to True the driver will verify the host certificates; '
'if False the driver will ignore verifying the SSL '
'certificate. If it\'s a path the driver will use the '
'specified certificate or one of the certificates in '
'the directory.')),
cfg.StrOpt('default_boot_mode',
default='auto',
choices=[('auto', _('based on boot mode settings on the '
'system')),
('bios', _('BIOS boot mode')),
('uefi', _('UEFI boot mode'))],
help=_('Default boot mode to be used in provisioning when '
'"boot_mode" capability is not provided in the '
'"properties/capabilities" of the node. The default is '
'"auto" for backward compatibility. When "auto" is '
'specified, default boot mode will be selected based '
'on boot mode settings on the system.')),
cfg.IntOpt('file_permission',
default=0o644,
help=_('File permission for swift-less image hosting with the '
'octal permission representation of file access '
'permissions. This setting defaults to ``644``, '
'or as the octal number ``0o644`` in Python. '
'This setting must be set to the octal number '
'representation, meaning starting with ``0o``.')),
cfg.StrOpt('kernel_append_params',
default='nofb vga=normal',
mutable=True,
help=_('Additional kernel parameters to pass down to the '
'instance kernel. These parameters can be consumed by '
'the kernel or by the applications by reading '
'/proc/cmdline. Mind severe cmdline size limit! Can be '
'overridden by `instance_info/kernel_append_params` '
'property.')),
cfg.StrOpt('cert_path',
default='/var/lib/ironic/ilo/',
help=_('On the ironic-conductor node, directory where ilo '
'driver stores the CSR and the cert.')),
]
def register_opts(conf):
conf.register_opts(opts, group='ilo')
-1
View File
@@ -37,7 +37,6 @@ _opts = [
('errors', ironic.conf.exception.opts),
('glance', ironic.conf.glance.list_opts()),
('healthcheck', ironic.conf.healthcheck.opts),
('ilo', ironic.conf.ilo.opts),
('inspection_rules', ironic.conf.inspector.inspection_rule_opts),
('inspector', ironic.conf.inspector.opts),
('inventory', ironic.conf.inventory.opts),
-95
View File
@@ -1,95 +0,0 @@
# Copyright 2022 Hewlett Packard Enterprise Development LP
# Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# 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.
"""
iLO Driver for managing HP Proliant Gen8 and above servers.
"""
from ironic.drivers import generic
from ironic.drivers.modules.ilo import bios
from ironic.drivers.modules.ilo import boot
from ironic.drivers.modules.ilo import inspect
from ironic.drivers.modules.ilo import management
from ironic.drivers.modules.ilo import power
from ironic.drivers.modules.ilo import raid
from ironic.drivers.modules.ilo import vendor
from ironic.drivers.modules import noop
class IloHardware(generic.GenericHardware):
"""iLO hardware type.
iLO hardware type is targeted for iLO 4 based Proliant Gen8
and Gen9 servers.
"""
@property
def supported_boot_interfaces(self):
"""List of supported boot interfaces."""
return [boot.IloVirtualMediaBoot, boot.IloiPXEBoot, boot.IloPXEBoot]
@property
def supported_bios_interfaces(self):
"""List of supported bios interfaces."""
return [bios.IloBIOS, noop.NoBIOS]
@property
def supported_console_interfaces(self):
"""List of supported console interfaces."""
return super().supported_console_interfaces
@property
def supported_inspect_interfaces(self):
"""List of supported inspect interfaces."""
return [inspect.IloInspect] + super(
IloHardware, self).supported_inspect_interfaces
@property
def supported_management_interfaces(self):
"""List of supported management interfaces."""
return [management.IloManagement]
@property
def supported_power_interfaces(self):
"""List of supported power interfaces."""
return [power.IloPower]
@property
def supported_vendor_interfaces(self):
"""List of supported vendor interfaces."""
return [vendor.VendorPassthru, noop.NoVendor]
class Ilo5Hardware(IloHardware):
"""iLO5 hardware type.
iLO5 hardware type is targeted for iLO5 based Proliant Gen10 servers.
"""
@property
def supported_boot_interfaces(self):
"""List of supported boot interfaces."""
return super(Ilo5Hardware,
self).supported_boot_interfaces + [boot.IloUefiHttpsBoot]
@property
def supported_raid_interfaces(self):
"""List of supported raid interfaces."""
return [raid.Ilo5RAID] + super(
Ilo5Hardware, self).supported_raid_interfaces
@property
def supported_management_interfaces(self):
"""List of supported management interfaces."""
return [management.Ilo5Management]
-248
View File
@@ -1,248 +0,0 @@
# Copyright 2018 Hewlett-Packard Development Company, L.P.
#
# 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.
"""
iLO BIOS Interface
"""
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 metrics_utils
from ironic.drivers import base
from ironic.drivers.modules import deploy_utils
from ironic.drivers.modules.ilo import common as ilo_common
from ironic import objects
LOG = logging.getLogger(__name__)
METRICS = metrics_utils.get_metrics_logger(__name__)
ilo_error = importutils.try_import('proliantutils.exception')
class IloBIOS(base.BIOSInterface):
_APPLY_CONFIGURATION_ARGSINFO = {
'settings': {
'description': 'Dictionary with current BIOS configuration.',
'required': True
}
}
def get_properties(self):
return ilo_common.REQUIRED_PROPERTIES
@METRICS.timer('IloBIOS.validate')
def validate(self, task):
"""Check that 'driver_info' contains required ILO credentials.
Validates whether the 'driver_info' property of the supplied
task's node contains the required credentials information.
:param task: a task from TaskManager.
:raises: InvalidParameterValue if required iLO parameters
are not valid.
:raises: MissingParameterValue if a required parameter is missing.
"""
ilo_common.parse_driver_info(task.node)
def _execute_pre_boot_bios_step(self, task, step, data=None):
"""Perform operations required prior to the reboot.
Depending on the step, it executes the operations required
and moves the node to CLEANWAIT or DEPLOYWAIT state prior to reboot
based on the operation being performed.
:param task: a task from TaskManager.
:param step: name of the clean step to be performed
:param data: if the clean step is apply_configuration it holds
the settings data.
:raises: NodeCleaningFailure, on failure to execute of clean step.
:raises: InstanceDeployFailure, on failure to execute of deploy step.
"""
node = task.node
if step not in ('apply_configuration', 'factory_reset'):
errmsg = (_('Could not find the step %(step)s for the '
'node %(node)s.')
% {'step': step, 'node': node.uuid})
if node.clean_step:
raise exception.NodeCleaningFailure(errmsg)
raise exception.InstanceDeployFailure(reason=errmsg)
try:
ilo_object = ilo_common.get_ilo_object(node)
ilo_object.set_bios_settings(data) if step == (
'apply_configuration') else ilo_object.reset_bios_to_default()
except (exception.MissingParameterValue,
exception.InvalidParameterValue,
ilo_error.IloError,
ilo_error.IloCommandNotSupportedError) as ir_exception:
errmsg = (_('Step %(step)s failed '
'on the node %(node)s with error: %(err)s')
% {'step': step, 'node': node.uuid, 'err': ir_exception})
if node.clean_step:
raise exception.NodeCleaningFailure(errmsg)
raise exception.InstanceDeployFailure(reason=errmsg)
return_state = deploy_utils.reboot_to_finish_step(task)
deploy_utils.set_async_step_flags(node, reboot=True,
skip_current_step=False)
if step == 'apply_configuration':
node.set_driver_internal_info('apply_bios', True)
else:
node.set_driver_internal_info('reset_bios', True)
node.save()
return return_state
def _execute_post_boot_bios_step(self, task, step):
"""Perform operations required after the reboot.
Caches BIOS settings in the database and clear the flags associated
with the clean step post reboot.
:param task: a task from TaskManager.
:param step: name of the clean step to be performed
:raises: NodeCleaningFailure, on failure to execute of clean step.
:raises: InstanceDeployFailure, on failure to execute of deploy step.
"""
node = task.node
node.del_driver_internal_info('apply_bios')
node.del_driver_internal_info('reset_bios')
node.save()
if step not in ('apply_configuration', 'factory_reset'):
errmsg = (_('Could not find the step %(step)s for the '
'node %(node)s.')
% {'step': step, 'node': node.uuid})
if node.clean_step:
raise exception.NodeCleaningFailure(errmsg)
raise exception.InstanceDeployFailure(reason=errmsg)
try:
ilo_object = ilo_common.get_ilo_object(node)
status = ilo_object.get_bios_settings_result()
except (exception.MissingParameterValue,
exception.InvalidParameterValue,
ilo_error.IloError,
ilo_error.IloCommandNotSupportedError) as ir_exception:
errmsg = (_('Step %(step)s failed '
'on the node %(node)s with error: %(err)s')
% {'step': step, 'node': node.uuid, 'err': ir_exception})
if node.clean_step:
raise exception.NodeCleaningFailure(errmsg)
raise exception.InstanceDeployFailure(reason=errmsg)
if status.get('status') == 'failed':
errmsg = (_('Step %(step)s failed '
'on the node %(node)s with error: %(err)s')
% {'step': step, 'node': node.uuid,
'err': status.get('results')})
if node.clean_step:
raise exception.NodeCleaningFailure(errmsg)
raise exception.InstanceDeployFailure(reason=errmsg)
@METRICS.timer('IloBIOS.apply_configuration')
@base.deploy_step(priority=0, abortable=False,
argsinfo=_APPLY_CONFIGURATION_ARGSINFO)
@base.clean_step(priority=0, abortable=False,
argsinfo=_APPLY_CONFIGURATION_ARGSINFO)
@base.cache_bios_settings
def apply_configuration(self, task, settings):
"""Applies the provided configuration on the node.
:param task: a TaskManager instance.
:param settings: Settings intended to be applied on the node.
:raises: NodeCleaningFailure, on failure to execute of clean step.
:raises: InstanceDeployFailure, on failure to execute of deploy step.
"""
node = task.node
data = {}
for setting in settings:
data.update({setting['name']: setting['value']})
if not node.driver_internal_info.get('apply_bios'):
return self._execute_pre_boot_bios_step(
task, 'apply_configuration', data)
else:
return self._execute_post_boot_bios_step(
task, 'apply_configuration')
@METRICS.timer('IloBIOS.factory_reset')
@base.deploy_step(priority=0, abortable=False)
@base.clean_step(priority=0, abortable=False)
@base.cache_bios_settings
def factory_reset(self, task):
"""Reset the BIOS settings to factory configuration.
:param task: a TaskManager instance.
:raises: NodeCleaningFailure, on failure to execute of clean step.
:raises: InstanceDeployFailure, on failure to execute of deploy step.
"""
node = task.node
if not node.driver_internal_info.get('reset_bios'):
return self._execute_pre_boot_bios_step(task, 'factory_reset')
else:
return self._execute_post_boot_bios_step(task, 'factory_reset')
@METRICS.timer('IloBIOS.cache_bios_settings')
def cache_bios_settings(self, task):
"""Store the BIOS settings in the database.
:param task: a TaskManager instance.
:raises: NodeCleaningFailure, on failure to execute of clean step.
:raises: InstanceDeployFailure, on failure to execute of deploy step.
"""
node = task.node
nodeid = node.id
try:
ilo_object = ilo_common.get_ilo_object(node)
bios_settings = ilo_object.get_current_bios_settings()
except (exception.MissingParameterValue,
exception.InvalidParameterValue,
ilo_error.IloError,
ilo_error.IloCommandNotSupportedError) as ir_exception:
errmsg = (_("Caching BIOS settings failed "
"on node %(node)s with error: %(err)s")
% {'node': node.uuid, 'err': ir_exception})
if node.clean_step:
raise exception.NodeCleaningFailure(errmsg)
raise exception.InstanceDeployFailure(reason=errmsg)
fmt_bios_settings = []
for setting in bios_settings:
fmt_bios_settings.append({"name": setting,
"value": bios_settings[setting]})
create_list, update_list, delete_list, nochange_list = (
objects.BIOSSettingList.sync_node_setting(task.context,
nodeid,
fmt_bios_settings))
if len(create_list) > 0:
objects.BIOSSettingList.create(task.context, nodeid, create_list)
if len(update_list) > 0:
objects.BIOSSettingList.save(task.context, nodeid, update_list)
if len(delete_list) > 0:
delete_name_list = [delete_name.get(
"name") for delete_name in delete_list]
objects.BIOSSettingList.delete(
task.context, nodeid, delete_name_list)
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,446 +0,0 @@
# Copyright 2016 Hewlett Packard Enterprise Development Company LP
#
# 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.
"""
Firmware file processor
"""
import functools
import os
import re
import shutil
import tempfile
import types
from urllib import parse as urlparse
from oslo_config import cfg
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 image_service
from ironic.common import swift
from ironic.drivers.modules.ilo import common as ilo_common
# Supported components for firmware update when invoked through manual clean
# step, ``update_firmware``.
SUPPORTED_ILO_FIRMWARE_UPDATE_COMPONENTS = ['ilo', 'cpld', 'power_pic', 'bios',
'chassis']
# Mandatory fields to be provided as part of firmware image update
# with manual clean step
FIRMWARE_IMAGE_INFO_FIELDS = {'url', 'checksum'}
CONF = cfg.CONF
LOG = logging.getLogger(__name__)
proliantutils_error = importutils.try_import('proliantutils.exception')
proliantutils_utils = importutils.try_import('proliantutils.utils')
def verify_firmware_update_args(func):
"""Verifies the firmware update arguments."""
@functools.wraps(func)
def wrapper(self, task, **kwargs):
"""Wrapper around ``update_firmware`` call.
:param task: a TaskManager object.
:raises: InvalidParameterValue if validation fails for input arguments
of firmware update.
"""
firmware_update_mode = kwargs.get('firmware_update_mode')
firmware_images = kwargs.get('firmware_images')
if firmware_update_mode != 'ilo':
msg = (_("Invalid firmware update mode '%(mode)s' provided for "
"node: %(node)s. 'ilo' is the only supported firmware "
"update mode.")
% {'mode': firmware_update_mode, 'node': task.node.uuid})
LOG.error(msg)
raise exception.InvalidParameterValue(msg)
if not firmware_images:
msg = _("Firmware images cannot be an empty list or None.")
LOG.error(msg)
raise exception.InvalidParameterValue(msg)
return func(self, task, **kwargs)
return wrapper
def _validate_ilo_component(component):
"""Validates component with supported values.
:param component: name of the component to be validated.
:raises: InvalidParameterValue, for unsupported firmware component
"""
if component not in SUPPORTED_ILO_FIRMWARE_UPDATE_COMPONENTS:
msg = (_("Component '%(component)s' for firmware update is not "
"supported in 'ilo' based firmware update. Supported "
"values are: %(supported_components)s") %
{'component': component, 'supported_components': (
", ".join(SUPPORTED_ILO_FIRMWARE_UPDATE_COMPONENTS))})
LOG.error(msg)
raise exception.InvalidParameterValue(msg)
def _validate_sum_components(components):
"""Validates components' file extension with supported values.
:param components: A list of components to be updated.
:raises: InvalidParameterValue, for unsupported firmware component
"""
not_supported = []
for component in components:
if not re.search('\\.(scexe|exe|rpm)$', component):
not_supported.append(component)
if not_supported:
msg = (_("The component files '%s' provided are not supported in "
"'SUM' based firmware update. The valid file extensions are "
"'scexe', 'exe', 'rpm'.") %
', '.join(x for x in not_supported))
LOG.error(msg)
raise exception.InvalidParameterValue(msg)
def get_and_validate_firmware_image_info(firmware_image_info,
firmware_update_mode):
"""Validates the firmware image info and returns the retrieved values.
:param firmware_image_info: dict object containing the firmware image info
:raises: MissingParameterValue, for missing fields (or values) in
image info.
:raises: InvalidParameterValue, for unsupported firmware component
:returns: tuple of firmware url, checksum, component when the firmware
update is ilo based.
"""
image_info = firmware_image_info or {}
LOG.debug("Validating firmware image info: %s ... in progress", image_info)
missing_fields = []
for field in FIRMWARE_IMAGE_INFO_FIELDS:
if not image_info.get(field):
missing_fields.append(field)
if firmware_update_mode == 'ilo' and not image_info.get('component'):
missing_fields.append('component')
if missing_fields:
msg = (_("Firmware image info: %(image_info)s is missing the "
"required %(missing)s field/s.") %
{'image_info': image_info,
'missing': ", ".join(missing_fields)})
LOG.error(msg)
raise exception.MissingParameterValue(msg)
if firmware_update_mode == 'sum':
component = image_info.get('components')
if component:
_validate_sum_components(component)
else:
component = image_info['component'].lower()
_validate_ilo_component(component)
LOG.debug("Validating firmware image info: %s ... done", image_info)
return image_info['url'], image_info['checksum'], component
class FirmwareProcessor(object):
"""Firmware file processor
This class helps in downloading the firmware file from url, extracting
the firmware file (if its in compact format) and makes it ready for
firmware update operation. In future, methods can be added as and when
required to extend functionality for different firmware file types.
"""
def __init__(self, url):
# :attribute ``self.parsed_url``: structure returned by urlparse
self._fine_tune_fw_processor(url)
def _fine_tune_fw_processor(self, url):
"""Fine tunes the firmware processor object based on specified url
:param url: url of firmware file
:raises: InvalidParameterValue, for unsupported firmware url
"""
parsed_url = urlparse.urlparse(url)
self.parsed_url = parsed_url
url_scheme = parsed_url.scheme
if url_scheme == 'file':
self._download_fw_to = types.MethodType(
_download_file_based_fw_to, self)
elif url_scheme in ('http', 'https'):
self._download_fw_to = types.MethodType(
_download_http_based_fw_to, self)
elif url_scheme == 'swift':
self._download_fw_to = types.MethodType(
_download_swift_based_fw_to, self)
else:
raise exception.InvalidParameterValue(
_('This method does not support URL scheme %(url_scheme)s. '
'Invalid URL %(url)s. The supported firmware URL schemes '
'are "file", "http", "https" and "swift"') %
{'url': url, 'url_scheme': url_scheme})
def process_fw_on(self, node, expected_checksum):
"""Processes the firmware file from the url
This is the template method which downloads the firmware file from
url, verifies checksum and extracts the firmware and makes it ready
for firmware update operation. ``_download_fw_to`` method is set in
the firmware processor object creation factory method,
``get_fw_processor()``, based on the url type.
:param node: a single Node.
:param expected_checksum: checksum to be checked against.
:returns: wrapper object of raw firmware image location
:raises: IloOperationError, on failure to process firmware file.
:raises: ImageDownloadFailed, on failure to download the original file.
:raises: ImageRefValidationFailed, on failure to verify the checksum.
:raises: SwiftOperationError, if upload to Swift fails.
:raises: ImageUploadFailed, if upload to web server fails.
"""
filename = os.path.basename(self.parsed_url.path)
# create a temp directory where firmware file will be downloaded
temp_dir = tempfile.mkdtemp()
target_file = os.path.join(temp_dir, filename)
# Note(deray): Operations performed in here:
#
# 1. Download the firmware file to the target file.
# 2. Verify the checksum of the downloaded file.
# 3. Extract the raw firmware file from its compact format
#
try:
LOG.debug("For firmware update, downloading firmware file "
"%(src_file)s to: %(target_file)s ...",
{'src_file': self.parsed_url.geturl(),
'target_file': target_file})
self._download_fw_to(target_file)
LOG.debug("For firmware update, verifying checksum of file: "
"%(target_file)s ...", {'target_file': target_file})
ilo_common.verify_image_checksum(target_file, expected_checksum)
# Extracting raw firmware file from target_file ...
fw_image_location_obj, is_different_file = (_extract_fw_from_file(
node, target_file))
except exception.IronicException:
# delete the target file along with temp dir and
# re-raise the exception
shutil.rmtree(temp_dir, ignore_errors=True)
raise
# Note(deray): In case of raw (no need for extraction) firmware files,
# the same firmware file is returned from the extract method.
# Hence, don't blindly delete the firmware file which gets passed on
# to extraction operation after successful extract. Check whether the
# file is same or not and then go ahead deleting it.
if is_different_file:
# delete the entire downloaded content along with temp dir.
shutil.rmtree(temp_dir, ignore_errors=True)
LOG.info("Final processed firmware location: %s",
fw_image_location_obj.fw_image_location)
return fw_image_location_obj
def _download_file_based_fw_to(self, target_file):
"""File based firmware file downloader (copier)
It copies the file (url) to temporary location (file location).
Original firmware file location (url) is expected in the format
"file:///tmp/.."
:param target_file: destination file for copying the original firmware
file.
:raises: ImageDownloadFailed, on failure to copy the original file.
"""
src_file = self.parsed_url.path
with open(target_file, 'wb') as fd:
image_service.FileImageService().download(src_file, fd)
def _download_http_based_fw_to(self, target_file):
"""HTTP based firmware file downloader
It downloads the file (url) to temporary location (file location).
Original firmware file location (url) is expected in the format
"http://.."
:param target_file: destination file for downloading the original firmware
file.
:raises: ImageDownloadFailed, on failure to download the original file.
"""
src_file = self.parsed_url.geturl()
with open(target_file, 'wb') as fd:
image_service.HttpImageService().download(src_file, fd)
def get_swift_url(parsed_url):
"""Gets swift temp url.
It generates a temp url for the swift based firmware url to the target
file. Expecting url as swift://containername/objectname.
:param parsed_url: Parsed url object.
:raises: SwiftOperationError, on failure to get url from swift.
"""
# Extract container name
container = parsed_url.netloc
# Extract the object name from the path of the form:
# ``/objectname`` OR
# ``/pseudo-folder/objectname``
# stripping the leading '/' character.
objectname = parsed_url.path.lstrip('/')
timeout = CONF.ilo.swift_object_expiry_timeout
# Generate temp url using swift API
return swift.SwiftAPI().get_temp_url(container, objectname, timeout)
def _download_swift_based_fw_to(self, target_file):
"""Swift based firmware file downloader
It downloads the firmware file via http based downloader to the target
file. Expecting url as swift://containername/objectname
:param target_file: destination file for downloading the original firmware
file.
:raises: ImageDownloadFailed, on failure to download the original file.
"""
# set the parsed_url attribute to the newly created tempurl from swift and
# delegate the downloading job to the http_based downloader
self.parsed_url = urlparse.urlparse(get_swift_url(self.parsed_url))
_download_http_based_fw_to(self, target_file)
def _extract_fw_from_file(node, target_file):
"""Extracts firmware image file.
Extracts the firmware image file thru proliantutils and uploads it to the
conductor webserver, if needed.
:param node: an Ironic node object.
:param target_file: firmware file to be extracted from
:returns: tuple of:
a) wrapper object of raw firmware image location
b) a boolean, depending upon whether the raw firmware file was
already in raw format(same file remains, no need to extract)
or compact format (thereby extracted and hence different
file). If uploaded then, then also its a different file.
:raises: ImageUploadFailed, if upload to web server fails.
:raises: SwiftOperationError, if upload to Swift fails.
:raises: IloOperationError, on failure to process firmware file.
"""
ilo_object = ilo_common.get_ilo_object(node)
try:
# Note(deray): Based upon different iLO firmwares, the firmware file
# which needs to be updated has to be either an http/https or a simple
# file location. If it has to be a http/https location, then conductor
# will take care of uploading the firmware file to web server or
# swift (providing a temp url).
fw_image_location, to_upload, is_extracted = (
proliantutils_utils.process_firmware_image(target_file,
ilo_object))
except (proliantutils_error.InvalidInputError,
proliantutils_error.ImageExtractionFailed) as proliantutils_exc:
operation = _("Firmware file extracting as part of manual cleaning")
raise exception.IloOperationError(operation=operation,
error=proliantutils_exc)
is_different_file = is_extracted
fw_image_filename = os.path.basename(fw_image_location)
fw_image_location_obj = FirmwareImageLocation(fw_image_location,
fw_image_filename)
if to_upload:
is_different_file = True
try:
if CONF.ilo.use_web_server_for_images:
# upload firmware image file to conductor webserver
LOG.debug("For firmware update on node %(node)s, hosting "
"firmware file %(firmware_image)s on web server ...",
{'firmware_image': fw_image_location,
'node': node.uuid})
fw_image_uploaded_url = ilo_common.copy_image_to_web_server(
fw_image_location, fw_image_filename)
fw_image_location_obj.fw_image_location = fw_image_uploaded_url
fw_image_location_obj.remove = types.MethodType(
_remove_webserver_based_me, fw_image_location_obj)
else:
# upload firmware image file to swift
LOG.debug("For firmware update on node %(node)s, hosting "
"firmware file %(firmware_image)s on swift ...",
{'firmware_image': fw_image_location,
'node': node.uuid})
fw_image_uploaded_url = ilo_common.copy_image_to_swift(
fw_image_location, fw_image_filename)
fw_image_location_obj.fw_image_location = fw_image_uploaded_url
fw_image_location_obj.remove = types.MethodType(
_remove_swift_based_me, fw_image_location_obj)
finally:
if is_extracted:
# Note(deray): remove the file `fw_image_location` irrespective
# of status of uploading (success or failure) and only if
# extracted (and not passed as in plain binary format). If the
# file is passed in binary format, then the invoking method
# takes care of handling the deletion of the file.
ilo_common.remove_single_or_list_of_files(fw_image_location)
LOG.debug("For firmware update on node %(node)s, hosting firmware "
"file: %(fw_image_location)s ... done. Hosted firmware "
"file: %(fw_image_uploaded_url)s",
{'fw_image_location': fw_image_location, 'node': node.uuid,
'fw_image_uploaded_url': fw_image_uploaded_url})
else:
fw_image_location_obj.remove = types.MethodType(
_remove_file_based_me, fw_image_location_obj)
return fw_image_location_obj, is_different_file
class FirmwareImageLocation(object):
"""Firmware image location class
This class acts as a wrapper class for the firmware image location.
It primarily helps in removing the firmware files from their respective
locations, made available for firmware update operation.
"""
def __init__(self, fw_image_location, fw_image_filename):
"""Keeps hold of image location and image filename"""
self.fw_image_location = fw_image_location
self.fw_image_filename = fw_image_filename
def remove(self):
"""Exposed method to remove the wrapped firmware file
This method gets overridden by the remove method for the respective
type of firmware file location it wraps.
"""
pass
def _remove_file_based_me(self):
"""Removes file based firmware image location"""
ilo_common.remove_single_or_list_of_files(self.fw_image_location)
def _remove_swift_based_me(self):
"""Removes swift based firmware image location (by its object name)"""
ilo_common.remove_image_from_swift(self.fw_image_filename,
"firmware update")
def _remove_webserver_based_me(self):
"""Removes webserver based firmware image location (by its file name)"""
ilo_common.remove_image_from_web_server(self.fw_image_filename)
-316
View File
@@ -1,316 +0,0 @@
# 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.
"""
iLO Inspect Interface
"""
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 metrics_utils
from ironic.common import states
from ironic.common import utils
from ironic.conductor import utils as conductor_utils
from ironic.drivers import base
from ironic.drivers.modules.ilo import common as ilo_common
from ironic.drivers.modules import inspect_utils
ilo_error = importutils.try_import('proliantutils.exception')
LOG = logging.getLogger(__name__)
METRICS = metrics_utils.get_metrics_logger(__name__)
CAPABILITIES_KEYS = {'secure_boot', 'rom_firmware_version',
'ilo_firmware_version', 'server_model',
'pci_gpu_devices', 'sriov_enabled', 'nic_capacity',
'has_ssd', 'has_rotational',
'rotational_drive_4800_rpm',
'rotational_drive_5400_rpm',
'rotational_drive_7200_rpm',
'rotational_drive_10000_rpm',
'rotational_drive_15000_rpm',
'logical_raid_level_0', 'logical_raid_level_1',
'logical_raid_level_2', 'logical_raid_level_10',
'logical_raid_level_5', 'logical_raid_level_6',
'logical_raid_level_50', 'logical_raid_level_60',
'cpu_vt', 'hardware_supports_raid', 'has_nvme_ssd',
'nvdimm_n', 'logical_nvdimm_n', 'persistent_memory',
'overall_security_status', 'security_override_switch',
'last_firmware_scan_result'}
def _get_essential_properties(node, ilo_object):
"""Inspects the node and get essential scheduling properties
:param node: node object.
:param ilo_object: an instance of proliantutils.ilo.IloClient
:raises: HardwareInspectionFailure if any of the properties values
are missing.
:returns: The dictionary containing properties and MAC data.
The dictionary possible keys are 'properties' and 'macs'.
The 'properties' should contain keys as in
IloInspect.ESSENTIAL_PROPERTIES. The 'macs' is a dictionary
containing key:value pairs of <port_numbers:mac_addresses>
"""
try:
# Retrieve the mandatory properties from hardware
result = ilo_object.get_essential_properties()
except ilo_error.IloError as e:
raise exception.HardwareInspectionFailure(error=e)
_validate(node, result)
return result
def _validate(node, data):
"""Validate the received value against the supported keys in ironic.
:param node: node object.
:param data: the dictionary received by querying server.
:raises: HardwareInspectionFailure
"""
if data.get('properties'):
if isinstance(data['properties'], dict):
valid_keys = IloInspect.ESSENTIAL_PROPERTIES
missing_keys = valid_keys - set(data['properties'])
if missing_keys:
error = (_(
"Server didn't return the key(s): %(key)s") %
{'key': ', '.join(missing_keys)})
raise exception.HardwareInspectionFailure(error=error)
else:
error = (_("Essential properties are expected to be in dictionary "
"format, received %(properties)s from node "
"%(node)s.") % {"properties": data['properties'],
'node': node.uuid})
raise exception.HardwareInspectionFailure(error=error)
else:
error = (_("The node %s didn't return 'properties' as the key with "
"inspection.") % node.uuid)
raise exception.HardwareInspectionFailure(error=error)
if data.get('macs'):
if not isinstance(data['macs'], dict):
error = (_("Node %(node)s didn't return MACs %(macs)s "
"in dictionary format.")
% {"macs": data['macs'], 'node': node.uuid})
raise exception.HardwareInspectionFailure(error=error)
else:
error = (_("The node %s didn't return 'macs' as the key with "
"inspection.") % node.uuid)
raise exception.HardwareInspectionFailure(error=error)
def _create_supported_capabilities_dict(capabilities):
"""Creates a capabilities dictionary from supported capabilities in ironic.
:param capabilities: a dictionary of capabilities as returned by the
hardware.
:returns: a dictionary of the capabilities supported by ironic
and returned by hardware.
"""
valid_cap = {}
# Add the capabilities starting with "gpu_" to the supported capabilities
# keys set as they are runtime generated keys and cannot be hardcoded.
for k in capabilities:
if k.startswith("gpu_"):
valid_cap[k] = capabilities.get(k)
for key in CAPABILITIES_KEYS.intersection(capabilities):
valid_cap[key] = capabilities.get(key)
return valid_cap
def _get_capabilities(node, ilo_object):
"""inspects hardware and gets additional capabilities.
:param node: Node object.
:param ilo_object: an instance of ilo drivers.
:returns: a string of capabilities like
'key1:value1,key2:value2,key3:value3'
or None.
"""
capabilities = None
try:
capabilities = ilo_object.get_server_capabilities()
except ilo_error.IloError:
LOG.debug("Node %s did not return any additional capabilities.",
node.uuid)
return capabilities
def _get_security_parameters(node, ilo_object):
"""inspect hardware and gets security parameter information.
:param node: Node object.
:param ilo_object: an instance of ilo drivers.
:returns: a dictionary of security parameters.
"""
security_params = None
try:
security_params = ilo_object.get_security_dashboard_values()
except ilo_error.IloError:
LOG.debug("Node %s did not return any security parameters.",
node.uuid)
return security_params
class IloInspect(base.InspectInterface):
def get_properties(self):
props = ilo_common.REQUIRED_PROPERTIES.copy()
props.update(ilo_common.SNMP_PROPERTIES)
props.update(ilo_common.SNMP_OPTIONAL_PROPERTIES)
return props
@METRICS.timer('IloInspect.validate')
def validate(self, task):
"""Check that 'driver_info' contains required ILO credentials.
Validates whether the 'driver_info' property of the supplied
task's node contains the required credentials information.
:param task: a task from TaskManager.
:raises: InvalidParameterValue if required iLO parameters
are not valid.
:raises: MissingParameterValue if a required parameter is missing.
"""
node = task.node
ilo_common.parse_driver_info(node)
@METRICS.timer('IloInspect.inspect_hardware')
def inspect_hardware(self, task):
"""Inspect hardware to get the hardware properties.
Inspects hardware to get the essential and additional hardware
properties. It fails if any of the essential properties
are not received from the node. It doesn't fail if node fails
to return any capabilities as the capabilities differ from hardware
to hardware mostly.
:param task: a TaskManager instance.
:raises: HardwareInspectionFailure if essential properties
could not be retrieved successfully.
:raises: IloOperationError if system fails to get power state.
:returns: The resulting state of inspection.
"""
power_turned_on = False
ilo_object = ilo_common.get_ilo_object(task.node)
try:
state = task.driver.power.get_power_state(task)
except exception.IloOperationError as ilo_exception:
operation = (_("Inspecting hardware (get_power_state) on %s")
% task.node.uuid)
raise exception.IloOperationError(operation=operation,
error=ilo_exception)
if state != states.POWER_ON:
LOG.info("The node %s is not powered on. Powering on the "
"node for inspection.", task.node.uuid)
conductor_utils.node_power_action(task, states.POWER_ON)
power_turned_on = True
# get the essential properties and update the node properties
# with it.
inspected_properties = {}
result = _get_essential_properties(task.node, ilo_object)
# A temporary hook for OOB inspection to not to update 'local_gb'
# for hardware if the storage is a "Direct Attached Storage" or
# "Dynamic Smart Array Controllers" and the operator has manually
# updated the local_gb in node properties prior to node inspection.
# This will be removed once we have inband inspection support for
# ilo drivers.
current_local_gb = task.node.properties.get('local_gb')
properties = result['properties']
if current_local_gb:
if properties['local_gb'] == 0 and current_local_gb > 0:
properties['local_gb'] = current_local_gb
LOG.warning('Could not discover size of disk on the node '
'%s. Value of `properties/local_gb` of the '
'node is not overwritten.', task.node.uuid)
for known_property in self.ESSENTIAL_PROPERTIES:
inspected_properties[known_property] = properties[known_property]
node_properties = task.node.properties
node_properties.update(inspected_properties)
task.node.properties = node_properties
# Inspect the hardware for additional hardware capabilities.
# Since additional hardware capabilities may not apply to all the
# hardwares, the method inspect_hardware() doesn't raise an error
# for these capabilities.
capabilities = _get_capabilities(task.node, ilo_object)
model = None
if capabilities:
model = capabilities.get('server_model')
valid_cap = _create_supported_capabilities_dict(capabilities)
capabilities = utils.get_updated_capabilities(
task.node.properties.get('capabilities'), valid_cap)
if capabilities:
node_properties['capabilities'] = capabilities
task.node.properties = node_properties
# Inspect the hardware for security parameters related information.
# Since it applies only for Gen10 based hardware, the method
# inspect_hardware() doesn't raise an error.
if model and 'Gen10' in model:
security_params = _get_security_parameters(task.node, ilo_object)
if security_params:
node_properties['security_parameters'] = (
security_params.get('security_parameters'))
task.node.properties = node_properties
# RIBCL(Gen8) protocol cannot determine if a NIC
# is physically connected with cable or not when the server
# is not provisioned. RIS(Gen9) can detect the same for few NIC
# adapters but not for all. However it is possible to determine
# the same using Redfish(Gen10) protocol. Hence proliantutils
# returns ALL MACs for Gen8 and Gen9 while it returns
# only active MACs for Gen10. A warning is being added
# for the user so that he knows that he needs to remove the
# ironic ports created for inactive ports for Gen8 and Gen9.
servers = ['Gen8', 'Gen9']
if model is not None and any(serv in model for serv in servers):
LOG.warning('iLO cannot determine if the NICs are physically '
'connected or not for ProLiant Gen8 and Gen9 servers. '
'Hence returns all the MACs present on the server. '
'Please remove the ironic ports created for inactive '
'NICs manually for the node %(node)s',
{"node": task.node.uuid})
task.node.save()
# Create ports for the nics detected.
inspect_utils.create_ports_if_not_exist(
task, list(result['macs'].values()))
LOG.debug("Node properties for %(node)s are updated as "
"%(properties)s",
{'properties': inspected_properties,
'node': task.node.uuid})
LOG.info("Node %s inspected.", task.node.uuid)
if power_turned_on:
conductor_utils.node_power_action(task, states.POWER_OFF)
LOG.info("The node %s was powered on for inspection. "
"Powered off the node as inspection completed.",
task.node.uuid)
return states.MANAGEABLE
File diff suppressed because it is too large Load Diff
-371
View File
@@ -1,371 +0,0 @@
# Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# 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.
"""
iLO Power Driver
"""
from oslo_log import log as logging
from oslo_service import loopingcall
from oslo_utils import importutils
from ironic.common import boot_devices
from ironic.common import exception
from ironic.common.i18n import _
from ironic.common import metrics_utils
from ironic.common import states
from ironic.conductor import task_manager
from ironic.conductor import utils as manager_utils
from ironic.conf import CONF
from ironic.drivers import base
from ironic.drivers.modules.ilo import common as ilo_common
from ironic.drivers import utils as driver_utils
ilo_error = importutils.try_import('proliantutils.exception')
LOG = logging.getLogger(__name__)
METRICS = metrics_utils.get_metrics_logger(__name__)
def _attach_boot_iso_if_needed(task):
"""Attaches boot ISO for a deployed node.
This method checks the instance info of the baremetal node for a
boot iso. If the instance info has a value of key 'boot_iso',
it indicates ramdisk deploy. Therefore it attaches the boot ISO on the
baremetal node and then sets the node to boot from virtual media cdrom.
:param task: a TaskManager instance containing the node to act on.
"""
node_state = task.node.provision_state
# NOTE: On instance rebuild, boot_iso will be present in
# instance_info but the node will be in DEPLOYING state.
# In such a scenario, the boot_iso shouldn't be
# attached to the node while powering on the node (the node
# should boot from deploy ramdisk instead, which will already
# be attached by the deploy driver).
boot_iso = driver_utils.get_field(task.node, 'boot_iso',
deprecated_prefix='ilo',
collection='instance_info')
if boot_iso and node_state == states.ACTIVE:
ilo_common.setup_vmedia_for_boot(task, boot_iso)
manager_utils.node_set_boot_device(task, boot_devices.CDROM)
def _get_power_state(node):
"""Returns the current power state of the node.
:param node: The node.
:returns: power state, one of :mod: `ironic.common.states`.
:raises: InvalidParameterValue if required iLO credentials are missing.
:raises: IloOperationError on an error from IloClient library.
"""
ilo_object = ilo_common.get_ilo_object(node)
# Check the current power state.
try:
power_status = ilo_object.get_host_power_status()
except ilo_error.IloError as ilo_exception:
LOG.error("iLO get_power_state failed for node %(node_id)s with "
"error: %(error)s.",
{'node_id': node.uuid, 'error': ilo_exception})
operation = _('iLO get_power_status')
if 'RIBCLI is disabled' in str(ilo_exception):
warn_msg = ("Node %s appears to have a disabled API "
"required for the \'%s\' hardware type to function. "
"Please consider using the \'redfish\' hardware "
"type." % (node.uuid, node.driver))
manager_utils.node_history_record(node, event=warn_msg,
event_type=node.provision_state,
error=True)
raise exception.IloOperationError(operation=operation,
error=warn_msg)
raise exception.IloOperationError(operation=operation,
error=ilo_exception)
if power_status == "ON":
return states.POWER_ON
elif power_status == "OFF":
return states.POWER_OFF
else:
return states.ERROR
def _wait_for_state_change(node, target_state, requested_state,
is_final_state=True, timeout=None):
"""Wait for the power state change to get reflected.
:param node: The node.
:param target_state: calculated target power state of the node.
:param requested_state: actual requested power state of the node.
:param is_final_state: True, if the given target state is the final
expected power state of the node. Default is True.
:param timeout: timeout (in seconds) positive integer (> 0) for any
power state. ``None`` indicates default timeout.
:returns: time consumed to achieve the power state change.
:raises: IloOperationError on an error from IloClient library.
:raises: PowerStateFailure if power state failed to change within timeout.
"""
state = [None]
retries = [0]
interval = CONF.ilo.power_wait
if timeout:
max_retry = int(timeout / interval)
else:
# Since we are going to track server post state, we are not using
# CONF.conductor.power_state_change_timeout as its default value
# is too short for bare metal to reach 'finished post' state
# during 'power on' operation. It could lead to deploy failures
# with default ironic configuration.
# Use conductor.soft_power_off_timeout, instead.
max_retry = int(CONF.conductor.soft_power_off_timeout / interval)
state_to_check = target_state
use_post_state = False
if _can_get_server_post_state(node):
use_post_state = True
if (target_state in [states.POWER_OFF, states.SOFT_POWER_OFF]
or target_state == states.SOFT_REBOOT and not is_final_state):
state_to_check = ilo_common.POST_POWEROFF_STATE
else:
# It may not be able to finish POST if no bootable device is
# found. Track (POST_FINISHEDPOST_STATE) only for soft reboot.
# For other power-on cases track for beginning of POST operation
# (POST_INPOST_STATE) to return.
state_to_check = (
ilo_common.POST_FINISHEDPOST_STATE if
requested_state == states.SOFT_REBOOT else
ilo_common.POST_INPOST_STATE)
def _wait(state):
if use_post_state:
state[0] = ilo_common.get_server_post_state(node)
else:
state[0] = _get_power_state(node)
# NOTE(rameshg87): For reboot operations, initially the state
# will be same as the final state. So defer the check for one retry.
if retries[0] != 0 and state[0] == state_to_check:
raise loopingcall.LoopingCallDone()
if retries[0] > max_retry:
state[0] = states.ERROR
raise loopingcall.LoopingCallDone()
LOG.debug("%(tim)s secs elapsed while waiting for power state "
"of '%(target_state)s', current state of server %(node)s "
"is '%(cur_state)s'.",
{'tim': int(retries[0] * interval),
'target_state': state_to_check,
'node': node.uuid,
'cur_state': state[0]})
retries[0] += 1
# Start a timer and wait for the operation to complete.
timer = loopingcall.FixedIntervalLoopingCall(_wait, state)
timer.start(interval=interval).wait()
if state[0] == state_to_check:
return int(retries[0] * interval)
else:
timeout = int(max_retry * interval)
LOG.error("iLO failed to change state to %(tstate)s "
"within %(timeout)s sec for node %(node)s. Reported "
"state from iLO is %(state)s, expected state from iLO "
"is %(expected)s.",
{'tstate': target_state, 'node': node.uuid,
'timeout': int(max_retry * interval), 'state': state[0],
'expected': state_to_check})
raise exception.PowerStateFailure(pstate=target_state)
def _set_power_state(task, target_state, timeout=None):
"""Turns the server power on/off or do a reboot.
:param task: a TaskManager instance containing the node to act on.
:param target_state: target state of the node.
:param timeout: timeout (in seconds) positive integer (> 0) for any
power state. ``None`` indicates default timeout.
:raises: InvalidParameterValue if an invalid power state was specified.
:raises: IloOperationError on an error from IloClient library.
:raises: PowerStateFailure if the power couldn't be set to target_state.
"""
node = task.node
ilo_object = ilo_common.get_ilo_object(node)
# Check if its soft power operation
soft_power_op = target_state in [states.SOFT_POWER_OFF, states.SOFT_REBOOT]
requested_state = target_state
if target_state == states.SOFT_REBOOT:
if _get_power_state(node) == states.POWER_OFF:
target_state = states.POWER_ON
# Trigger the operation based on the target state.
try:
if target_state == states.POWER_OFF:
ilo_object.hold_pwr_btn()
elif target_state == states.POWER_ON:
_attach_boot_iso_if_needed(task)
ilo_object.set_host_power('ON')
elif target_state == states.REBOOT:
_attach_boot_iso_if_needed(task)
ilo_object.reset_server()
target_state = states.POWER_ON
elif target_state in (states.SOFT_POWER_OFF, states.SOFT_REBOOT):
ilo_object.press_pwr_btn()
else:
msg = _("_set_power_state called with invalid power state "
"'%s'") % target_state
raise exception.InvalidParameterValue(msg)
except ilo_error.IloError as ilo_exception:
LOG.error("iLO set_power_state failed to set state to %(tstate)s "
" for node %(node_id)s with error: %(error)s",
{'tstate': target_state, 'node_id': node.uuid,
'error': ilo_exception})
operation = _('iLO set_power_state')
raise exception.IloOperationError(operation=operation,
error=ilo_exception)
# Wait till the soft power state change gets reflected.
time_consumed = 0
if soft_power_op:
# For soft power-off, bare metal reaches final state with one
# power operation. In case of soft reboot it takes two; soft
# power-off followed by power-on. Also, for soft reboot we
# need to ensure timeout does not expire during power-off
# and power-on operation.
is_final_state = target_state in (states.SOFT_POWER_OFF,
states.POWER_ON)
time_consumed = _wait_for_state_change(
node, target_state, requested_state,
is_final_state=is_final_state, timeout=timeout)
if target_state == states.SOFT_REBOOT:
_attach_boot_iso_if_needed(task)
try:
ilo_object.set_host_power('ON')
except ilo_error.IloError as ilo_exception:
operation = (_('Powering on failed after soft power off for '
'node %s') % node.uuid)
raise exception.IloOperationError(operation=operation,
error=ilo_exception)
# Re-calculate timeout available for power-on operation
rem_timeout = timeout - time_consumed
time_consumed += _wait_for_state_change(
node, states.SOFT_REBOOT, requested_state, is_final_state=True,
timeout=rem_timeout)
else:
time_consumed = _wait_for_state_change(
node, target_state, requested_state, is_final_state=True,
timeout=timeout)
LOG.info("The node %(node_id)s operation of '%(state)s' "
"is completed in %(time_consumed)s seconds.",
{'node_id': node.uuid, 'state': target_state,
'time_consumed': time_consumed})
def _can_get_server_post_state(node):
"""Checks if POST state can be retrieved.
Returns True if the POST state of the server can be retrieved.
It cannot be retrieved for older ProLiant models.
:param node: The node.
:returns: True if POST state can be retrieved, else False.
:raises: IloOperationError on an error from IloClient library.
"""
try:
ilo_common.get_server_post_state(node)
return True
except exception.IloOperationNotSupported as exc:
LOG.debug("Node %(node)s does not support retrieval of "
"boot post state. Reason: %(reason)s",
{'node': node.uuid, 'reason': exc})
return False
class IloPower(base.PowerInterface):
def get_properties(self):
return ilo_common.COMMON_PROPERTIES
@METRICS.timer('IloPower.validate')
def validate(self, task):
"""Check if node.driver_info contains the required iLO credentials.
:param task: a TaskManager instance.
:param node: Single node object.
:raises: InvalidParameterValue if required iLO credentials are missing.
"""
ilo_common.parse_driver_info(task.node)
@METRICS.timer('IloPower.get_power_state')
def get_power_state(self, task):
"""Gets the current power state.
:param task: a TaskManager instance.
:param node: The Node.
:returns: one of :mod:`ironic.common.states` POWER_OFF,
POWER_ON or ERROR.
:raises: InvalidParameterValue if required iLO credentials are missing.
:raises: IloOperationError on an error from IloClient library.
"""
return _get_power_state(task.node)
@METRICS.timer('IloPower.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). Unsupported by this interface.
:raises: InvalidParameterValue if an invalid power state was specified.
:raises: IloOperationError on an error from IloClient library.
:raises: PowerStateFailure if the power couldn't be set to power_state.
"""
_set_power_state(task, power_state, timeout=timeout)
@METRICS.timer('IloPower.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). Unsupported by this interface.
:raises: PowerStateFailure if the final state of the node is not
POWER_ON.
:raises: IloOperationError on an error from IloClient library.
"""
node = task.node
current_pstate = _get_power_state(node)
if current_pstate == states.POWER_ON:
_set_power_state(task, states.REBOOT, timeout=timeout)
elif current_pstate == states.POWER_OFF:
_set_power_state(task, states.POWER_ON, timeout=timeout)
@METRICS.timer('IloPower.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_OFF, states.POWER_ON, states.REBOOT,
states.SOFT_POWER_OFF, states.SOFT_REBOOT]
-267
View File
@@ -1,267 +0,0 @@
# Copyright 2018 Hewlett Packard Enterprise Development LP
#
# 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.
"""
iLO5 RAID specific methods
"""
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 metrics_utils
from ironic.common import raid
from ironic.common import states
from ironic.conductor import utils as manager_utils
from ironic import conf
from ironic.drivers import base
from ironic.drivers.modules import deploy_utils
from ironic.drivers.modules.ilo import common as ilo_common
LOG = logging.getLogger(__name__)
CONF = conf.CONF
METRICS = metrics_utils.get_metrics_logger(__name__)
ilo_error = importutils.try_import('proliantutils.exception')
class Ilo5RAID(base.RAIDInterface):
"""Implementation of OOB RAIDInterface for iLO5."""
_RAID_APPLY_CONFIGURATION_ARGSINFO = {
"raid_config": {
"description": "The RAID configuration to apply.",
"required": True,
},
"create_root_volume": {
"description": (
"Setting this to 'False' indicates not to create root "
"volume that is specified in 'raid_config'. Default "
"value is 'True'."
),
"required": False,
},
"create_nonroot_volumes": {
"description": (
"Setting this to 'False' indicates not to create "
"non-root volumes (all except the root volume) in "
"'raid_config'. Default value is 'True'."
),
"required": False,
}
}
def get_properties(self):
"""Return the properties of the interface."""
return ilo_common.REQUIRED_PROPERTIES
def _set_step_failed(self, task, msg, exc):
log_msg = ("RAID configuration job failed for node %(node)s. "
"Message: '%(message)s'." %
{'node': task.node.uuid, 'message': msg})
if task.node.provision_state == states.DEPLOYING:
manager_utils.deploying_error_handler(task, log_msg, errmsg=msg)
else:
manager_utils.cleaning_error_handler(task, log_msg, errmsg=msg)
def _set_driver_internal_true_value(self, task, *keys):
for key in keys:
task.node.set_driver_internal_info(key, True)
task.node.save()
def _set_driver_internal_false_value(self, task, *keys):
for key in keys:
task.node.set_driver_internal_info(key, False)
task.node.save()
def _pop_driver_internal_values(self, task, *keys):
for key in keys:
task.node.del_driver_internal_info(key)
task.node.save()
def _prepare_for_read_raid(self, task, raid_step):
deploy_utils.reboot_to_finish_step(task)
if raid_step == 'create_raid':
self._set_driver_internal_true_value(
task, 'ilo_raid_create_in_progress')
else:
self._set_driver_internal_true_value(
task, 'ilo_raid_delete_in_progress')
deploy_utils.set_async_step_flags(task.node, reboot=True,
skip_current_step=False)
@base.deploy_step(priority=0,
argsinfo=_RAID_APPLY_CONFIGURATION_ARGSINFO)
def apply_configuration(self, task, raid_config, create_root_volume=True,
create_nonroot_volumes=False):
return super(Ilo5RAID, self).apply_configuration(
task, raid_config, create_root_volume=create_root_volume,
create_nonroot_volumes=create_nonroot_volumes)
@METRICS.timer('Ilo5RAID.create_configuration')
@base.clean_step(priority=0, abortable=False, argsinfo={
'create_root_volume': {
'description': (
'This specifies whether to create the root volume. '
'Defaults to `True`.'
),
'required': False
},
'create_nonroot_volumes': {
'description': (
'This specifies whether to create the non-root volumes. '
'Defaults to `True`.'
),
'required': False
}
})
def create_configuration(self, task, create_root_volume=True,
create_nonroot_volumes=True):
"""Create a RAID configuration on a bare metal using agent ramdisk.
This method creates a RAID configuration on the given node.
:param task: a TaskManager instance.
:param create_root_volume: If True, a root volume is created
during RAID configuration. Otherwise, no root volume is
created. Default is True.
:param create_nonroot_volumes: If True, non-root volumes are
created. If False, no non-root volumes are created. Default
is True.
:raises: MissingParameterValue, if node.target_raid_config is missing
or was found to be empty after skipping root volume and/or non-root
volumes.
:raises: NodeCleaningFailure, on failure to execute clean step.
:raises: InstanceDeployFailure, on failure to execute deploy step.
"""
node = task.node
target_raid_config = raid.filter_target_raid_config(
node, create_root_volume=create_root_volume,
create_nonroot_volumes=create_nonroot_volumes)
node.set_driver_internal_info('target_raid_config',
target_raid_config)
node.save()
LOG.debug("Calling OOB RAID create_configuration for node %(node)s "
"with the following target RAID configuration: %(target)s",
{'node': node.uuid, 'target': target_raid_config})
ilo_object = ilo_common.get_ilo_object(node)
try:
# Raid configuration in progress, checking status
if not node.driver_internal_info.get(
'ilo_raid_create_in_progress'):
ilo_object.create_raid_configuration(target_raid_config)
self._prepare_for_read_raid(task, 'create_raid')
return deploy_utils.get_async_step_return_state(node)
else:
# Raid configuration is done, updating raid_config
raid_conf = (
ilo_object.read_raid_configuration(
raid_config=target_raid_config))
fields = ['ilo_raid_create_in_progress']
if node.clean_step:
fields.append('skip_current_clean_step')
else:
fields.append('skip_current_deploy_step')
self._pop_driver_internal_values(task, *fields)
if len(raid_conf['logical_disks']):
raid.update_raid_info(node, raid_conf)
LOG.debug("Node %(uuid)s raid create clean step is done.",
{'uuid': node.uuid})
else:
# Raid configuration failed
msg = (_("Step create_configuration failed "
"on node %(node)s with error: "
"Unable to create raid")
% {'node': node.uuid})
if node.clean_step:
raise exception.NodeCleaningFailure(msg)
else:
raise exception.InstanceDeployFailure(reason=msg)
except ilo_error.IloError as ilo_exception:
operation = (_("Failed to create raid configuration on node %s")
% node.uuid)
fields = ['ilo_raid_create_in_progress']
if node.clean_step:
fields.append('skip_current_clean_step')
else:
fields.append('skip_current_deploy_step')
self._pop_driver_internal_values(task, *fields)
self._set_step_failed(task, operation, ilo_exception)
@METRICS.timer('Ilo5RAID.delete_configuration')
@base.clean_step(priority=0, abortable=False)
@base.deploy_step(priority=0)
def delete_configuration(self, task):
"""Delete the RAID configuration.
:param task: a TaskManager instance containing the node to act on.
:raises: NodeCleaningFailure, on failure to execute clean step.
:raises: InstanceDeployFailure, on failure to execute deploy step.
"""
node = task.node
LOG.debug("OOB RAID delete_configuration invoked for node %s.",
node.uuid)
ilo_object = ilo_common.get_ilo_object(node)
try:
# Raid configuration in progress, checking status
if not node.driver_internal_info.get(
'ilo_raid_delete_in_progress'):
ilo_object.delete_raid_configuration()
self._prepare_for_read_raid(task, 'delete_raid')
return deploy_utils.get_async_step_return_state(node)
else:
# Raid configuration is done, updating raid_config
raid_conf = ilo_object.read_raid_configuration()
fields = ['ilo_raid_delete_in_progress']
if node.clean_step:
fields.append('skip_current_clean_step')
else:
fields.append('skip_current_deploy_step')
self._pop_driver_internal_values(task, *fields)
if not len(raid_conf['logical_disks']):
node.raid_config = {}
LOG.debug("Node %(uuid)s raid delete clean step is done.",
{'uuid': node.uuid})
else:
# Raid configuration failed
err_msg = (_("Step delete_configuration failed "
"on node %(node)s with error: "
"Unable to delete these logical disks: "
"%(disks)s")
% {'node': node.uuid,
'disks': raid_conf['logical_disks']})
if node.clean_step:
raise exception.NodeCleaningFailure(err_msg)
else:
raise exception.InstanceDeployFailure(reason=err_msg)
except ilo_error.IloLogicalDriveNotFoundError:
LOG.info("No logical drive found to delete on node %(node)s",
{'node': node.uuid})
except ilo_error.IloError as ilo_exception:
operation = (_("Failed to delete raid configuration on node %s")
% node.uuid)
self._pop_driver_internal_values(task,
'ilo_raid_delete_in_progress',
'skip_current_clean_step')
fields = ['ilo_raid_delete_in_progress']
if node.clean_step:
fields.append('skip_current_clean_step')
else:
fields.append('skip_current_deploy_step')
self._pop_driver_internal_values(task, *fields)
self._set_step_failed(task, operation, ilo_exception)
-135
View File
@@ -1,135 +0,0 @@
# Copyright 2022 Hewlett Packard Enterprise Development LP
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# 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.
"""
Vendor Interface for iLO drivers and its supporting methods.
"""
from ironic.common import exception
from ironic.common.i18n import _
from ironic.common import metrics_utils
from ironic.common import states
from ironic.conductor import task_manager
from ironic.conductor import utils as manager_utils
from ironic.drivers import base
from ironic.drivers.modules import deploy_utils
from ironic.drivers.modules.ilo import common as ilo_common
from ironic.drivers.modules.redfish import vendor as redfish_vendor
METRICS = metrics_utils.get_metrics_logger(__name__)
class VendorPassthru(redfish_vendor.RedfishVendorPassthru):
"""Vendor-specific interfaces for iLO deploy drivers."""
@METRICS.timer('IloVendorPassthru.validate')
def validate(self, task, method, **kwargs):
"""Validate vendor-specific actions.
Checks if a valid vendor passthru method was passed and validates
the parameters for the vendor passthru method.
:param task: a TaskManager instance containing the node to act on.
:param method: method to be validated.
:param kwargs: kwargs containing the vendor passthru method's
parameters.
:raises: MissingParameterValue, if some required parameters were not
passed.
:raises: InvalidParameterValue, if any of the parameters have invalid
value.
:raises: IloOperationNotSupported, if the driver does not support the
given operation with ilo vendor interface.
"""
if method == 'boot_into_iso':
self._validate_boot_into_iso(task, kwargs)
return
redfish_event_methods = ['create_subscription',
'delete_subscription',
'get_all_subscriptions', 'get_subscription']
if method in redfish_event_methods:
self._validate_is_it_a_supported_system(task)
ilo_common.parse_driver_info(task.node)
ilo_common.update_redfish_properties(task)
if method == 'eject_vmedia':
error_message = _(method + (
" can not be performed as the driver does not support "
"eject_vmedia through ilo vendor interface"))
raise exception.IloOperationNotSupported(operation=method,
error=error_message)
super(VendorPassthru, self).validate(task, method, **kwargs)
def _validate_boot_into_iso(self, task, kwargs):
"""Validates if attach_iso can be called and if inputs are proper."""
if not (task.node.provision_state == states.MANAGEABLE
or task.node.maintenance is True):
msg = (_("The requested action 'boot_into_iso' can be performed "
"only when node %(node_uuid)s is in %(state)s state or "
"in 'maintenance' mode") %
{'node_uuid': task.node.uuid,
'state': states.MANAGEABLE})
raise exception.InvalidStateRequested(msg)
boot_iso = kwargs.get('boot_iso_href')
d_info = {'boot_iso_href': boot_iso}
error_msg = _("Error validating input for boot_into_iso vendor "
"passthru. Some parameters were not provided: ")
deploy_utils.check_for_missing_params(d_info, error_msg)
# Validate that the image exists
deploy_utils.get_image_properties(task.context, boot_iso)
@METRICS.timer('IloVendorPassthru.boot_into_iso')
@base.passthru(['POST'],
description=_("Attaches an ISO image and reboots the node. "
"Required argument: 'boot_iso_href' - href "
"of the image to be booted. This can be a "
"Glance UUID or an HTTP(S) URL."))
@task_manager.require_exclusive_lock
def boot_into_iso(self, task, **kwargs):
"""Attaches an ISO image in glance and reboots bare metal.
This method accepts an ISO image href (a Glance UUID or an HTTP(S) URL)
attaches it as virtual media and then reboots the node. This is
useful for debugging purposes. This can be invoked only when the node
is in manage state.
:param task: A TaskManager object.
:param kwargs: The arguments sent with vendor passthru. The expected
kwargs are::
'boot_iso_href': href of the image to be booted. This can be
a Glance UUID or an HTTP(S) URL.
"""
ilo_common.setup_vmedia(task, kwargs['boot_iso_href'],
ramdisk_options=None)
manager_utils.node_power_action(task, states.REBOOT)
def _validate_is_it_a_supported_system(self, task):
"""Verify and raise an exception if it is not a supported system.
:param task: A TaskManager object.
:param kwargs: The arguments sent with vendor passthru.
:raises: IloOperationNotSupported, if the node is not a Gen10 or
Gen10 Plus system.
"""
node = task.node
ilo_object = ilo_common.get_ilo_object(node)
product_name = ilo_object.get_product_name()
operation = _("Event methods")
error_message = _(operation + (
" can not be performed as the driver does not support Event "
"methods on the given node"))
if 'Gen10' not in product_name:
raise exception.IloOperationNotSupported(operation=operation,
error=error_message)
+2 -19
View File
@@ -65,22 +65,6 @@ class ImageHandler(object):
"file_permission": CONF.redfish.file_permission,
"kernel_params": CONF.redfish.kernel_append_params
},
"ilo5": {
"swift_enabled": not CONF.ilo.use_web_server_for_images,
"container": CONF.ilo.swift_ilo_container,
"timeout": CONF.ilo.swift_object_expiry_timeout,
"image_subdir": "ilo",
"file_permission": CONF.ilo.file_permission,
"kernel_params": CONF.ilo.kernel_append_params
},
"ilo": {
"swift_enabled": not CONF.ilo.use_web_server_for_images,
"container": CONF.ilo.swift_ilo_container,
"timeout": CONF.ilo.swift_object_expiry_timeout,
"image_subdir": "ilo",
"file_permission": CONF.ilo.file_permission,
"kernel_params": CONF.ilo.kernel_append_params
},
}
if driver not in _SWIFT_MAP:
@@ -376,9 +360,8 @@ def prepare_remote_image(task, image_url, file_name='boot.iso',
"""
scheme = urlparse.urlparse(image_url).scheme.lower()
if scheme == 'swift':
# FIXME(dtantsur): iLO supports swift: scheme. In the long run we
# should support it for all boot interfaces by using temporary
# URLs. Until it's done, return image_url as it is.
# FIXME(dtantsur): support swift: scheme for all boot interfaces
# by using temporary URLs. Until it's done, return as-is.
return image_url
if (download_source == 'swift'
@@ -240,20 +240,6 @@ class TestLookup(test_api_base.BaseApiTest):
self.assertEqual(self.node.uuid, data['node']['uuid'])
self._check_config(data, skip_bmc_detect=True)
def test_bmc_detect_skip_for_ilo_variants(self):
"""Test BMC detection skip is enabled for iLO variants."""
for ilo_interface in ['ilo', 'ilo5', 'ilo6']:
self.node.management_interface = ilo_interface
self.node.save()
self._set_secret_mock(self.node, 'test-token')
data = self.get_json(
'/lookup?node_uuid=%s' % self.node.uuid,
headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(self.node.uuid, data['node']['uuid'])
self._check_config(data, skip_bmc_detect=True)
def test_bmc_detect_skip_for_idrac_redfish(self):
"""Test BMC detection skip is enabled for iDRAC Redfish."""
self.node.management_interface = 'idrac-redfish'
@@ -6862,21 +6862,6 @@ class ManagerTestProperties(mgr_utils.ServiceSetUpMixin, db_base.DbTestCase):
'ipmi_cipher_suite']
self._check_driver_properties("ipmi", expected)
def test_driver_properties_ilo(self):
self.config(enabled_hardware_types='ilo',
enabled_power_interfaces=['ilo'],
enabled_management_interfaces=['ilo'],
enabled_boot_interfaces=['ilo-virtual-media'],
enabled_inspect_interfaces=['ilo'],
enabled_console_interfaces=[])
expected = ['ilo_address', 'ilo_username',
'ilo_password', 'client_port', 'client_timeout',
'deploy_iso', 'ilo_change_password',
'ca_file', 'snmp_auth_user', 'snmp_auth_prot_password',
'snmp_auth_priv_password', 'snmp_auth_protocol',
'snmp_auth_priv_protocol', 'ilo_verify_ca']
self._check_driver_properties("ilo", expected, pxe_common=False)
def test_driver_properties_manual_management(self):
self.config(enabled_hardware_types=['manual-management'])
self._check_driver_properties('manual-management', [])
-8
View File
@@ -81,14 +81,6 @@ def get_test_pxe_instance_info():
}
def get_test_ilo_info():
return {
"ilo_address": "1.2.3.4",
"ilo_username": "admin",
"ilo_password": "fake",
}
def get_test_drac_info():
return {
"redfish_address": "1.2.3.4",
@@ -1,715 +0,0 @@
# Copyright 2018 Hewlett-Packard Development Company, L.P.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""Test class for IloPower module."""
from unittest import mock
from oslo_config import cfg
from oslo_utils import importutils
from ironic.common import exception
from ironic.conductor import task_manager
from ironic.conductor import utils as manager_utils
from ironic.drivers.modules import deploy_utils
from ironic.drivers.modules.ilo import bios as ilo_bios
from ironic.drivers.modules.ilo import boot as ilo_boot
from ironic.drivers.modules.ilo import common as ilo_common
from ironic import objects
from ironic.tests.unit.db import utils as db_utils
from ironic.tests.unit.drivers.modules.ilo import test_common
ilo_error = importutils.try_import('proliantutils.exception')
INFO_DICT = db_utils.get_test_ilo_info()
CONF = cfg.CONF
class IloBiosTestCase(test_common.BaseIloTest):
def test_get_properties(self):
expected = ilo_common.REQUIRED_PROPERTIES
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
self.assertEqual(expected, task.driver.bios.get_properties())
@mock.patch.object(ilo_common, 'parse_driver_info', spec_set=True,
autospec=True)
def test_validate(self, mock_drvinfo):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
task.driver.bios.validate(task)
mock_drvinfo.assert_called_once_with(task.node)
def _test_ilo_error(self, exc_cls,
test_methods_not_called,
test_methods_called,
method_details, exception_mock,
operation='cleaning'):
exception_mock.side_effect = exc_cls('error')
method = method_details.get("name")
args = method_details.get("args")
if self.node.clean_step:
self.assertRaises(exception.NodeCleaningFailure,
method,
*args)
else:
self.assertRaises(exception.InstanceDeployFailure,
method,
*args)
for test_method in test_methods_not_called:
test_method.assert_not_called()
for called_method in test_methods_called:
called_method["name"].assert_called_once_with(
*called_method["args"])
@mock.patch.object(ilo_bios.IloBIOS, 'cache_bios_settings',
autospec=True)
@mock.patch.object(ilo_bios.IloBIOS, '_execute_post_boot_bios_step',
autospec=True)
@mock.patch.object(ilo_bios.IloBIOS, '_execute_pre_boot_bios_step',
autospec=True)
def test_apply_configuration_pre_boot(self, exe_pre_boot_mock,
exe_post_boot_mock,
cache_settings_mock):
settings = [
{
"name": "SET_A", "value": "VAL_A",
},
{
"name": "SET_B", "value": "VAL_B",
},
{
"name": "SET_C", "value": "VAL_C",
},
{
"name": "SET_D", "value": "VAL_D",
}
]
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
driver_internal_info = task.node.driver_internal_info
driver_internal_info.pop('apply_bios', None)
task.node.driver_internal_info = driver_internal_info
task.node.save()
actual_settings = {'SET_A': 'VAL_A', 'SET_B': 'VAL_B',
'SET_C': 'VAL_C', 'SET_D': 'VAL_D'}
task.driver.bios.apply_configuration(task, settings)
exe_pre_boot_mock.assert_called_once_with(
task.driver.bios, task, 'apply_configuration', actual_settings)
self.assertFalse(exe_post_boot_mock.called)
cache_settings_mock.assert_called_once_with(task.driver.bios, task)
@mock.patch.object(ilo_bios.IloBIOS, 'cache_bios_settings',
autospec=True)
@mock.patch.object(ilo_bios.IloBIOS, '_execute_post_boot_bios_step',
autospec=True)
@mock.patch.object(ilo_bios.IloBIOS, '_execute_pre_boot_bios_step',
autospec=True)
def test_apply_configuration_post_boot(self, exe_pre_boot_mock,
exe_post_boot_mock,
cache_settings_mock):
settings = [
{
"name": "SET_A", "value": "VAL_A",
},
{
"name": "SET_B", "value": "VAL_B",
},
{
"name": "SET_C", "value": "VAL_C",
},
{
"name": "SET_D", "value": "VAL_D",
}
]
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
driver_internal_info = task.node.driver_internal_info
driver_internal_info['apply_bios'] = True
task.node.driver_internal_info = driver_internal_info
task.node.save()
task.driver.bios.apply_configuration(task, settings)
exe_post_boot_mock.assert_called_once_with(
task.driver.bios, task, 'apply_configuration')
self.assertFalse(exe_pre_boot_mock.called)
cache_settings_mock.assert_called_once_with(task.driver.bios, task)
@mock.patch.object(ilo_boot.IloVirtualMediaBoot, 'prepare_ramdisk',
spec_set=True, autospec=True)
@mock.patch.object(manager_utils, 'node_power_action', spec_set=True,
autospec=True)
@mock.patch.object(deploy_utils, 'build_agent_options', spec_set=True,
autospec=True)
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
autospec=True)
def test__execute_pre_boot_bios_step_apply_configuration(
self, get_ilo_object_mock, build_agent_mock,
node_power_mock, prepare_mock):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
ilo_object_mock = get_ilo_object_mock.return_value
data = {
"SET_A": "VAL_A",
"SET_B": "VAL_B",
"SET_C": "VAL_C",
"SET_D": "VAL_D"
}
step = 'apply_configuration'
task.node.deploy_step = {
'step': 'apply_configuration',
'interface': 'bios'}
task.driver.bios._execute_pre_boot_bios_step(task, step, data)
driver_info = task.node.driver_internal_info
self.assertTrue(
all(x in driver_info for x in (
'apply_bios', 'deployment_reboot',
'skip_current_deploy_step')))
ilo_object_mock.set_bios_settings.assert_called_once_with(data)
self.assertFalse(ilo_object_mock.reset_bios_to_default.called)
build_agent_mock.assert_called_once_with(task.node)
self.assertTrue(prepare_mock.called)
self.assertTrue(node_power_mock.called)
@mock.patch.object(ilo_boot.IloVirtualMediaBoot, 'prepare_ramdisk',
spec_set=True, autospec=True)
@mock.patch.object(manager_utils, 'node_power_action', spec_set=True,
autospec=True)
@mock.patch.object(deploy_utils, 'build_agent_options', spec_set=True,
autospec=True)
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
autospec=True)
def _test__execute_pre_boot_bios_step(
self, get_ilo_mock, build_agent_mock,
node_power_mock, prepare_mock):
if self.node.clean_step:
step_data = self.node.clean_step
check_fields = ['cleaning_reboot', 'skip_current_clean_step']
else:
step_data = self.node.deploy_step
check_fields = ['deployment_reboot', 'skip_current_deploy_step']
data = step_data['argsinfo'].get('settings', None)
step = step_data['step']
if step == 'factory_reset':
check_fields.append('reset_bios')
elif step == 'apply_configuration':
check_fields.append('apply_bios')
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
ilo_mock = get_ilo_mock.return_value
task.driver.bios._execute_pre_boot_bios_step(task, step, data)
drv_internal_info = task.node.driver_internal_info
self.assertTrue(
all(x in drv_internal_info for x in check_fields))
if step == 'factory_reset':
ilo_mock.reset_bios_to_default.assert_called_once_with()
elif step == 'apply_configuration':
ilo_mock.set_bios_settings.assert_called_once_with(data)
build_agent_mock.assert_called_once_with(task.node)
self.assertTrue(prepare_mock.called)
self.assertTrue(node_power_mock.called)
def test__execute_pre_boot_bios_step_apply_conf_cleaning(self):
data = {"SET_A": "VAL_A",
"SET_B": "VAL_B",
"SET_C": "VAL_C",
"SET_D": "VAL_D"}
self.node.clean_step = {'priority': 100, 'interface': 'bios',
'step': 'apply_configuration',
'argsinfo': {'settings': data}}
self.node.save()
self._test__execute_pre_boot_bios_step()
def test__execute_pre_boot_bios_step_apply_conf_deploying(self):
data = {"SET_A": "VAL_A",
"SET_B": "VAL_B",
"SET_C": "VAL_C",
"SET_D": "VAL_D"}
self.node.deploy_step = {'priority': 100, 'interface': 'bios',
'step': 'apply_configuration',
'argsinfo': {'settings': data}}
self.node.save()
self._test__execute_pre_boot_bios_step()
def test__execute_pre_boot_bios_step_factory_reset_cleaning(self):
self.node.clean_step = {'priority': 100, 'interface': 'bios',
'step': 'factory_reset', 'argsinfo': {}}
self.node.save()
self._test__execute_pre_boot_bios_step()
def test__execute_pre_boot_bios_step_factory_reset_deploying(self):
self.node.deploy_step = {'priority': 100, 'interface': 'bios',
'step': 'factory_reset', 'argsinfo': {}}
self.node.save()
self._test__execute_pre_boot_bios_step()
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
autospec=True)
def _test__execute_pre_boot_bios_step_invalid(
self, get_ilo_object_mock):
if self.node.clean_step:
step_data = self.node.clean_step
exept = exception.NodeCleaningFailure
else:
step_data = self.node.deploy_step
exept = exception.InstanceDeployFailure
data = step_data['argsinfo'].get('settings', None)
step = step_data['step']
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
ilo_object_mock = get_ilo_object_mock.return_value
ilo_object_mock.set_bios_settings.side_effect = ilo_error.IloError(
'err')
if task.node.clean_step:
exept = exception.NodeCleaningFailure
else:
exept = exception.InstanceDeployFailure
self.assertRaises(exept,
task.driver.bios._execute_pre_boot_bios_step,
task, step, data)
def test__execute_pre_boot_bios_step_invalid_cleaning(self):
data = {"SET_A": "VAL_A",
"SET_B": "VAL_B",
"SET_C": "VAL_C",
"SET_D": "VAL_D"}
self.node.clean_step = {'priority': 100, 'interface': 'bios',
'step': 'invalid_step',
'argsinfo': {'settings': data}}
self.node.save()
self._test__execute_pre_boot_bios_step_invalid()
def test__execute_pre_boot_bios_step_invalid_deploying(self):
data = {"SET_A": "VAL_A",
"SET_B": "VAL_B",
"SET_C": "VAL_C",
"SET_D": "VAL_D"}
self.node.deploy_step = {'priority': 100, 'interface': 'bios',
'step': 'invalid_step',
'argsinfo': {'settings': data}}
self.node.save()
self._test__execute_pre_boot_bios_step_invalid()
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
def _test__execute_pre_boot_bios_step_ilo_fail(self, get_ilo_mock):
if self.node.clean_step:
step_data = self.node.clean_step
exept = exception.NodeCleaningFailure
else:
step_data = self.node.deploy_step
exept = exception.InstanceDeployFailure
data = step_data['argsinfo'].get('settings', None)
step = step_data['step']
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
get_ilo_mock.side_effect = exception.MissingParameterValue('err')
self.assertRaises(exept,
task.driver.bios._execute_pre_boot_bios_step,
task, step, data)
def test__execute_pre_boot_bios_step_iloobj_failed_cleaning(self):
data = {"SET_A": "VAL_A",
"SET_B": "VAL_B",
"SET_C": "VAL_C",
"SET_D": "VAL_D"}
self.node.clean_step = {'priority': 100, 'interface': 'bios',
'step': 'apply_configuration',
'argsinfo': {'settings': data}}
self.node.save()
self._test__execute_pre_boot_bios_step_ilo_fail()
def test__execute_pre_boot_bios_step_iloobj_failed_deploying(self):
data = {"SET_A": "VAL_A",
"SET_B": "VAL_B",
"SET_C": "VAL_C",
"SET_D": "VAL_D"}
self.node.deploy_step = {'priority': 100, 'interface': 'bios',
'step': 'apply_configuration',
'argsinfo': {'settings': data}}
self.node.save()
self._test__execute_pre_boot_bios_step_ilo_fail()
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
autospec=True)
def _test__execute_pre_boot_bios_step_set_bios_failed(
self, get_ilo_object_mock):
if self.node.clean_step:
step_data = self.node.clean_step
exept = exception.NodeCleaningFailure
else:
step_data = self.node.deploy_step
exept = exception.InstanceDeployFailure
data = step_data['argsinfo'].get('settings', None)
step = step_data['step']
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
ilo_object_mock = get_ilo_object_mock.return_value
ilo_object_mock.set_bios_settings.side_effect = ilo_error.IloError(
'err')
if task.node.clean_step:
exept = exception.NodeCleaningFailure
else:
exept = exception.InstanceDeployFailure
self.assertRaises(exept,
task.driver.bios._execute_pre_boot_bios_step,
task, step, data)
def test__execute_pre_boot_bios_step_set_bios_failed_cleaning(self):
data = {"SET_A": "VAL_A",
"SET_B": "VAL_B",
"SET_C": "VAL_C",
"SET_D": "VAL_D"}
self.node.clean_step = {'priority': 100, 'interface': 'bios',
'step': 'apply_configuration',
'argsinfo': {'settings': data}}
self.node.save()
self._test__execute_post_boot_bios_get_settings_failed()
def test__execute_pre_boot_bios_step_set_bios_failed_deploying(self):
data = {"SET_A": "VAL_A",
"SET_B": "VAL_B",
"SET_C": "VAL_C",
"SET_D": "VAL_D"}
self.node.deploy_step = {'priority': 100, 'interface': 'bios',
'step': 'apply_configuration',
'argsinfo': {'settings': data}}
self.node.save()
self._test__execute_post_boot_bios_get_settings_failed()
def test__execute_pre_boot_bios_step_reset_bios_failed_cleaning(self):
self.node.clean_step = {'priority': 100, 'interface': 'bios',
'step': 'factory_reset', 'argsinfo': {}}
self.node.save()
self._test__execute_post_boot_bios_get_settings_failed()
def test__execute_pre_boot_bios_step_reset_bios_failed_deploying(self):
self.node.deploy_step = {'priority': 100, 'interface': 'bios',
'step': 'factory_reset', 'argsinfo': {}}
self.node.save()
self._test__execute_post_boot_bios_get_settings_failed()
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
autospec=True)
def test__execute_post_boot_bios_step_apply_configuration(
self, get_ilo_object_mock):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
driver_info = task.node.driver_internal_info
driver_info.update({'apply_bios': True})
task.node.driver_internal_info = driver_info
task.node.save()
ilo_object_mock = get_ilo_object_mock.return_value
step = 'apply_configuration'
task.driver.bios._execute_post_boot_bios_step(task, step)
driver_info = task.node.driver_internal_info
self.assertNotIn('apply_bios', driver_info)
ilo_object_mock.get_bios_settings_result.assert_called_once_with()
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
autospec=True)
def test__execute_post_boot_bios_step_factory_reset(
self, get_ilo_object_mock):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
driver_info = task.node.driver_internal_info
driver_info.update({'reset_bios': True})
task.node.driver_internal_info = driver_info
task.node.save()
ilo_object_mock = get_ilo_object_mock.return_value
step = 'factory_reset'
task.driver.bios._execute_post_boot_bios_step(task, step)
driver_info = task.node.driver_internal_info
self.assertNotIn('reset_bios', driver_info)
ilo_object_mock.get_bios_settings_result.assert_called_once_with()
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
autospec=True)
def _test__execute_post_boot_bios_step_invalid(
self, get_ilo_object_mock):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
driver_info = task.node.driver_internal_info
driver_info.update({'apply_bios': True})
task.node.driver_internal_info = driver_info
task.node.save()
step = 'invalid_step'
if self.node.clean_step:
exept = exception.NodeCleaningFailure
else:
exept = exception.InstanceDeployFailure
self.assertRaises(exept,
task.driver.bios._execute_post_boot_bios_step,
task, step)
self.assertNotIn('apply_bios', task.node.driver_internal_info)
def test__execute_post_boot_bios_step_invalid_cleaning(self):
self.node.clean_step = {'priority': 100, 'interface': 'bios',
'step': u'apply_configuration',
'argsinfo': {'settings': {'a': 1, 'b': 2}}}
self.node.save()
self._test__execute_post_boot_bios_step_invalid()
def test__execute_post_boot_bios_step_invalid_deploy(self):
self.node.deploy_step = {'priority': 100, 'interface': 'bios',
'step': u'apply_configuration',
'argsinfo': {'settings': {'a': 1, 'b': 2}}}
self.node.save()
self._test__execute_post_boot_bios_step_invalid()
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
autospec=True)
def _test__execute_post_boot_bios_step_iloobj_failed(
self, get_ilo_object_mock):
if self.node.clean_step:
step = self.node.clean_step['step']
exept = exception.NodeCleaningFailure
if self.node.deploy_step:
step = self.node.deploy_step['step']
exept = exception.InstanceDeployFailure
driver_internal_info = self.node.driver_internal_info
driver_internal_info['apply_bios'] = True
self.node.driver_internal_info = driver_internal_info
self.node.save()
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
get_ilo_object_mock.side_effect = exception.MissingParameterValue(
'err')
step = 'apply_configuration'
self.assertRaises(exept,
task.driver.bios._execute_post_boot_bios_step,
task, step)
self.assertNotIn('apply_bios', task.node.driver_internal_info)
def test__execute_post_boot_bios_step_iloobj_failed_cleaning(self):
self.node.clean_step = {'priority': 100, 'interface': 'bios',
'step': u'apply_configuration',
'argsinfo': {'settings': {'a': 1, 'b': 2}}}
self.node.save()
self._test__execute_post_boot_bios_step_iloobj_failed()
def test__execute_post_boot_bios_step_iloobj_failed_deploy(self):
self.node.deploy_step = {'priority': 100, 'interface': 'bios',
'step': u'apply_configuration',
'argsinfo': {'settings': {'a': 1, 'b': 2}}}
self.node.save()
self._test__execute_post_boot_bios_step_iloobj_failed()
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
autospec=True)
def _test__execute_post_boot_bios_get_settings_error(
self, get_ilo_object_mock):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
driver_info = task.node.driver_internal_info
driver_info.update({'apply_bios': True})
task.node.driver_internal_info = driver_info
task.node.save()
ilo_object_mock = get_ilo_object_mock.return_value
step = 'apply_configuration'
mdobj = {
"name": task.driver.bios._execute_post_boot_bios_step,
"args": (task, step,)
}
self._test_ilo_error(ilo_error.IloCommandNotSupportedError,
[],
[], mdobj,
ilo_object_mock.get_bios_settings_result)
self.assertNotIn('apply_bios', task.node.driver_internal_info)
def test__execute_post_boot_bios_get_settings_error_cleaning(
self):
self.node.clean_step = {'priority': 100, 'interface': 'bios',
'step': u'apply_configuration',
'argsinfo': {'settings': {'a': 1, 'b': 2}}}
self.node.save()
self._test__execute_post_boot_bios_get_settings_error()
def test__execute_post_boot_bios_get_settings_error_deploying(
self):
self.node.deploy_step = {'priority': 100, 'interface': 'bios',
'step': 'apply_configuration',
'argsinfo': {'settings': {'a': 1, 'b': 2}}}
self.node.save()
self._test__execute_post_boot_bios_get_settings_error()
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
autospec=True)
def _test__execute_post_boot_bios_get_settings_failed(
self, get_ilo_object_mock):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
driver_info = task.node.driver_internal_info
driver_info.update({'reset_bios': True})
task.node.driver_internal_info = driver_info
task.node.save()
ilo_object_mock = get_ilo_object_mock.return_value
ilo_object_mock.get_bios_settings_result.return_value = (
{'status': 'failed', 'message': 'Some data'})
step = 'factory_reset'
if task.node.clean_step:
exept = exception.NodeCleaningFailure
else:
exept = exception.InstanceDeployFailure
self.assertRaises(exept,
task.driver.bios._execute_post_boot_bios_step,
task, step)
self.assertNotIn('reset_bios', task.node.driver_internal_info)
def test__execute_post_boot_bios_get_settings_failed_cleaning(
self):
self.node.clean_step = {'priority': 100, 'interface': 'bios',
'step': 'factory_reset', 'argsinfo': {}}
self.node.save()
self._test__execute_post_boot_bios_get_settings_failed()
def test__execute_post_boot_bios_get_settings_failed_deploying(
self):
self.node.depoy_step = {'priority': 100, 'interface': 'bios',
'step': 'factory_reset', 'argsinfo': {}}
self.node.save()
self._test__execute_post_boot_bios_get_settings_failed()
@mock.patch.object(objects.BIOSSettingList, 'create', autospec=True)
@mock.patch.object(objects.BIOSSettingList, 'save', autospec=True)
@mock.patch.object(objects.BIOSSettingList, 'delete', autospec=True)
@mock.patch.object(objects.BIOSSettingList, 'sync_node_setting',
autospec=True)
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
def test_cache_bios_settings(self, get_ilo_object_mock, sync_node_mock,
delete_mock, save_mock, create_mock):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
ilo_object_mock = get_ilo_object_mock.return_value
settings = {
"SET_A": True,
"SET_B": True,
"SET_C": True,
"SET_D": True
}
ilo_object_mock.get_current_bios_settings.return_value = settings
expected_bios_settings = [
{"name": "SET_A", "value": True},
{"name": "SET_B", "value": True},
{"name": "SET_C", "value": True},
{"name": "SET_D", "value": True}
]
sync_node_mock.return_value = ([], [], [], [])
all_settings = (
[
{"name": "C_1", "value": "C_1_VAL"},
{"name": "C_2", "value": "C_2_VAL"}
],
[
{"name": "U_1", "value": "U_1_VAL"},
{"name": "U_2", "value": "U_2_VAL"}
],
[
{"name": "D_1", "value": "D_1_VAL"},
{"name": "D_2", "value": "D_2_VAL"}
],
[]
)
sync_node_mock.return_value = all_settings
task.driver.bios.cache_bios_settings(task)
ilo_object_mock.get_current_bios_settings.assert_called_once_with()
actual_arg = sorted(sync_node_mock.call_args[0][2],
key=lambda x: x.get("name"))
expected_arg = sorted(expected_bios_settings,
key=lambda x: x.get("name"))
self.assertEqual(actual_arg, expected_arg)
create_mock.assert_called_once_with(
self.context, task.node.id, all_settings[0])
save_mock.assert_called_once_with(
self.context, task.node.id, all_settings[1])
del_names = [setting.get("name") for setting in all_settings[2]]
delete_mock.assert_called_once_with(
self.context, task.node.id, del_names)
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
def test_cache_bios_settings_missing_parameter(self, get_ilo_object_mock):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
mdobj = {
"name": task.driver.bios.cache_bios_settings,
"args": (task,)
}
self._test_ilo_error(exception.MissingParameterValue,
[],
[], mdobj, get_ilo_object_mock)
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
def test_cache_bios_settings_invalid_parameter(self, get_ilo_object_mock):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
mdobj = {
"name": task.driver.bios.cache_bios_settings,
"args": (task,)
}
self._test_ilo_error(exception.InvalidParameterValue,
[],
[], mdobj, get_ilo_object_mock)
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
def test_cache_bios_settings_with_ilo_error(self, get_ilo_object_mock):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
ilo_object_mock = get_ilo_object_mock.return_value
mdobj = {
"name": task.driver.bios.cache_bios_settings,
"args": (task,)
}
self._test_ilo_error(ilo_error.IloError,
[],
[],
mdobj,
ilo_object_mock.get_current_bios_settings)
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
def test_cache_bios_settings_with_unknown_error(self, get_ilo_object_mock):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
ilo_object_mock = get_ilo_object_mock.return_value
mdobj = {
"name": task.driver.bios.cache_bios_settings,
"args": (task,)
}
self._test_ilo_error(ilo_error.IloCommandNotSupportedError,
[],
[],
mdobj,
ilo_object_mock.get_current_bios_settings)
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,646 +0,0 @@
# Copyright 2016 Hewlett Packard Enterprise Development Company LP
#
# 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 Firmware Processor used by iLO management interface."""
import builtins
import io
from unittest import mock
from urllib import parse as urlparse
from oslo_utils import importutils
import proliantutils
from ironic.common import exception
from ironic.drivers.modules.ilo import common as ilo_common
from ironic.drivers.modules.ilo import firmware_processor as ilo_fw_processor
from ironic.tests import base
ilo_error = importutils.try_import('proliantutils.exception')
class FirmwareProcessorTestCase(base.TestCase):
def setUp(self):
super(FirmwareProcessorTestCase, self).setUp()
self.any_url = 'http://netloc/path'
self.fw_processor_fake = mock.MagicMock(
parsed_url='set it as required')
def test_verify_firmware_update_args_throws_for_invalid_update_mode(self):
# | GIVEN |
update_firmware_mock = mock.MagicMock()
firmware_update_args = {'firmware_update_mode': 'invalid_mode',
'firmware_images': None}
# Note(deray): Need to set __name__ attribute explicitly to keep
# ``functools.wraps`` happy. Passing this to the `name` argument at
# the time creation of Mock doesn't help.
update_firmware_mock.__name__ = 'update_firmware_mock'
wrapped_func = (ilo_fw_processor.
verify_firmware_update_args(update_firmware_mock))
node_fake = mock.MagicMock(uuid='fake_node_uuid')
task_fake = mock.MagicMock(node=node_fake)
# | WHEN & THEN |
self.assertRaises(exception.InvalidParameterValue,
wrapped_func,
mock.ANY,
task_fake,
**firmware_update_args)
def test_verify_firmware_update_args_throws_for_no_firmware_url(self):
# | GIVEN |
update_firmware_mock = mock.MagicMock()
firmware_update_args = {'firmware_update_mode': 'ilo',
'firmware_images': []}
update_firmware_mock.__name__ = 'update_firmware_mock'
wrapped_func = (ilo_fw_processor.
verify_firmware_update_args(update_firmware_mock))
# | WHEN & THEN |
self.assertRaises(exception.InvalidParameterValue,
wrapped_func,
mock.ANY,
mock.ANY,
**firmware_update_args)
def test_get_and_validate_firmware_image_info(self):
# | GIVEN |
firmware_image_info = {
'url': self.any_url,
'checksum': 'b64c8f7799cfbb553d384d34dc43fafe336cc889',
'component': 'BIOS'
}
# | WHEN |
url, checksum, component = (
ilo_fw_processor.get_and_validate_firmware_image_info(
firmware_image_info, 'ilo'))
# | THEN |
self.assertEqual(self.any_url, url)
self.assertEqual('b64c8f7799cfbb553d384d34dc43fafe336cc889', checksum)
self.assertEqual('bios', component)
def test_get_and_validate_firmware_image_info_fails_for_missing_parameter(
self):
# | GIVEN |
invalid_firmware_image_info = {
'url': self.any_url,
'component': 'bios'
}
# | WHEN | & | THEN |
self.assertRaisesRegex(
exception.MissingParameterValue, 'checksum',
ilo_fw_processor.get_and_validate_firmware_image_info,
invalid_firmware_image_info, 'ilo')
def test_get_and_validate_firmware_image_info_fails_for_empty_parameter(
self):
# | GIVEN |
invalid_firmware_image_info = {
'url': self.any_url,
'checksum': 'valid_checksum',
'component': ''
}
# | WHEN | & | THEN |
self.assertRaisesRegex(
exception.MissingParameterValue, 'component',
ilo_fw_processor.get_and_validate_firmware_image_info,
invalid_firmware_image_info, 'ilo')
def test_get_and_validate_firmware_image_info_fails_for_invalid_component(
self):
# | GIVEN |
invalid_firmware_image_info = {
'url': self.any_url,
'checksum': 'valid_checksum',
'component': 'INVALID'
}
# | WHEN | & | THEN |
self.assertRaises(
exception.InvalidParameterValue,
ilo_fw_processor.get_and_validate_firmware_image_info,
invalid_firmware_image_info, 'ilo')
def test_get_and_validate_firmware_image_info_sum(self):
# | GIVEN |
result = None
firmware_image_info = {
'url': self.any_url,
'checksum': 'b64c8f7799cfbb553d384d34dc43fafe336cc889'
}
# | WHEN | & | THEN |
ret_val = ilo_fw_processor.get_and_validate_firmware_image_info(
firmware_image_info, 'sum')
self.assertEqual(result, ret_val)
def test_get_and_validate_firmware_image_info_sum_with_component(self):
# | GIVEN |
result = None
firmware_image_info = {
'url': self.any_url,
'checksum': 'b64c8f7799cfbb553d384d34dc43fafe336cc889',
'components': ['CP02345.exe']
}
# | WHEN | & | THEN |
ret_val = ilo_fw_processor.get_and_validate_firmware_image_info(
firmware_image_info, 'sum')
self.assertEqual(result, ret_val)
def test_get_and_validate_firmware_image_info_sum_invalid_component(
self):
# | GIVEN |
invalid_firmware_image_info = {
'url': 'any_url',
'checksum': 'valid_checksum',
'components': 'INVALID'
}
# | WHEN | & | THEN |
self.assertRaises(
exception.InvalidParameterValue,
ilo_fw_processor.get_and_validate_firmware_image_info,
invalid_firmware_image_info, 'sum')
def test__validate_sum_components(self):
result = None
components = ['CP02345.scexe', 'CP02678.exe']
ret_val = ilo_fw_processor._validate_sum_components(components)
self.assertEqual(ret_val, result)
@mock.patch.object(ilo_fw_processor, 'LOG', autospec=True)
def test__validate_sum_components_fails(self, LOG_mock):
components = ['INVALID']
self.assertRaises(
exception.InvalidParameterValue,
ilo_fw_processor._validate_sum_components, components)
self.assertTrue(LOG_mock.error.called)
def test_fw_processor_ctor_sets_parsed_url_attrib_of_fw_processor(self):
# | WHEN |
fw_processor = ilo_fw_processor.FirmwareProcessor(self.any_url)
# | THEN |
self.assertEqual(self.any_url, fw_processor.parsed_url.geturl())
@mock.patch.object(
ilo_fw_processor, '_download_file_based_fw_to', autospec=True)
def test__download_file_based_fw_to_gets_invoked_for_file_based_firmware(
self, _download_file_based_fw_to_mock):
# | GIVEN |
some_file_url = 'file:///some_location/some_firmware_file'
# | WHEN |
fw_processor = ilo_fw_processor.FirmwareProcessor(some_file_url)
fw_processor._download_fw_to('some_target_file')
# | THEN |
_download_file_based_fw_to_mock.assert_called_once_with(
fw_processor, 'some_target_file')
@mock.patch.object(
ilo_fw_processor, '_download_http_based_fw_to', autospec=True)
def test__download_http_based_fw_to_gets_invoked_for_http_based_firmware(
self, _download_http_based_fw_to_mock):
# | GIVEN |
for some_http_url in ('http://netloc/path_to_firmware_file',
'https://netloc/path_to_firmware_file'):
# | WHEN |
fw_processor = ilo_fw_processor.FirmwareProcessor(some_http_url)
fw_processor._download_fw_to('some_target_file')
# | THEN |
_download_http_based_fw_to_mock.assert_called_once_with(
fw_processor, 'some_target_file')
_download_http_based_fw_to_mock.reset_mock()
@mock.patch.object(
ilo_fw_processor, '_download_swift_based_fw_to', autospec=True)
def test__download_swift_based_fw_to_gets_invoked_for_swift_based_firmware(
self, _download_swift_based_fw_to_mock):
# | GIVEN |
some_swift_url = 'swift://containername/objectname'
# | WHEN |
fw_processor = ilo_fw_processor.FirmwareProcessor(some_swift_url)
fw_processor._download_fw_to('some_target_file')
# | THEN |
_download_swift_based_fw_to_mock.assert_called_once_with(
fw_processor, 'some_target_file')
def test_fw_processor_ctor_throws_exception_with_invalid_firmware_url(
self):
# | GIVEN |
any_invalid_firmware_url = 'any_invalid_url'
# | WHEN | & | THEN |
self.assertRaises(exception.InvalidParameterValue,
ilo_fw_processor.FirmwareProcessor,
any_invalid_firmware_url)
@mock.patch.object(ilo_fw_processor, 'tempfile', autospec=True)
@mock.patch.object(ilo_fw_processor, 'os', autospec=True)
@mock.patch.object(ilo_fw_processor, 'shutil', autospec=True)
@mock.patch.object(ilo_common, 'verify_image_checksum',
spec_set=True, autospec=True)
@mock.patch.object(
ilo_fw_processor, '_extract_fw_from_file', autospec=True)
def test_process_fw_on_calls__download_fw_to(
self, _extract_fw_from_file_mock, verify_checksum_mock,
shutil_mock, os_mock, tempfile_mock):
# | GIVEN |
fw_processor = ilo_fw_processor.FirmwareProcessor(self.any_url)
# Now mock the __download_fw_to method of fw_processor instance
_download_fw_to_mock = mock.MagicMock()
fw_processor._download_fw_to = _download_fw_to_mock
expected_return_location = (ilo_fw_processor.FirmwareImageLocation(
'some_location/file', 'file'))
_extract_fw_from_file_mock.return_value = (expected_return_location,
True)
node_mock = mock.ANY
checksum_fake = mock.ANY
# | WHEN |
actual_return_location = fw_processor.process_fw_on(node_mock,
checksum_fake)
# | THEN |
_download_fw_to_mock.assert_called_once_with(
os_mock.path.join.return_value)
self.assertEqual(expected_return_location.fw_image_location,
actual_return_location.fw_image_location)
self.assertEqual(expected_return_location.fw_image_filename,
actual_return_location.fw_image_filename)
@mock.patch.object(ilo_fw_processor, 'tempfile', autospec=True)
@mock.patch.object(ilo_fw_processor, 'os', autospec=True)
@mock.patch.object(ilo_fw_processor, 'shutil', autospec=True)
@mock.patch.object(ilo_common, 'verify_image_checksum',
spec_set=True, autospec=True)
@mock.patch.object(
ilo_fw_processor, '_extract_fw_from_file', autospec=True)
def test_process_fw_on_verifies_checksum_of_downloaded_fw_file(
self, _extract_fw_from_file_mock, verify_checksum_mock,
shutil_mock, os_mock, tempfile_mock):
# | GIVEN |
fw_processor = ilo_fw_processor.FirmwareProcessor(self.any_url)
# Now mock the __download_fw_to method of fw_processor instance
_download_fw_to_mock = mock.MagicMock()
fw_processor._download_fw_to = _download_fw_to_mock
expected_return_location = (ilo_fw_processor.FirmwareImageLocation(
'some_location/file', 'file'))
_extract_fw_from_file_mock.return_value = (expected_return_location,
True)
node_mock = mock.ANY
checksum_fake = mock.ANY
# | WHEN |
actual_return_location = fw_processor.process_fw_on(node_mock,
checksum_fake)
# | THEN |
_download_fw_to_mock.assert_called_once_with(
os_mock.path.join.return_value)
verify_checksum_mock.assert_called_once_with(
os_mock.path.join.return_value, checksum_fake)
self.assertEqual(expected_return_location.fw_image_location,
actual_return_location.fw_image_location)
self.assertEqual(expected_return_location.fw_image_filename,
actual_return_location.fw_image_filename)
@mock.patch.object(ilo_fw_processor, 'tempfile', autospec=True)
@mock.patch.object(ilo_fw_processor, 'os', autospec=True)
@mock.patch.object(ilo_fw_processor, 'shutil', autospec=True)
@mock.patch.object(ilo_common, 'verify_image_checksum',
spec_set=True, autospec=True)
def test_process_fw_on_throws_error_if_checksum_validation_fails(
self, verify_checksum_mock, shutil_mock, os_mock, tempfile_mock):
# | GIVEN |
fw_processor = ilo_fw_processor.FirmwareProcessor(self.any_url)
# Now mock the __download_fw_to method of fw_processor instance
_download_fw_to_mock = mock.MagicMock()
fw_processor._download_fw_to = _download_fw_to_mock
verify_checksum_mock.side_effect = exception.ImageRefValidationFailed(
image_href='some image',
reason='checksum verification failed')
node_mock = mock.ANY
checksum_fake = mock.ANY
# | WHEN | & | THEN |
self.assertRaises(exception.ImageRefValidationFailed,
fw_processor.process_fw_on,
node_mock,
checksum_fake)
shutil_mock.rmtree.assert_called_once_with(
tempfile_mock.mkdtemp(), ignore_errors=True)
@mock.patch.object(ilo_fw_processor, 'tempfile', autospec=True)
@mock.patch.object(ilo_fw_processor, 'os', autospec=True)
@mock.patch.object(ilo_fw_processor, 'shutil', autospec=True)
@mock.patch.object(ilo_common, 'verify_image_checksum',
spec_set=True, autospec=True)
@mock.patch.object(
ilo_fw_processor, '_extract_fw_from_file', autospec=True)
def test_process_fw_on_calls__extract_fw_from_file(
self, _extract_fw_from_file_mock, verify_checksum_mock,
shutil_mock, os_mock, tempfile_mock):
# | GIVEN |
fw_processor = ilo_fw_processor.FirmwareProcessor(self.any_url)
# Now mock the __download_fw_to method of fw_processor instance
_download_fw_to_mock = mock.MagicMock()
fw_processor._download_fw_to = _download_fw_to_mock
expected_return_location = (ilo_fw_processor.FirmwareImageLocation(
'some_location/file', 'file'))
_extract_fw_from_file_mock.return_value = (expected_return_location,
True)
node_mock = mock.ANY
checksum_fake = mock.ANY
# | WHEN |
actual_return_location = fw_processor.process_fw_on(node_mock,
checksum_fake)
# | THEN |
_extract_fw_from_file_mock.assert_called_once_with(
node_mock, os_mock.path.join.return_value)
self.assertEqual(expected_return_location.fw_image_location,
actual_return_location.fw_image_location)
self.assertEqual(expected_return_location.fw_image_filename,
actual_return_location.fw_image_filename)
shutil_mock.rmtree.assert_called_once_with(
tempfile_mock.mkdtemp(), ignore_errors=True)
@mock.patch.object(builtins, 'open', autospec=True)
@mock.patch.object(
ilo_fw_processor.image_service, 'FileImageService', autospec=True)
def test__download_file_based_fw_to_copies_file_to_target(
self, file_image_service_mock, open_mock):
# | GIVEN |
fd_mock = mock.MagicMock(spec=io.BytesIO)
open_mock.return_value = fd_mock
fd_mock.__enter__.return_value = fd_mock
any_file_based_firmware_file = 'file:///tmp/any_file_path'
firmware_file_path = '/tmp/any_file_path'
self.fw_processor_fake.parsed_url = urlparse.urlparse(
any_file_based_firmware_file)
# | WHEN |
ilo_fw_processor._download_file_based_fw_to(self.fw_processor_fake,
'target_file')
# | THEN |
file_image_service_mock.return_value.download.assert_called_once_with(
firmware_file_path, fd_mock)
@mock.patch.object(builtins, 'open', autospec=True)
@mock.patch.object(ilo_fw_processor, 'image_service', autospec=True)
def test__download_http_based_fw_to_downloads_the_fw_file(
self, image_service_mock, open_mock):
# | GIVEN |
fd_mock = mock.MagicMock(spec=io.BytesIO)
open_mock.return_value = fd_mock
fd_mock.__enter__.return_value = fd_mock
any_http_based_firmware_file = 'http://netloc/path_to_firmware_file'
any_target_file = 'any_target_file'
self.fw_processor_fake.parsed_url = urlparse.urlparse(
any_http_based_firmware_file)
# | WHEN |
ilo_fw_processor._download_http_based_fw_to(self.fw_processor_fake,
any_target_file)
# | THEN |
image_service_mock.HttpImageService().download.assert_called_once_with(
any_http_based_firmware_file, fd_mock)
@mock.patch.object(ilo_fw_processor, 'urlparse', autospec=True)
@mock.patch.object(
ilo_fw_processor, '_download_http_based_fw_to', autospec=True)
@mock.patch.object(ilo_fw_processor, 'swift', autospec=True)
def test__download_swift_based_fw_to_creates_temp_url(
self, swift_mock, _download_http_based_fw_to_mock, urlparse_mock):
# | GIVEN |
swift_based_firmware_files = [
'swift://containername/objectname',
'swift://containername/pseudo-folder/objectname'
]
for swift_firmware_file in swift_based_firmware_files:
# | WHEN |
self.fw_processor_fake.parsed_url = (urlparse.
urlparse(swift_firmware_file))
ilo_fw_processor._download_swift_based_fw_to(
self.fw_processor_fake, 'any_target_file')
# | THEN |
expected_temp_url_call_args_list = [
mock.call('containername', 'objectname', mock.ANY),
mock.call('containername', 'pseudo-folder/objectname', mock.ANY)
]
actual_temp_url_call_args_list = (
swift_mock.SwiftAPI().get_temp_url.call_args_list)
self.assertEqual(expected_temp_url_call_args_list,
actual_temp_url_call_args_list)
@mock.patch.object(urlparse, 'urlparse', autospec=True)
@mock.patch.object(
ilo_fw_processor, '_download_http_based_fw_to', autospec=True)
@mock.patch.object(ilo_fw_processor, 'swift', autospec=True)
def test__download_swift_based_fw_to_calls__download_http_based_fw_to(
self, swift_mock, _download_http_based_fw_to_mock, urlparse_mock):
"""_download_swift_based_fw_to invokes _download_http_based_fw_to
_download_swift_based_fw_to makes a call to _download_http_based_fw_to
in turn with temp url set as the url attribute of fw_processor instance
"""
# | GIVEN |
any_swift_based_firmware_file = 'swift://containername/objectname'
any_target_file = 'any_target_file'
self.fw_processor_fake.parsed_url = urlparse.urlparse(
any_swift_based_firmware_file)
urlparse_mock.reset_mock()
# | WHEN |
ilo_fw_processor._download_swift_based_fw_to(self.fw_processor_fake,
any_target_file)
# | THEN |
_download_http_based_fw_to_mock.assert_called_once_with(
self.fw_processor_fake, any_target_file)
urlparse_mock.assert_called_once_with(
swift_mock.SwiftAPI().get_temp_url.return_value)
self.assertEqual(
urlparse_mock.return_value, self.fw_processor_fake.parsed_url)
@mock.patch.object(ilo_fw_processor, 'ilo_common', autospec=True)
def test__extract_fw_from_file_calls_process_firmware_image(
self, ilo_common_mock):
# | GIVEN |
if not mock._is_instance_mock(proliantutils.utils):
mock.patch.object(proliantutils.utils, 'process_firmware_image',
autospec=True).start()
utils_mock = proliantutils.utils.process_firmware_image
node_mock = mock.MagicMock(uuid='fake_node_uuid')
any_target_file = 'any_target_file'
ilo_object_mock = ilo_common_mock.get_ilo_object.return_value
utils_mock.return_value = ('some_location', True, True)
# | WHEN |
ilo_fw_processor._extract_fw_from_file(node_mock, any_target_file)
# | THEN |
utils_mock.assert_called_once_with(any_target_file, ilo_object_mock)
@mock.patch.object(ilo_fw_processor, 'ilo_common', autospec=True)
def test__extract_fw_from_file_doesnt_upload_firmware(
self, ilo_common_mock):
# | GIVEN |
if not mock._is_instance_mock(proliantutils.utils):
mock.patch.object(proliantutils.utils, 'process_firmware_image',
autospec=True).start()
utils_mock = proliantutils.utils.process_firmware_image
node_mock = mock.MagicMock(uuid='fake_node_uuid')
any_target_file = 'any_target_file'
utils_mock.return_value = (
'some_location/some_fw_file', False, True)
# | WHEN |
ilo_fw_processor._extract_fw_from_file(node_mock, any_target_file)
# | THEN |
ilo_common_mock.copy_image_to_web_server.assert_not_called()
@mock.patch.object(ilo_fw_processor, 'ilo_common', autospec=True)
@mock.patch.object(ilo_fw_processor, '_remove_file_based_me',
autospec=True)
def test__extract_fw_from_file_sets_loc_obj_remove_to_file_if_no_upload(
self, _remove_mock, ilo_common_mock):
# | GIVEN |
if not mock._is_instance_mock(proliantutils.utils):
mock.patch.object(proliantutils.utils, 'process_firmware_image',
autospec=True).start()
utils_mock = proliantutils.utils.process_firmware_image
node_mock = mock.MagicMock(uuid='fake_node_uuid')
any_target_file = 'any_target_file'
utils_mock.return_value = (
'some_location/some_fw_file', False, True)
# | WHEN |
location_obj, is_different_file = (
ilo_fw_processor._extract_fw_from_file(node_mock, any_target_file))
location_obj.remove()
# | THEN |
_remove_mock.assert_called_once_with(location_obj)
@mock.patch.object(ilo_fw_processor, 'ilo_common', autospec=True)
def test__extract_fw_from_file_uploads_firmware_to_webserver(
self, ilo_common_mock):
# | GIVEN |
if not mock._is_instance_mock(proliantutils.utils):
mock.patch.object(proliantutils.utils, 'process_firmware_image',
autospec=True).start()
utils_mock = proliantutils.utils.process_firmware_image
node_mock = mock.MagicMock(uuid='fake_node_uuid')
any_target_file = 'any_target_file'
utils_mock.return_value = (
'some_location/some_fw_file', True, True)
self.config(use_web_server_for_images=True, group='ilo')
# | WHEN |
ilo_fw_processor._extract_fw_from_file(node_mock, any_target_file)
# | THEN |
ilo_common_mock.copy_image_to_web_server.assert_called_once_with(
'some_location/some_fw_file', 'some_fw_file')
@mock.patch.object(ilo_fw_processor, 'ilo_common', autospec=True)
@mock.patch.object(ilo_fw_processor, '_remove_webserver_based_me',
autospec=True)
def test__extract_fw_from_file_sets_loc_obj_remove_to_webserver(
self, _remove_mock, ilo_common_mock):
# | GIVEN |
if not mock._is_instance_mock(proliantutils.utils):
mock.patch.object(proliantutils.utils, 'process_firmware_image',
autospec=True).start()
utils_mock = proliantutils.utils.process_firmware_image
node_mock = mock.MagicMock(uuid='fake_node_uuid')
any_target_file = 'any_target_file'
utils_mock.return_value = (
'some_location/some_fw_file', True, True)
self.config(use_web_server_for_images=True, group='ilo')
# | WHEN |
location_obj, is_different_file = (
ilo_fw_processor._extract_fw_from_file(node_mock, any_target_file))
location_obj.remove()
# | THEN |
_remove_mock.assert_called_once_with(location_obj)
@mock.patch.object(ilo_fw_processor, 'ilo_common', autospec=True)
def test__extract_fw_from_file_uploads_firmware_to_swift(
self, ilo_common_mock):
# | GIVEN |
if not mock._is_instance_mock(proliantutils.utils):
mock.patch.object(proliantutils.utils, 'process_firmware_image',
autospec=True).start()
utils_mock = proliantutils.utils.process_firmware_image
node_mock = mock.MagicMock(uuid='fake_node_uuid')
any_target_file = 'any_target_file'
utils_mock.return_value = (
'some_location/some_fw_file', True, True)
self.config(use_web_server_for_images=False, group='ilo')
# | WHEN |
ilo_fw_processor._extract_fw_from_file(node_mock, any_target_file)
# | THEN |
ilo_common_mock.copy_image_to_swift.assert_called_once_with(
'some_location/some_fw_file', 'some_fw_file')
@mock.patch.object(ilo_fw_processor, 'ilo_common', autospec=True)
@mock.patch.object(ilo_fw_processor, '_remove_swift_based_me',
autospec=True)
def test__extract_fw_from_file_sets_loc_obj_remove_to_swift(
self, _remove_mock, ilo_common_mock):
# | GIVEN |
if not mock._is_instance_mock(proliantutils.utils):
mock.patch.object(proliantutils.utils, 'process_firmware_image',
autospec=True).start()
utils_mock = proliantutils.utils.process_firmware_image
node_mock = mock.MagicMock(uuid='fake_node_uuid')
any_target_file = 'any_target_file'
utils_mock.return_value = (
'some_location/some_fw_file', True, True)
self.config(use_web_server_for_images=False, group='ilo')
# | WHEN |
location_obj, is_different_file = (
ilo_fw_processor._extract_fw_from_file(node_mock, any_target_file))
location_obj.remove()
# | THEN |
_remove_mock.assert_called_once_with(location_obj)
def test_fw_img_loc_sets_these_attributes(self):
# | GIVEN |
any_loc = 'some_location/some_fw_file'
any_s_filename = 'some_fw_file'
# | WHEN |
location_obj = ilo_fw_processor.FirmwareImageLocation(
any_loc, any_s_filename)
# | THEN |
self.assertEqual(any_loc, location_obj.fw_image_location)
self.assertEqual(any_s_filename, location_obj.fw_image_filename)
@mock.patch.object(ilo_fw_processor, 'ilo_common', autospec=True)
def test__remove_file_based_me(
self, ilo_common_mock):
# | GIVEN |
fw_img_location_obj_fake = mock.MagicMock()
# | WHEN |
ilo_fw_processor._remove_file_based_me(fw_img_location_obj_fake)
# | THEN |
(ilo_common_mock.remove_single_or_list_of_files.
assert_called_with(fw_img_location_obj_fake.fw_image_location))
@mock.patch.object(ilo_fw_processor, 'ilo_common', autospec=True)
def test__remove_swift_based_me(self, ilo_common_mock):
# | GIVEN |
fw_img_location_obj_fake = mock.MagicMock()
# | WHEN |
ilo_fw_processor._remove_swift_based_me(fw_img_location_obj_fake)
# | THEN |
(ilo_common_mock.remove_image_from_swift.assert_called_with(
fw_img_location_obj_fake.fw_image_filename, "firmware update"))
@mock.patch.object(ilo_fw_processor, 'ilo_common', autospec=True)
def test__remove_webserver_based_me(self, ilo_common_mock):
# | GIVEN |
fw_img_location_obj_fake = mock.MagicMock()
# | WHEN |
ilo_fw_processor._remove_webserver_based_me(fw_img_location_obj_fake)
# | THEN |
(ilo_common_mock.remove_image_from_web_server.assert_called_with(
fw_img_location_obj_fake.fw_image_filename))
@@ -1,487 +0,0 @@
# Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# 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 Management Interface used by iLO modules."""
from unittest import mock
from ironic.common import exception
from ironic.common import states
from ironic.common import utils
from ironic.conductor import task_manager
from ironic.conductor import utils as conductor_utils
from ironic.drivers.modules.ilo import common as ilo_common
from ironic.drivers.modules.ilo import inspect as ilo_inspect
from ironic.drivers.modules.ilo import power as ilo_power
from ironic.drivers.modules import inspect_utils
from ironic.tests.unit.drivers.modules.ilo import test_common
class IloInspectTestCase(test_common.BaseIloTest):
def test_get_properties(self):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
properties = ilo_common.REQUIRED_PROPERTIES.copy()
properties.update(ilo_common.SNMP_PROPERTIES)
properties.update(ilo_common.SNMP_OPTIONAL_PROPERTIES)
self.assertEqual(properties,
task.driver.inspect.get_properties())
@mock.patch.object(ilo_common, 'parse_driver_info', spec_set=True,
autospec=True)
def test_validate(self, driver_info_mock):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.driver.inspect.validate(task)
driver_info_mock.assert_called_once_with(task.node)
@mock.patch.object(ilo_inspect, '_get_capabilities', spec_set=True,
autospec=True)
@mock.patch.object(inspect_utils, 'create_ports_if_not_exist',
spec_set=True, autospec=True)
@mock.patch.object(ilo_inspect, '_get_essential_properties', spec_set=True,
autospec=True)
@mock.patch.object(ilo_power.IloPower, 'get_power_state', spec_set=True,
autospec=True)
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
autospec=True)
def test_inspect_essential_ok(self, get_ilo_object_mock,
power_mock,
get_essential_mock,
create_port_mock,
get_capabilities_mock):
ilo_object_mock = get_ilo_object_mock.return_value
properties = {'memory_mb': '512', 'local_gb': 10,
'cpu_arch': 'x86_64'}
macs = {'Port 1': 'aa:aa:aa:aa:aa:aa', 'Port 2': 'bb:bb:bb:bb:bb:bb'}
capabilities = {}
result = {'properties': properties, 'macs': macs}
get_essential_mock.return_value = result
get_capabilities_mock.return_value = capabilities
power_mock.return_value = states.POWER_ON
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.driver.inspect.inspect_hardware(task)
self.assertEqual(properties, task.node.properties)
power_mock.assert_called_once_with(mock.ANY, task)
get_essential_mock.assert_called_once_with(task.node,
ilo_object_mock)
get_capabilities_mock.assert_called_once_with(task.node,
ilo_object_mock)
create_port_mock.assert_called_once_with(
task, ['aa:aa:aa:aa:aa:aa', 'bb:bb:bb:bb:bb:bb'])
@mock.patch.object(ilo_inspect.LOG, 'warning',
spec_set=True, autospec=True)
@mock.patch.object(ilo_inspect, '_get_capabilities', spec_set=True,
autospec=True)
@mock.patch.object(inspect_utils, 'create_ports_if_not_exist',
spec_set=True, autospec=True)
@mock.patch.object(ilo_inspect, '_get_essential_properties', spec_set=True,
autospec=True)
@mock.patch.object(ilo_power.IloPower, 'get_power_state', spec_set=True,
autospec=True)
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
autospec=True)
def test_inspect_essential_ok_local_gb_zero(self, get_ilo_object_mock,
power_mock,
get_essential_mock,
create_port_mock,
get_capabilities_mock,
log_mock):
ilo_object_mock = get_ilo_object_mock.return_value
properties = {'memory_mb': '512', 'local_gb': 0, 'cpu_arch': 'x86_64'}
macs = {'Port 1': 'aa:aa:aa:aa:aa:aa', 'Port 2': 'bb:bb:bb:bb:bb:bb'}
capabilities = {}
result = {'properties': properties, 'macs': macs}
get_essential_mock.return_value = result
get_capabilities_mock.return_value = capabilities
power_mock.return_value = states.POWER_ON
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
properties = task.node.properties
properties['local_gb'] = 10
task.node.properties = properties
task.node.save()
expected_properties = {'memory_mb': '512', 'local_gb': 10,
'cpu_arch': 'x86_64'}
task.driver.inspect.inspect_hardware(task)
self.assertEqual(expected_properties, task.node.properties)
power_mock.assert_called_once_with(mock.ANY, task)
get_essential_mock.assert_called_once_with(task.node,
ilo_object_mock)
self.assertTrue(log_mock.called)
get_capabilities_mock.assert_called_once_with(task.node,
ilo_object_mock)
create_port_mock.assert_called_once_with(
task, ['aa:aa:aa:aa:aa:aa', 'bb:bb:bb:bb:bb:bb'])
@mock.patch.object(ilo_inspect.LOG, 'warning',
spec_set=True, autospec=True)
@mock.patch.object(ilo_inspect, '_get_capabilities', spec_set=True,
autospec=True)
@mock.patch.object(inspect_utils, 'create_ports_if_not_exist',
spec_set=True, autospec=True)
@mock.patch.object(ilo_inspect, '_get_essential_properties', spec_set=True,
autospec=True)
@mock.patch.object(ilo_power.IloPower, 'get_power_state', spec_set=True,
autospec=True)
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
autospec=True)
def test_inspect_ok_gen8(self, get_ilo_object_mock,
power_mock,
get_essential_mock,
create_port_mock,
get_capabilities_mock,
log_mock):
ilo_object_mock = get_ilo_object_mock.return_value
properties = {'memory_mb': '512', 'local_gb': 10, 'cpu_arch': 'x86_64'}
macs = {'Port 1': 'aa:aa:aa:aa:aa:aa', 'Port 2': 'bb:bb:bb:bb:bb:bb'}
capabilities = {'server_model': 'Gen8'}
result = {'properties': properties, 'macs': macs}
get_essential_mock.return_value = result
get_capabilities_mock.return_value = capabilities
power_mock.return_value = states.POWER_ON
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
expected_properties = {'memory_mb': '512', 'local_gb': 10,
'cpu_arch': 'x86_64',
'capabilities': 'server_model:Gen8'}
task.driver.inspect.inspect_hardware(task)
self.assertEqual(expected_properties, task.node.properties)
power_mock.assert_called_once_with(mock.ANY, task)
get_essential_mock.assert_called_once_with(task.node,
ilo_object_mock)
self.assertTrue(log_mock.called)
get_capabilities_mock.assert_called_once_with(task.node,
ilo_object_mock)
create_port_mock.assert_called_once_with(
task, ['aa:aa:aa:aa:aa:aa', 'bb:bb:bb:bb:bb:bb'])
@mock.patch.object(ilo_inspect.LOG, 'warning',
spec_set=True, autospec=True)
@mock.patch.object(ilo_inspect, '_get_security_parameters',
spec_set=True, autospec=True)
@mock.patch.object(ilo_inspect, '_get_capabilities', spec_set=True,
autospec=True)
@mock.patch.object(inspect_utils, 'create_ports_if_not_exist',
spec_set=True, autospec=True)
@mock.patch.object(ilo_inspect, '_get_essential_properties', spec_set=True,
autospec=True)
@mock.patch.object(ilo_power.IloPower, 'get_power_state', spec_set=True,
autospec=True)
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
autospec=True)
def test_inspect_ok_gen10(self, get_ilo_object_mock,
power_mock,
get_essential_mock,
create_port_mock,
get_capabilities_mock,
get_security_params_mock,
log_mock):
ilo_object_mock = get_ilo_object_mock.return_value
properties = {'memory_mb': '512', 'local_gb': 10, 'cpu_arch': 'x86_64'}
macs = {'NIC.LOM.1.1': 'aa:aa:aa:aa:aa:aa'}
capabilities = {'server_model': 'Gen10'}
security_params = (
{'security_parameters': {'Password Complexity': 'ok'}})
result = {'properties': properties, 'macs': macs}
get_essential_mock.return_value = result
get_capabilities_mock.return_value = capabilities
get_security_params_mock.return_value = security_params
power_mock.return_value = states.POWER_ON
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
expected_properties = {
'memory_mb': '512', 'local_gb': 10,
'cpu_arch': 'x86_64', 'capabilities': 'server_model:Gen10',
'security_parameters': {'Password Complexity': 'ok'}}
task.driver.inspect.inspect_hardware(task)
self.assertEqual(expected_properties, task.node.properties)
power_mock.assert_called_once_with(mock.ANY, task)
get_essential_mock.assert_called_once_with(task.node,
ilo_object_mock)
self.assertFalse(log_mock.called)
get_capabilities_mock.assert_called_once_with(task.node,
ilo_object_mock)
create_port_mock.assert_called_once_with(
task, ['aa:aa:aa:aa:aa:aa'])
@mock.patch.object(ilo_inspect, '_get_capabilities', spec_set=True,
autospec=True)
@mock.patch.object(inspect_utils, 'create_ports_if_not_exist',
spec_set=True, autospec=True)
@mock.patch.object(ilo_inspect, '_get_essential_properties', spec_set=True,
autospec=True)
@mock.patch.object(conductor_utils, 'node_power_action', spec_set=True,
autospec=True)
@mock.patch.object(ilo_power.IloPower, 'get_power_state', spec_set=True,
autospec=True)
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
autospec=True)
def test_inspect_essential_ok_power_off(self, get_ilo_object_mock,
power_mock,
set_power_mock,
get_essential_mock,
create_port_mock,
get_capabilities_mock):
ilo_object_mock = get_ilo_object_mock.return_value
properties = {'memory_mb': '512', 'local_gb': 10,
'cpu_arch': 'x86_64'}
macs = {'Port 1': 'aa:aa:aa:aa:aa:aa', 'Port 2': 'bb:bb:bb:bb:bb:bb'}
capabilities = {}
result = {'properties': properties, 'macs': macs}
get_essential_mock.return_value = result
get_capabilities_mock.return_value = capabilities
power_mock.return_value = states.POWER_OFF
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.driver.inspect.inspect_hardware(task)
self.assertEqual(properties, task.node.properties)
power_mock.assert_called_once_with(mock.ANY, task)
set_power_mock.assert_any_call(task, states.POWER_ON)
get_essential_mock.assert_called_once_with(task.node,
ilo_object_mock)
get_capabilities_mock.assert_called_once_with(task.node,
ilo_object_mock)
create_port_mock.assert_called_once_with(
task, ['aa:aa:aa:aa:aa:aa', 'bb:bb:bb:bb:bb:bb'])
@mock.patch.object(ilo_inspect, '_get_capabilities', spec_set=True,
autospec=True)
@mock.patch.object(inspect_utils, 'create_ports_if_not_exist',
spec_set=True, autospec=True)
@mock.patch.object(ilo_inspect, '_get_essential_properties', spec_set=True,
autospec=True)
@mock.patch.object(ilo_power.IloPower, 'get_power_state', spec_set=True,
autospec=True)
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
autospec=True)
def test_inspect_essential_capabilities_ok(self, get_ilo_object_mock,
power_mock,
get_essential_mock,
create_port_mock,
get_capabilities_mock):
ilo_object_mock = get_ilo_object_mock.return_value
properties = {'memory_mb': '512', 'local_gb': 10,
'cpu_arch': 'x86_64'}
macs = {'Port 1': 'aa:aa:aa:aa:aa:aa', 'Port 2': 'bb:bb:bb:bb:bb:bb'}
capability_str = 'sriov_enabled:true'
capabilities = {'sriov_enabled': 'true'}
result = {'properties': properties, 'macs': macs}
get_essential_mock.return_value = result
get_capabilities_mock.return_value = capabilities
power_mock.return_value = states.POWER_ON
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.driver.inspect.inspect_hardware(task)
expected_properties = {'memory_mb': '512', 'local_gb': 10,
'cpu_arch': 'x86_64',
'capabilities': capability_str}
self.assertEqual(expected_properties, task.node.properties)
power_mock.assert_called_once_with(mock.ANY, task)
get_essential_mock.assert_called_once_with(task.node,
ilo_object_mock)
get_capabilities_mock.assert_called_once_with(task.node,
ilo_object_mock)
create_port_mock.assert_called_once_with(
task, ['aa:aa:aa:aa:aa:aa', 'bb:bb:bb:bb:bb:bb'])
@mock.patch.object(ilo_inspect, '_get_capabilities', spec_set=True,
autospec=True)
@mock.patch.object(inspect_utils, 'create_ports_if_not_exist',
spec_set=True, autospec=True)
@mock.patch.object(ilo_inspect, '_get_essential_properties', spec_set=True,
autospec=True)
@mock.patch.object(ilo_power.IloPower, 'get_power_state', spec_set=True,
autospec=True)
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
autospec=True)
def test_inspect_essential_capabilities_exist_ok(self, get_ilo_object_mock,
power_mock,
get_essential_mock,
create_port_mock,
get_capabilities_mock):
ilo_object_mock = get_ilo_object_mock.return_value
properties = {'memory_mb': '512', 'local_gb': 10,
'cpu_arch': 'x86_64', 'somekey': 'somevalue'}
macs = {'Port 1': 'aa:aa:aa:aa:aa:aa', 'Port 2': 'bb:bb:bb:bb:bb:bb'}
result = {'properties': properties, 'macs': macs}
capabilities = {'sriov_enabled': 'true'}
get_essential_mock.return_value = result
get_capabilities_mock.return_value = capabilities
power_mock.return_value = states.POWER_ON
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.node.properties = {'capabilities': 'boot_mode:uefi'}
expected_capabilities = ('sriov_enabled:true,'
'boot_mode:uefi')
set1 = set(expected_capabilities.split(','))
task.driver.inspect.inspect_hardware(task)
end_capabilities = task.node.properties['capabilities']
set2 = set(end_capabilities.split(','))
self.assertEqual(set1, set2)
expected_properties = {'memory_mb': '512', 'local_gb': 10,
'cpu_arch': 'x86_64',
'capabilities': end_capabilities}
power_mock.assert_called_once_with(mock.ANY, task)
self.assertEqual(task.node.properties, expected_properties)
get_essential_mock.assert_called_once_with(task.node,
ilo_object_mock)
get_capabilities_mock.assert_called_once_with(task.node,
ilo_object_mock)
create_port_mock.assert_called_once_with(
task, ['aa:aa:aa:aa:aa:aa', 'bb:bb:bb:bb:bb:bb'])
class TestInspectPrivateMethods(test_common.BaseIloTest):
def test__get_essential_properties_ok(self):
ilo_mock = mock.MagicMock(spec=['get_essential_properties'])
properties = {'memory_mb': '512', 'local_gb': 10,
'cpu_arch': 'x86_64'}
macs = {'Port 1': 'aa:aa:aa:aa:aa:aa', 'Port 2': 'bb:bb:bb:bb:bb:bb'}
result = {'properties': properties, 'macs': macs}
ilo_mock.get_essential_properties.return_value = result
actual_result = ilo_inspect._get_essential_properties(self.node,
ilo_mock)
self.assertEqual(result, actual_result)
def test__get_essential_properties_fail(self):
ilo_mock = mock.MagicMock(
spec=['get_additional_capabilities', 'get_essential_properties'])
# Missing key: cpu_arch
properties = {'memory_mb': '512', 'local_gb': 10}
macs = {'Port 1': 'aa:aa:aa:aa:aa:aa', 'Port 2': 'bb:bb:bb:bb:bb:bb'}
result = {'properties': properties, 'macs': macs}
ilo_mock.get_essential_properties.return_value = result
result = self.assertRaises(exception.HardwareInspectionFailure,
ilo_inspect._get_essential_properties,
self.node,
ilo_mock)
self.assertEqual(
str(result),
("Failed to inspect hardware. Reason: Server didn't return the "
"key(s): cpu_arch"))
def test__get_essential_properties_fail_invalid_format(self):
ilo_mock = mock.MagicMock(
spec=['get_additional_capabilities', 'get_essential_properties'])
# Not a dict
properties = ['memory_mb', '512', 'local_gb', 10]
macs = ['aa:aa:aa:aa:aa:aa', 'bb:bb:bb:bb:bb:bb']
capabilities = ''
result = {'properties': properties, 'macs': macs}
ilo_mock.get_essential_properties.return_value = result
ilo_mock.get_additional_capabilities.return_value = capabilities
self.assertRaises(exception.HardwareInspectionFailure,
ilo_inspect._get_essential_properties,
self.node, ilo_mock)
def test__get_essential_properties_fail_mac_invalid_format(self):
ilo_mock = mock.MagicMock(spec=['get_essential_properties'])
properties = {'memory_mb': '512', 'local_gb': 10,
'cpu_arch': 'x86_64'}
# Not a dict
macs = 'aa:aa:aa:aa:aa:aa'
result = {'properties': properties, 'macs': macs}
ilo_mock.get_essential_properties.return_value = result
self.assertRaises(exception.HardwareInspectionFailure,
ilo_inspect._get_essential_properties,
self.node, ilo_mock)
def test__get_essential_properties_hardware_port_empty(self):
ilo_mock = mock.MagicMock(
spec=['get_additional_capabilities', 'get_essential_properties'])
properties = {'memory_mb': '512', 'local_gb': 10,
'cpu_arch': 'x86_64'}
# Not a dictionary
macs = None
result = {'properties': properties, 'macs': macs}
capabilities = ''
ilo_mock.get_essential_properties.return_value = result
ilo_mock.get_additional_capabilities.return_value = capabilities
self.assertRaises(exception.HardwareInspectionFailure,
ilo_inspect._get_essential_properties,
self.node, ilo_mock)
def test__get_essential_properties_hardware_port_not_dict(self):
ilo_mock = mock.MagicMock(spec=['get_essential_properties'])
properties = {'memory_mb': '512', 'local_gb': 10,
'cpu_arch': 'x86_64'}
# Not a dict
macs = 'aa:bb:cc:dd:ee:ff'
result = {'properties': properties, 'macs': macs}
ilo_mock.get_essential_properties.return_value = result
result = self.assertRaises(
exception.HardwareInspectionFailure,
ilo_inspect._get_essential_properties, self.node, ilo_mock)
@mock.patch.object(utils, 'get_updated_capabilities', spec_set=True,
autospec=True)
def test__get_capabilities_ok(self, capability_mock):
ilo_mock = mock.MagicMock(spec=['get_server_capabilities'])
capabilities = {'ilo_firmware_version': 'xyz'}
ilo_mock.get_server_capabilities.return_value = capabilities
cap = ilo_inspect._get_capabilities(self.node, ilo_mock)
self.assertEqual(cap, capabilities)
def test__validate_ok(self):
properties = {'memory_mb': '512', 'local_gb': 10,
'cpu_arch': 'x86_arch'}
macs = {'Port 1': 'aa:aa:aa:aa:aa:aa'}
data = {'properties': properties, 'macs': macs}
valid_keys = ilo_inspect.IloInspect.ESSENTIAL_PROPERTIES
ilo_inspect._validate(self.node, data)
self.assertEqual(sorted(set(properties)), sorted(valid_keys))
def test__validate_essential_keys_fail_missing_key(self):
properties = {'memory_mb': '512', 'local_gb': 10}
macs = {'Port 1': 'aa:aa:aa:aa:aa:aa'}
data = {'properties': properties, 'macs': macs}
self.assertRaises(exception.HardwareInspectionFailure,
ilo_inspect._validate, self.node, data)
def test___create_supported_capabilities_dict(self):
capabilities = {}
expected = {}
for key in ilo_inspect.CAPABILITIES_KEYS:
capabilities.update({key: 'true'})
expected.update({key: 'true'})
capabilities.update({'unknown_property': 'true'})
cap = ilo_inspect._create_supported_capabilities_dict(capabilities)
self.assertEqual(expected, cap)
def test___create_supported_capabilities_dict_excluded_capability(self):
capabilities = {}
expected = {}
for key in ilo_inspect.CAPABILITIES_KEYS - {'has_ssd'}:
capabilities.update({key: 'true'})
expected.update({key: 'true'})
cap = ilo_inspect._create_supported_capabilities_dict(capabilities)
self.assertEqual(expected, cap)
def test___create_supported_capabilities_dict_gpu_capabilities(self):
capabilities = {'gpu_Nvidia_count': 1, 'gpu_Nvidia_Tesla_M10_count': 1,
'gpu_Nvidia_Tesla_M10': True}
expected = {}
expected.update(capabilities)
for key in ilo_inspect.CAPABILITIES_KEYS:
capabilities.update({key: 'true'})
expected.update({key: 'true'})
capabilities.update({'unknown_property': 'true'})
cap = ilo_inspect._create_supported_capabilities_dict(capabilities)
self.assertEqual(expected, cap)
File diff suppressed because it is too large Load Diff
@@ -1,471 +0,0 @@
# Copyright 2014 Hewlett-Packard Development Company, L.P.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""Test class for IloPower module."""
from unittest import mock
from oslo_config import cfg
from oslo_utils import importutils
from oslo_utils import uuidutils
from ironic.common import boot_devices
from ironic.common import exception
from ironic.common import states
from ironic.conductor import task_manager
from ironic.conductor import utils as manager_utils
from ironic.drivers.modules.ilo import common as ilo_common
from ironic.drivers.modules.ilo import power as ilo_power
from ironic.tests.unit.db import utils as db_utils
from ironic.tests.unit.drivers.modules.ilo import test_common
from ironic.tests.unit.objects import utils as obj_utils
ilo_error = importutils.try_import('proliantutils.exception')
INFO_DICT = db_utils.get_test_ilo_info()
CONF = cfg.CONF
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True, autospec=True)
class IloPowerInternalMethodsTestCase(test_common.BaseIloTest):
def setUp(self):
super(IloPowerInternalMethodsTestCase, self).setUp()
self.node = obj_utils.create_test_node(
self.context, driver='ilo', driver_info=INFO_DICT,
instance_uuid=uuidutils.generate_uuid())
CONF.set_override('power_wait', 1, 'ilo')
CONF.set_override('soft_power_off_timeout', 1, 'conductor')
def test__get_power_state(self, get_ilo_object_mock):
ilo_mock_object = get_ilo_object_mock.return_value
ilo_mock_object.get_host_power_status.return_value = 'ON'
self.assertEqual(
states.POWER_ON, ilo_power._get_power_state(self.node))
ilo_mock_object.get_host_power_status.return_value = 'OFF'
self.assertEqual(
states.POWER_OFF, ilo_power._get_power_state(self.node))
ilo_mock_object.get_host_power_status.return_value = 'ERROR'
self.assertEqual(states.ERROR, ilo_power._get_power_state(self.node))
def test__get_power_state_fail(self, get_ilo_object_mock):
ilo_mock_object = get_ilo_object_mock.return_value
exc = ilo_error.IloError('error')
ilo_mock_object.get_host_power_status.side_effect = exc
self.assertRaises(exception.IloOperationError,
ilo_power._get_power_state,
self.node)
ilo_mock_object.get_host_power_status.assert_called_once_with()
@mock.patch.object(manager_utils, 'node_history_record', autospec=True)
def test__get_power_state_ilo6_redirect(self, record_history_mock,
get_ilo_object_mock):
ilo_mock_object = get_ilo_object_mock.return_value
exc = ilo_error.IloError('Error: RIBCLI is disabled.')
ilo_mock_object.get_host_power_status.side_effect = exc
self.assertRaisesRegex(exception.IloOperationError,
'appears to have a disabled API required',
ilo_power._get_power_state,
self.node)
ilo_mock_object.get_host_power_status.assert_called_once_with()
record_history_mock.assert_called_once_with(
mock.ANY,
event=('Node %s appears to have a disabled API required for the '
'\'ilo\' hardware type to function. Please consider using '
'the \'redfish\' hardware type.' % self.node.uuid),
event_type='available',
error=True)
def test__set_power_state_invalid_state(self, get_ilo_object_mock):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
self.assertRaises(exception.InvalidParameterValue,
ilo_power._set_power_state,
task,
states.ERROR)
def test__set_power_state_reboot_fail(self, get_ilo_object_mock):
ilo_mock_object = get_ilo_object_mock.return_value
exc = ilo_error.IloError('error')
ilo_mock_object.reset_server.side_effect = exc
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
self.assertRaises(exception.IloOperationError,
ilo_power._set_power_state,
task,
states.REBOOT)
ilo_mock_object.reset_server.assert_called_once_with()
@mock.patch.object(ilo_common, 'get_server_post_state', spec_set=True,
autospec=True)
def test__set_power_state_reboot_ok(self, get_post_mock,
get_ilo_object_mock):
ilo_mock_object = get_ilo_object_mock.return_value
get_post_mock.side_effect = (['FinishedPost', 'PowerOff',
'InPost'])
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
ilo_power._set_power_state(task, states.REBOOT)
get_post_mock.assert_called_with(task.node)
ilo_mock_object.reset_server.assert_called_once_with()
@mock.patch.object(ilo_common, 'get_server_post_state', spec_set=True,
autospec=True)
def test__set_power_state_off_fail(self, get_post_mock,
get_ilo_object_mock):
ilo_mock_object = get_ilo_object_mock.return_value
get_post_mock.side_effect = (['FinishedPost', 'FinishedPost',
'FinishedPost', 'FinishedPost',
'FinishedPost'])
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
self.assertRaises(exception.PowerStateFailure,
ilo_power._set_power_state,
task,
states.POWER_OFF)
get_post_mock.assert_called_with(task.node)
ilo_mock_object.hold_pwr_btn.assert_called_once_with()
@mock.patch.object(ilo_common, 'get_server_post_state', spec_set=True,
autospec=True)
def test__set_power_state_on_ok(self, get_post_mock, get_ilo_object_mock):
ilo_mock_object = get_ilo_object_mock.return_value
get_post_mock.side_effect = ['PowerOff', 'PowerOff', 'InPost']
target_state = states.POWER_ON
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
ilo_power._set_power_state(task, target_state)
get_post_mock.assert_called_with(task.node)
ilo_mock_object.set_host_power.assert_called_once_with('ON')
@mock.patch.object(ilo_power.LOG, 'info', autospec=True)
@mock.patch.object(ilo_power, '_attach_boot_iso_if_needed',
spec_set=True, autospec=True)
@mock.patch.object(ilo_common, 'get_server_post_state', spec_set=True,
autospec=True)
def test__set_power_state_soft_reboot_ok(
self, get_post_mock, attach_boot_iso_mock,
log_mock, get_ilo_object_mock):
CONF.set_override('power_wait', 1, 'ilo')
ilo_mock_object = get_ilo_object_mock.return_value
ilo_mock_object.get_host_power_status.return_value = 'ON'
get_post_mock.side_effect = (
['FinishedPost', 'FinishedPost', 'PowerOff', 'PowerOff', 'InPost',
'FinishedPost'])
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
ilo_power._set_power_state(task, states.SOFT_REBOOT, timeout=3)
get_post_mock.assert_called_with(task.node)
ilo_mock_object.press_pwr_btn.assert_called_once_with()
attach_boot_iso_mock.assert_called_once_with(task)
ilo_mock_object.set_host_power.assert_called_once_with('ON')
log_mock.assert_called_once_with(
"The node %(node_id)s operation of '%(state)s' "
"is completed in %(time_consumed)s seconds.",
{'state': 'soft rebooting', 'node_id': task.node.uuid,
'time_consumed': 2})
@mock.patch.object(ilo_power.LOG, 'info', autospec=True)
@mock.patch.object(ilo_power, '_attach_boot_iso_if_needed',
spec_set=True, autospec=True)
@mock.patch.object(ilo_common, 'get_server_post_state', spec_set=True,
autospec=True)
def test__set_power_state_soft_reboot_ok_initial_power_off(
self, get_post_mock, attach_boot_iso_mock,
log_mock, get_ilo_object_mock):
CONF.set_override('power_wait', 1, 'ilo')
ilo_mock_object = get_ilo_object_mock.return_value
ilo_mock_object.get_host_power_status.return_value = 'OFF'
get_post_mock.side_effect = ['FinishedPost', 'PowerOff',
'FinishedPost']
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
ilo_power._set_power_state(task, states.SOFT_REBOOT, timeout=3)
get_post_mock.assert_called_with(task.node)
attach_boot_iso_mock.assert_called_once_with(task)
ilo_mock_object.set_host_power.assert_called_once_with('ON')
log_mock.assert_called_once_with(
"The node %(node_id)s operation of '%(state)s' "
"is completed in %(time_consumed)s seconds.",
{'state': 'power on', 'node_id': task.node.uuid,
'time_consumed': 1})
@mock.patch.object(ilo_power.LOG, 'info', autospec=True)
@mock.patch.object(ilo_power, '_attach_boot_iso_if_needed',
spec_set=True, autospec=True)
@mock.patch.object(ilo_common, 'get_server_post_state', spec_set=True,
autospec=True)
def test__set_power_state_soft_reboot_fail_to_off(
self, get_post_mock, attach_boot_iso_mock,
log_mock, get_ilo_object_mock):
CONF.set_override('power_wait', 1, 'ilo')
exc = ilo_error.IloError('error')
ilo_mock_object = get_ilo_object_mock.return_value
ilo_mock_object.get_host_power_status.return_value = 'ON'
ilo_mock_object.press_pwr_btn.side_effect = exc
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
self.assertRaises(exception.IloOperationError,
ilo_power._set_power_state,
task, states.SOFT_REBOOT, timeout=3)
ilo_mock_object.press_pwr_btn.assert_called_once_with()
self.assertFalse(get_post_mock.called)
self.assertFalse(attach_boot_iso_mock.called)
self.assertFalse(log_mock.called)
@mock.patch.object(ilo_power.LOG, 'info', autospec=True)
@mock.patch.object(ilo_power, '_attach_boot_iso_if_needed',
spec_set=True, autospec=True)
@mock.patch.object(ilo_common, 'get_server_post_state', spec_set=True,
autospec=True)
def test__set_power_state_soft_reboot_fail_to_on(
self, get_post_mock, attach_boot_iso_mock,
log_mock, get_ilo_object_mock):
CONF.set_override('power_wait', 1, 'ilo')
exc = ilo_error.IloError('error')
ilo_mock_object = get_ilo_object_mock.return_value
ilo_mock_object.get_host_power_status.return_value = 'ON'
get_post_mock.side_effect = (
['FinishedPost', 'PowerOff', 'PowerOff', 'InPost',
'InPost', 'InPost', 'InPost', 'InPost'])
ilo_mock_object.press_pwr_btn.side_effect = [None, exc]
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
self.assertRaises(exception.PowerStateFailure,
ilo_power._set_power_state,
task, states.SOFT_REBOOT, timeout=3)
get_post_mock.assert_called_with(task.node)
ilo_mock_object.press_pwr_btn.assert_called_once_with()
ilo_mock_object.set_host_power.assert_called_once_with('ON')
attach_boot_iso_mock.assert_called_once_with(task)
self.assertFalse(log_mock.called)
@mock.patch.object(ilo_power.LOG, 'info', autospec=True)
@mock.patch.object(ilo_power, '_attach_boot_iso_if_needed',
spec_set=True, autospec=True)
@mock.patch.object(ilo_common, 'get_server_post_state', spec_set=True,
autospec=True)
def test__set_power_state_soft_reboot_timeout(
self, get_post_mock, attach_boot_iso_mock,
log_mock, get_ilo_object_mock):
CONF.set_override('power_wait', 1, 'ilo')
ilo_mock_object = get_ilo_object_mock.return_value
ilo_mock_object.get_host_power_status.return_value = 'ON'
get_post_mock.side_effect = ['FinishedPost', 'FinishedPost',
'PowerOff', 'InPost', 'InPost', 'InPost'
'InPost', 'InPost']
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
self.assertRaises(exception.PowerStateFailure,
ilo_power._set_power_state,
task, states.SOFT_REBOOT, timeout=2)
get_post_mock.assert_called_with(task.node)
ilo_mock_object.press_pwr_btn.assert_called_once_with()
ilo_mock_object.set_host_power.assert_called_once_with('ON')
attach_boot_iso_mock.assert_called_once_with(task)
self.assertFalse(log_mock.called)
@mock.patch.object(ilo_power.LOG, 'info', autospec=True)
@mock.patch.object(ilo_common, 'get_server_post_state', spec_set=True,
autospec=True)
def test__set_power_state_soft_power_off_ok(
self, get_post_mock, log_mock, get_ilo_object_mock):
CONF.set_override('power_wait', 1, 'ilo')
ilo_mock_object = get_ilo_object_mock.return_value
get_post_mock.side_effect = ['FinishedPost', 'FinishedPost', 'PowerOff'
'PowerOff', 'PowerOff']
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
ilo_power._set_power_state(task, states.SOFT_POWER_OFF, timeout=3)
get_post_mock.assert_called_with(task.node)
ilo_mock_object.press_pwr_btn.assert_called_once_with()
log_mock.assert_called_once_with(
"The node %(node_id)s operation of '%(state)s' "
"is completed in %(time_consumed)s seconds.",
{'state': 'soft power off', 'node_id': task.node.uuid,
'time_consumed': 2})
@mock.patch.object(ilo_power.LOG, 'info', autospec=True)
@mock.patch.object(ilo_common, 'get_server_post_state', spec_set=True,
autospec=True)
def test__set_power_state_soft_power_off_fail(
self, get_post_mock, log_mock, get_ilo_object_mock):
CONF.set_override('power_wait', 1, 'ilo')
exc = ilo_error.IloError('error')
ilo_mock_object = get_ilo_object_mock.return_value
ilo_mock_object.get_host_power_status.return_value = 'ON'
ilo_mock_object.press_pwr_btn.side_effect = exc
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
self.assertRaises(exception.IloOperationError,
ilo_power._set_power_state,
task, states.SOFT_POWER_OFF, timeout=2)
ilo_mock_object.press_pwr_btn.assert_called_once_with()
self.assertFalse(get_post_mock.called)
self.assertFalse(log_mock.called)
@mock.patch.object(ilo_power.LOG, 'info', autospec=True)
@mock.patch.object(ilo_common, 'get_server_post_state', spec_set=True,
autospec=True)
def test__set_power_state_soft_power_off_timeout(
self, get_post_mock, log_mock, get_ilo_object_mock):
CONF.set_override('power_wait', 1, 'ilo')
ilo_mock_object = get_ilo_object_mock.return_value
ilo_mock_object.get_host_power_status.return_value = 'ON'
get_post_mock.side_effect = ['FinishedPost', 'InPost', 'InPost',
'InPost', 'InPost']
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
self.assertRaises(exception.PowerStateFailure,
ilo_power._set_power_state,
task, states.SOFT_POWER_OFF, timeout=2)
get_post_mock.assert_called_with(task.node)
ilo_mock_object.press_pwr_btn.assert_called_with()
self.assertFalse(log_mock.called)
@mock.patch.object(manager_utils, 'node_set_boot_device', spec_set=True,
autospec=True)
@mock.patch.object(ilo_common, 'setup_vmedia_for_boot', spec_set=True,
autospec=True)
def test__attach_boot_iso_if_needed(
self, setup_vmedia_mock, set_boot_device_mock,
get_ilo_object_mock):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
task.node.provision_state = states.ACTIVE
task.node.instance_info['boot_iso'] = 'boot-iso'
ilo_power._attach_boot_iso_if_needed(task)
setup_vmedia_mock.assert_called_once_with(task, 'boot-iso')
set_boot_device_mock.assert_called_once_with(task,
boot_devices.CDROM)
@mock.patch.object(manager_utils, 'node_set_boot_device', spec_set=True,
autospec=True)
@mock.patch.object(ilo_common, 'setup_vmedia_for_boot', spec_set=True,
autospec=True)
def test__attach_boot_iso_if_needed_on_rebuild(
self, setup_vmedia_mock, set_boot_device_mock,
get_ilo_object_mock):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
task.node.provision_state = states.DEPLOYING
task.node.instance_info['boot_iso'] = 'boot-iso'
ilo_power._attach_boot_iso_if_needed(task)
self.assertFalse(setup_vmedia_mock.called)
self.assertFalse(set_boot_device_mock.called)
class IloPowerTestCase(test_common.BaseIloTest):
def test_get_properties(self):
expected = ilo_common.COMMON_PROPERTIES
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
self.assertEqual(expected, task.driver.power.get_properties())
@mock.patch.object(ilo_common, 'parse_driver_info', spec_set=True,
autospec=True)
def test_validate(self, mock_drvinfo):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
task.driver.power.validate(task)
mock_drvinfo.assert_called_once_with(task.node)
@mock.patch.object(ilo_common, 'parse_driver_info', spec_set=True,
autospec=True)
def test_validate_fail(self, mock_drvinfo):
side_effect = exception.InvalidParameterValue("Invalid Input")
mock_drvinfo.side_effect = side_effect
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
self.assertRaises(exception.InvalidParameterValue,
task.driver.power.validate,
task)
@mock.patch.object(ilo_power, '_get_power_state', spec_set=True,
autospec=True)
def test_get_power_state(self, mock_get_power):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
mock_get_power.return_value = states.POWER_ON
self.assertEqual(states.POWER_ON,
task.driver.power.get_power_state(task))
mock_get_power.assert_called_once_with(task.node)
@mock.patch.object(ilo_power, '_set_power_state', spec_set=True,
autospec=True)
def _test_set_power_state(self, mock_set_power, timeout=None):
mock_set_power.return_value = states.POWER_ON
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.driver.power.set_power_state(task, states.POWER_ON,
timeout=timeout)
mock_set_power.assert_called_once_with(task, states.POWER_ON,
timeout=timeout)
def test_set_power_state_no_timeout(self):
self._test_set_power_state(timeout=None)
def test_set_power_state_timeout(self):
self._test_set_power_state(timeout=13)
@mock.patch.object(ilo_power, '_set_power_state', spec_set=True,
autospec=True)
@mock.patch.object(ilo_power, '_get_power_state', spec_set=True,
autospec=True)
def _test_reboot(
self, mock_get_power, mock_set_power,
timeout=None):
mock_get_power.return_value = states.POWER_ON
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.driver.power.reboot(task, timeout=timeout)
mock_get_power.assert_called_once_with(task.node)
mock_set_power.assert_called_once_with(
task, states.REBOOT, timeout=timeout)
def test_reboot_no_timeout(self):
self._test_reboot(timeout=None)
def test_reboot_with_timeout(self):
self._test_reboot(timeout=100)
def test_get_supported_power_states(self):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
expected = [states.POWER_OFF, states.POWER_ON, states.REBOOT,
states.SOFT_POWER_OFF, states.SOFT_REBOOT]
self.assertEqual(
sorted(expected),
sorted(task.driver.power.
get_supported_power_states(task)))
@@ -1,607 +0,0 @@
# Copyright 2018 Hewlett Packard Enterprise Development LP
#
# 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 Raid Interface used by iLO5."""
from unittest import mock
from oslo_utils import importutils
from ironic.common import exception
from ironic.common import raid
from ironic.common import states
from ironic.conductor import task_manager
from ironic.conductor import utils as manager_utils
from ironic.drivers.modules import deploy_utils
from ironic.drivers.modules.ilo import common as ilo_common
from ironic.drivers.modules.ilo import raid as ilo_raid
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
ilo_error = importutils.try_import('proliantutils.exception')
INFO_DICT = db_utils.get_test_ilo_info()
class Ilo5RAIDTestCase(db_base.DbTestCase):
def setUp(self):
super(Ilo5RAIDTestCase, self).setUp()
self.driver = mock.Mock(raid=ilo_raid.Ilo5RAID())
self.target_raid_config = {
"logical_disks": [
{'size_gb': 200, 'raid_level': 0, 'is_root_volume': True},
{'size_gb': 200, 'raid_level': 5}
]}
n = {
'driver': 'ilo5',
'driver_info': INFO_DICT,
'target_raid_config': self.target_raid_config,
}
self.config(enabled_hardware_types=['ilo5'],
enabled_boot_interfaces=['ilo-virtual-media'],
enabled_console_interfaces=[],
enabled_deploy_interfaces=['direct'],
enabled_inspect_interfaces=['ilo'],
enabled_management_interfaces=['ilo5'],
enabled_power_interfaces=['ilo'],
enabled_raid_interfaces=['ilo5'])
self.node = obj_utils.create_test_node(self.context, **n)
@mock.patch.object(deploy_utils, 'build_agent_options', autospec=True)
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
def _test__prepare_for_read_raid_create_raid(
self, mock_reboot, mock_build_opt):
with task_manager.acquire(self.context, self.node.uuid) as task:
mock_build_opt.return_value = []
task.driver.raid._prepare_for_read_raid(task, 'create_raid')
self.assertTrue(
task.node.driver_internal_info.get(
'ilo_raid_create_in_progress'))
if task.node.clean_step:
self.assertTrue(
task.node.driver_internal_info.get(
'cleaning_reboot'))
self.assertFalse(
task.node.driver_internal_info.get(
'skip_current_clean_step'))
if task.node.deploy_step:
self.assertTrue(
task.node.driver_internal_info.get(
'deployment_reboot'))
self.assertFalse(
task.node.driver_internal_info.get(
'skip_current_deploy_step'))
mock_reboot.assert_called_once_with(task, states.REBOOT)
def test__prepare_for_read_raid_create_raid_cleaning(self):
self.node.clean_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.save()
self._test__prepare_for_read_raid_create_raid()
def test__prepare_for_read_raid_create_raid_deploying(self):
self.node.deploy_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.save()
self._test__prepare_for_read_raid_create_raid()
@mock.patch.object(deploy_utils, 'build_agent_options', autospec=True)
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
def _test__prepare_for_read_raid_delete_raid(
self, mock_reboot, mock_build_opt):
with task_manager.acquire(self.context, self.node.uuid) as task:
mock_build_opt.return_value = []
task.driver.raid._prepare_for_read_raid(task, 'delete_raid')
self.assertTrue(
task.node.driver_internal_info.get(
'ilo_raid_delete_in_progress'))
if task.node.clean_step:
self.assertTrue(
task.node.driver_internal_info.get(
'cleaning_reboot'))
self.assertEqual(
task.node.driver_internal_info.get(
'skip_current_clean_step'), False)
else:
self.assertTrue(
task.node.driver_internal_info.get(
'deployment_reboot'))
self.assertEqual(
task.node.driver_internal_info.get(
'skip_current_deploy_step'), False)
mock_reboot.assert_called_once_with(task, states.REBOOT)
def test__prepare_for_read_raid_delete_raid_cleaning(self):
self.node.clean_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.save()
self._test__prepare_for_read_raid_delete_raid()
def test__prepare_for_read_raid_delete_raid_deploying(self):
self.node.deploy_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.save()
self._test__prepare_for_read_raid_delete_raid()
@mock.patch.object(ilo_raid.Ilo5RAID, '_prepare_for_read_raid',
autospec=True)
@mock.patch.object(raid, 'filter_target_raid_config', autospec=True)
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
def _test_create_configuration(
self, ilo_mock, filter_target_raid_config_mock, prepare_raid_mock):
ilo_mock_object = ilo_mock.return_value
with task_manager.acquire(self.context, self.node.uuid) as task:
filter_target_raid_config_mock.return_value = (
self.target_raid_config)
result = task.driver.raid.create_configuration(task)
prepare_raid_mock.assert_called_once_with(
mock.ANY, task, 'create_raid')
if task.node.clean_step:
self.assertEqual(states.CLEANWAIT, result)
else:
self.assertEqual(states.DEPLOYWAIT, result)
(ilo_mock_object.create_raid_configuration.
assert_called_once_with(self.target_raid_config))
def test_create_configuration_cleaning(self):
self.node.clean_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.save()
self._test_create_configuration()
def test_create_configuration_deploying(self):
self.node.deploy_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.save()
self._test_create_configuration()
@mock.patch.object(raid, 'update_raid_info', autospec=True)
@mock.patch.object(raid, 'filter_target_raid_config', autospec=True)
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
def _test_create_configuration_with_read_raid(
self, ilo_mock, filter_target_raid_config_mock, update_raid_mock):
raid_conf = {u'logical_disks':
[{u'size_gb': 89,
u'physical_disks': [u'5I:1:1'],
u'raid_level': u'0',
u'root_device_hint': {u'wwn': u'0x600508b1001c7e87'},
u'controller': u'Smart Array P822 in Slot 1',
u'volume_name': u'0006EB7BPDVTF0BRH5L0EAEDDA'}]
}
ilo_mock_object = ilo_mock.return_value
driver_internal_info = self.node.driver_internal_info
driver_internal_info['ilo_raid_create_in_progress'] = True
if self.node.clean_step:
driver_internal_info['skip_current_clean_step'] = False
driver_internal_info['cleaning_reboot'] = True
else:
driver_internal_info['skip_current_deploy_step'] = False
driver_internal_info['deployment_reboot'] = True
self.node.driver_internal_info = driver_internal_info
self.node.save()
with task_manager.acquire(self.context, self.node.uuid) as task:
filter_target_raid_config_mock.return_value = (
self.target_raid_config)
ilo_mock_object.read_raid_configuration.return_value = raid_conf
task.driver.raid.create_configuration(task)
update_raid_mock.assert_called_once_with(task.node, raid_conf)
self.assertNotIn('ilo_raid_create_in_progress',
task.node.driver_internal_info)
if task.node.clean_step:
self.assertNotIn('skip_current_clean_step',
task.node.driver_internal_info)
def test_create_configuration_with_read_raid_cleaning(self):
self.node.clean_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.save()
self._test_create_configuration_with_read_raid()
def test_create_configuration_with_read_raid_deploying(self):
self.node.deploy_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.save()
self._test_create_configuration_with_read_raid()
@mock.patch.object(raid, 'filter_target_raid_config', autospec=True)
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
def _test_create_configuration_with_read_raid_failed(
self, ilo_mock, filter_target_raid_config_mock):
raid_conf = {u'logical_disks': []}
driver_internal_info = self.node.driver_internal_info
driver_internal_info['ilo_raid_create_in_progress'] = True
driver_internal_info['skip_current_clean_step'] = False
self.node.driver_internal_info = driver_internal_info
self.node.save()
ilo_mock_object = ilo_mock.return_value
if self.node.clean_step:
exept = exception.NodeCleaningFailure
else:
exept = exception.InstanceDeployFailure
with task_manager.acquire(self.context, self.node.uuid) as task:
filter_target_raid_config_mock.return_value = (
self.target_raid_config)
ilo_mock_object.read_raid_configuration.return_value = raid_conf
self.assertRaises(exept,
task.driver.raid.create_configuration, task)
self.assertNotIn('ilo_raid_create_in_progress',
task.node.driver_internal_info)
if task.node.clean_step:
self.assertNotIn('skip_current_clean_step',
task.node.driver_internal_info)
else:
self.assertNotIn('skip_current_deploy_step',
task.node.driver_internal_info)
def test_create_configuration_with_read_raid_failed_cleaning(self):
self.node.clean_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.save()
self._test_create_configuration_with_read_raid_failed()
def test_create_configuration_with_read_raid_failed_deploying(self):
self.node.deploy_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.save()
self._test_create_configuration_with_read_raid_failed()
@mock.patch.object(raid, 'filter_target_raid_config', autospec=True)
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
def _test_create_configuration_empty_target_raid_config(
self, ilo_mock, filter_target_raid_config_mock):
self.node.target_raid_config = {}
self.node.save()
ilo_mock_object = ilo_mock.return_value
with task_manager.acquire(self.context, self.node.uuid) as task:
msg = "Node %s has no target RAID configuration" % self.node.uuid
filter_target_raid_config_mock.side_effect = (
exception.MissingParameterValue(msg))
self.assertRaises(exception.MissingParameterValue,
task.driver.raid.create_configuration, task)
self.assertFalse(ilo_mock_object.create_raid_configuration.called)
def test_create_configuration_empty_target_raid_config_cleaning(self):
self.node.clean_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.save()
self._test_create_configuration_empty_target_raid_config()
def test_create_configuration_empty_target_raid_config_deploying(self):
self.node.deploy_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.save()
self._test_create_configuration_empty_target_raid_config()
@mock.patch.object(ilo_raid.Ilo5RAID, '_prepare_for_read_raid',
autospec=True)
@mock.patch.object(raid, 'filter_target_raid_config', autospec=True)
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
def _test_create_configuration_skip_root(
self, ilo_mock, filter_target_raid_config_mock,
prepare_raid_mock):
ilo_mock_object = ilo_mock.return_value
with task_manager.acquire(self.context, self.node.uuid) as task:
exp_target_raid_config = {
"logical_disks": [
{'size_gb': 200, 'raid_level': 5}
]}
filter_target_raid_config_mock.return_value = (
exp_target_raid_config)
result = task.driver.raid.create_configuration(
task, create_root_volume=False)
(ilo_mock_object.create_raid_configuration.
assert_called_once_with(exp_target_raid_config))
if task.node.clean_step:
self.assertEqual(states.CLEANWAIT, result)
else:
self.assertEqual(states.DEPLOYWAIT, result)
prepare_raid_mock.assert_called_once_with(
mock.ANY, task, 'create_raid')
self.assertEqual(
exp_target_raid_config,
task.node.driver_internal_info['target_raid_config'])
def test_create_configuration_skip_root_cleaning(self):
self.node.clean_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.save()
self._test_create_configuration_skip_root()
def test_create_configuration_skip_root_deploying(self):
self.node.deploy_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.save()
self._test_create_configuration_skip_root()
@mock.patch.object(ilo_raid.Ilo5RAID, '_prepare_for_read_raid',
autospec=True)
@mock.patch.object(raid, 'filter_target_raid_config', autospec=True)
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
def _test_create_configuration_skip_non_root(
self, ilo_mock, filter_target_raid_config_mock, prepare_raid_mock):
ilo_mock_object = ilo_mock.return_value
with task_manager.acquire(self.context, self.node.uuid) as task:
exp_target_raid_config = {
"logical_disks": [
{'size_gb': 200, 'raid_level': 0, 'is_root_volume': True}
]}
filter_target_raid_config_mock.return_value = (
exp_target_raid_config)
result = task.driver.raid.create_configuration(
task, create_nonroot_volumes=False)
(ilo_mock_object.create_raid_configuration.
assert_called_once_with(exp_target_raid_config))
prepare_raid_mock.assert_called_once_with(
mock.ANY, task, 'create_raid')
if task.node.clean_step:
self.assertEqual(states.CLEANWAIT, result)
else:
self.assertEqual(states.DEPLOYWAIT, result)
self.assertEqual(
exp_target_raid_config,
task.node.driver_internal_info['target_raid_config'])
def test_create_configuration_skip_non_root_cleaning(self):
self.node.clean_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.save()
self._test_create_configuration_skip_non_root()
def test_create_configuration_skip_non_root_deploying(self):
self.node.deploy_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.save()
self._test_create_configuration_skip_non_root()
@mock.patch.object(raid, 'filter_target_raid_config', autospec=True)
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
def _test_create_configuration_skip_root_skip_non_root(
self, ilo_mock, filter_target_raid_config_mock):
ilo_mock_object = ilo_mock.return_value
with task_manager.acquire(self.context, self.node.uuid) as task:
msg = "Node %s has no target RAID configuration" % self.node.uuid
filter_target_raid_config_mock.side_effect = (
exception.MissingParameterValue(msg))
self.assertRaises(
exception.MissingParameterValue,
task.driver.raid.create_configuration,
task, False, False)
self.assertFalse(ilo_mock_object.create_raid_configuration.called)
def test_create_configuration_skip_root_skip_non_root_cleaning(self):
self.node.clean_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.save()
self._test_create_configuration_skip_root_skip_non_root()
def test_create_configuration_skip_root_skip_non_root_deploying(self):
self.node.deploy_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.save()
self._test_create_configuration_skip_root_skip_non_root()
@mock.patch.object(manager_utils, 'cleaning_error_handler',
autospec=True)
@mock.patch.object(manager_utils, 'deploying_error_handler',
autospec=True)
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
def _test_create_configuration_ilo_error(self, ilo_mock,
deploy_err_handler_mock,
clean_err_handler_mock):
ilo_mock_object = ilo_mock.return_value
exc = ilo_error.IloError('error')
ilo_mock_object.create_raid_configuration.side_effect = exc
with task_manager.acquire(self.context, self.node.uuid) as task:
task.driver.raid.create_configuration(
task, create_nonroot_volumes=False)
self.assertNotIn('ilo_raid_create_in_progress',
task.node.driver_internal_info)
if task.node.clean_step:
self.assertNotIn('skip_current_clean_step',
task.node.driver_internal_info)
clean_err_handler_mock.assert_called_once_with(
task,
("RAID configuration job failed for node %s. Message: "
"'Failed to create raid configuration on node %s'." %
(self.node.uuid, self.node.uuid)),
'Failed to create raid configuration '
'on node %s' % self.node.uuid)
else:
self.assertNotIn('skip_current_deploy_step',
task.node.driver_internal_info)
deploy_err_handler_mock.assert_called_once_with(
task,
("RAID configuration job failed for node %s. Message: "
"'Failed to create raid configuration on node %s'." %
(self.node.uuid, self.node.uuid)),
'Failed to create raid configuration '
'on node %s' % self.node.uuid)
def test_create_configuration_ilo_error_cleaning(self):
self.node.clean_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.provision_state = states.CLEANING
self.node.save()
self._test_create_configuration_ilo_error()
def test_create_configuration_ilo_error_cleaning_deploying(self):
self.node.deploy_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.provision_state = states.DEPLOYING
self.node.save()
self._test_create_configuration_ilo_error()
@mock.patch.object(ilo_raid.Ilo5RAID, '_prepare_for_read_raid',
autospec=True)
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
def _test_delete_configuration(self, ilo_mock, prepare_raid_mock):
ilo_mock_object = ilo_mock.return_value
with task_manager.acquire(self.context, self.node.uuid) as task:
result = task.driver.raid.delete_configuration(task)
if task.node.clean_step:
self.assertEqual(states.CLEANWAIT, result)
else:
self.assertEqual(states.DEPLOYWAIT, result)
ilo_mock_object.delete_raid_configuration.assert_called_once_with()
prepare_raid_mock.assert_called_once_with(mock.ANY, task,
'delete_raid')
def test_delete_configuration_cleaning(self):
self.node.clean_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.save()
self._test_delete_configuration()
def test_delete_configuration_deploying(self):
self.node.deploy_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.save()
self._test_delete_configuration()
@mock.patch.object(ilo_raid.LOG, 'info', spec_set=True,
autospec=True)
@mock.patch.object(ilo_raid.Ilo5RAID, '_prepare_for_read_raid',
autospec=True)
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
def _test_delete_configuration_no_logical_drive(
self, ilo_mock, prepare_raid_mock, log_mock):
ilo_mock_object = ilo_mock.return_value
exc = ilo_error.IloLogicalDriveNotFoundError('No logical drive found')
with task_manager.acquire(self.context, self.node.uuid) as task:
ilo_mock_object.delete_raid_configuration.side_effect = exc
task.driver.raid.delete_configuration(task)
self.assertTrue(log_mock.called)
def test_delete_configuration_no_logical_drive_cleaning(self):
self.node.clean_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.save()
self._test_delete_configuration_no_logical_drive()
def test_delete_configuration_no_logical_drive_deploying(self):
self.node.deploy_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.save()
self._test_delete_configuration_no_logical_drive()
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
def _test_delete_configuration_with_read_raid(self, ilo_mock):
raid_conf = {u'logical_disks': []}
driver_internal_info = self.node.driver_internal_info
driver_internal_info['ilo_raid_delete_in_progress'] = True
driver_internal_info['skip_current_clean_step'] = False
self.node.driver_internal_info = driver_internal_info
self.node.save()
ilo_mock_object = ilo_mock.return_value
if self.node.clean_step:
skip_field_name = 'skip_current_clean_step'
else:
skip_field_name = 'skip_current_deploy_step'
with task_manager.acquire(self.context, self.node.uuid) as task:
ilo_mock_object.read_raid_configuration.return_value = raid_conf
task.driver.raid.delete_configuration(task)
self.assertEqual(self.node.raid_config, {})
self.assertNotIn('ilo_raid_delete_in_progress',
task.node.driver_internal_info)
self.assertNotIn(skip_field_name,
task.node.driver_internal_info)
def test_delete_configuration_with_read_raid_cleaning(self):
self.node.clean_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.save()
self._test_delete_configuration_with_read_raid()
def test_delete_configuration_with_read_raid_deploying(self):
self.node.deploy_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.save()
self._test_delete_configuration_with_read_raid()
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
def _test_delete_configuration_with_read_raid_failed(self, ilo_mock):
raid_conf = {u'logical_disks': [{'size_gb': 200,
'raid_level': 0,
'is_root_volume': True}]}
driver_internal_info = self.node.driver_internal_info
driver_internal_info['ilo_raid_delete_in_progress'] = True
driver_internal_info['skip_current_clean_step'] = False
self.node.driver_internal_info = driver_internal_info
self.node.save()
ilo_mock_object = ilo_mock.return_value
if self.node.clean_step:
exept = exception.NodeCleaningFailure
else:
exept = exception.InstanceDeployFailure
with task_manager.acquire(self.context, self.node.uuid) as task:
ilo_mock_object.read_raid_configuration.return_value = raid_conf
self.assertRaises(exept,
task.driver.raid.delete_configuration, task)
self.assertNotIn('ilo_raid_delete_in_progress',
task.node.driver_internal_info)
if task.node.clean_step:
self.assertNotIn('skip_current_clean_step',
task.node.driver_internal_info)
else:
self.assertNotIn('skip_current_deploy_step',
task.node.driver_internal_info)
def test_delete_configuration_with_read_raid_failed_cleaning(self):
self.node.clean_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.save()
self._test_delete_configuration_with_read_raid_failed()
def test_delete_configuration_with_read_raid_failed_deploying(self):
self.node.deploy_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.save()
self._test_delete_configuration_with_read_raid_failed()
@mock.patch.object(ilo_raid.Ilo5RAID, '_set_step_failed', autospec=True)
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
def _test_delete_configuration_ilo_error(self, ilo_mock,
set_step_failed_mock):
ilo_mock_object = ilo_mock.return_value
exc = ilo_error.IloError('error')
ilo_mock_object.delete_raid_configuration.side_effect = exc
with task_manager.acquire(self.context, self.node.uuid) as task:
task.driver.raid.delete_configuration(task)
ilo_mock_object.delete_raid_configuration.assert_called_once_with()
self.assertNotIn('ilo_raid_delete_in_progress',
task.node.driver_internal_info)
self.assertNotIn('cleaning_reboot',
task.node.driver_internal_info)
self.assertNotIn('skip_current_clean_step',
task.node.driver_internal_info)
set_step_failed_mock.assert_called_once_with(
mock.ANY,
task,
'Failed to delete raid configuration '
'on node %s' % self.node.uuid, exc)
def test_delete_configuration_ilo_error_cleaning(self):
self.node.clean_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.save()
self._test_delete_configuration_ilo_error()
def test_delete_configuration_ilo_error_deploying(self):
self.node.deploy_step = {'step': 'create_configuration',
'interface': 'raid'}
self.node.save()
self._test_delete_configuration_ilo_error()
@@ -1,168 +0,0 @@
# Copyright 2022 Hewlett Packard Enterprise Development LP
# Copyright 2015 Hewlett-Packard Development Company, L.P.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""Test class for vendor methods used by iLO modules."""
from unittest import mock
from ironic.common import exception
from ironic.common import states
from ironic.conductor import task_manager
from ironic.conductor import utils as manager_utils
from ironic.drivers.modules import deploy_utils
from ironic.drivers.modules.ilo import common as ilo_common
from ironic.drivers.modules.ilo import vendor as ilo_vendor
from ironic.tests.unit.drivers.modules.ilo import test_common
class VendorPassthruTestCase(test_common.BaseIloTest):
boot_interface = 'ilo-virtual-media'
vendor_interface = 'ilo'
@mock.patch.object(manager_utils, 'node_power_action', spec_set=True,
autospec=True)
@mock.patch.object(ilo_common, 'setup_vmedia', spec_set=True,
autospec=True)
def test_boot_into_iso(self, setup_vmedia_mock, power_action_mock):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.driver.vendor.boot_into_iso(task, boot_iso_href='foo')
setup_vmedia_mock.assert_called_once_with(task, 'foo',
ramdisk_options=None)
power_action_mock.assert_called_once_with(task, states.REBOOT)
@mock.patch.object(ilo_vendor.VendorPassthru, '_validate_boot_into_iso',
spec_set=True, autospec=True)
def test_validate_boot_into_iso(self, validate_boot_into_iso_mock):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
vendor = ilo_vendor.VendorPassthru()
vendor.validate(task, method='boot_into_iso', foo='bar')
validate_boot_into_iso_mock.assert_called_once_with(
vendor, task, {'foo': 'bar'})
def test__validate_boot_into_iso_invalid_state(self):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.node.provision_state = states.AVAILABLE
self.assertRaises(
exception.InvalidStateRequested,
task.driver.vendor._validate_boot_into_iso,
task, {})
def test__validate_boot_into_iso_missing_boot_iso_href(self):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.node.provision_state = states.MANAGEABLE
self.assertRaises(
exception.MissingParameterValue,
task.driver.vendor._validate_boot_into_iso,
task, {})
@mock.patch.object(deploy_utils, 'get_image_properties',
spec_set=True, autospec=True)
def test__validate_boot_into_iso_manage(self, validate_image_prop_mock):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
info = {'boot_iso_href': 'foo'}
task.node.provision_state = states.MANAGEABLE
task.driver.vendor._validate_boot_into_iso(
task, info)
validate_image_prop_mock.assert_called_once_with(
task.context, 'foo')
@mock.patch.object(deploy_utils, 'get_image_properties',
spec_set=True, autospec=True)
def test__validate_boot_into_iso_maintenance(
self, validate_image_prop_mock):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
info = {'boot_iso_href': 'foo'}
task.node.maintenance = True
task.driver.vendor._validate_boot_into_iso(
task, info)
validate_image_prop_mock.assert_called_once_with(
task.context, 'foo')
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
autospec=True)
def test__validate_is_it_a_supported_system(
self, get_ilo_object_mock):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.node.maintenance = True
ilo_mock_object = get_ilo_object_mock.return_value
ilo_mock_object.get_product_name.return_value = (
'ProLiant DL380 Gen10')
task.driver.vendor._validate_is_it_a_supported_system(task)
get_ilo_object_mock.assert_called_once_with(task.node)
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
autospec=True)
def test__validate_is_it_a_supported_system_exception(
self, get_ilo_object_mock):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.node.maintenance = True
ilo_mock_object = get_ilo_object_mock.return_value
ilo_mock_object.get_product_name.return_value = (
'ProLiant DL380 Gen8')
self.assertRaises(
exception.IloOperationNotSupported,
task.driver.vendor._validate_is_it_a_supported_system, task)
@mock.patch.object(ilo_common, 'parse_driver_info',
spec_set=True, autospec=True)
@mock.patch.object(ilo_common, 'update_redfish_properties',
spec_set=True, autospec=True)
@mock.patch.object(ilo_vendor.VendorPassthru,
'_validate_is_it_a_supported_system',
spec_set=True, autospec=True)
def test_validate_create_subscription(self, validate_redfish_system_mock,
redfish_properties_mock,
driver_info_mock):
self.node.vendor_interface = 'ilo'
self.node.save()
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
d_info = {'ilo_address': '1.1.1.1',
'ilo_username': 'user',
'ilo_password': 'password',
'ilo_verify_ca': False}
driver_info_mock.return_value = d_info
redfish_properties = {'redfish_address': '1.1.1.1',
'redfish_username': 'user',
'redfish_password': 'password',
'redfish_system_id': '/redfish/v1/Systems/1',
'redfish_verify_ca': False}
redfish_properties_mock.return_value = redfish_properties
kwargs = {'Destination': 'https://someulr',
'Context': 'MyProtocol'}
task.driver.vendor.validate(task, 'create_subscription', **kwargs)
driver_info_mock.assert_called_once_with(task.node)
redfish_properties_mock.assert_called_once_with(task)
validate_redfish_system_mock.assert_called_once_with(
task.driver.vendor, task)
def test_validate_operation_exeption(self):
self.node.vendor_interface = 'ilo'
self.node.save()
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
self.assertRaises(
exception.IloOperationNotSupported,
task.driver.vendor.validate, task, 'eject_vmedia')
@@ -931,11 +931,11 @@ class TrySetBootDeviceTestCase(db_base.DbTestCase):
@mock.patch.object(manager_utils, 'node_set_boot_device', autospec=True)
def test_try_set_boot_device_some_other_exception(
self, node_set_boot_device_mock):
exc = exception.IloOperationError(operation="qwe", error="error")
exc = exception.RedfishError(error="error")