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:
@@ -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 \
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
------------------------
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
-------------
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 -> 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"];
|
||||
}
|
||||
</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 -> 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"];
|
||||
}
|
||||
</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 |
@@ -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"];
|
||||
}
|
||||
@@ -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 -> 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"];
|
||||
}
|
||||
</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 |
@@ -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"];
|
||||
}
|
||||
@@ -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 -> 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"];
|
||||
}
|
||||
</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 |
@@ -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"];
|
||||
}
|
||||
@@ -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 -> 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"];
|
||||
}
|
||||
</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 |
@@ -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``:
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,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
|
||||
|
||||
|
||||
@@ -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 '
|
||||
|
||||
@@ -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),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -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')
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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')
|
||||
@@ -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),
|
||||
|
||||
@@ -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]
|
||||
@@ -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)
|
||||
@@ -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
@@ -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]
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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', [])
|
||||
|
||||
@@ -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")
|
||||