Switch contributor documentation to hardware types

Also write a bit more meaningful documentation on writing drivers with
helpful links to move forward.

Change-Id: Id76705efabaf93a76a1370bc2e1d998622e82ac9
Partial-Bug: #1690185
(cherry picked from commit 152f45c993)
This commit is contained in:
Dmitry Tantsur 2018-01-25 10:08:07 +01:00 committed by Julia Kreger
parent 6f5650233d
commit f15aaec4b2
7 changed files with 204 additions and 89 deletions

View File

@ -30,49 +30,10 @@ Drivers
The internal driver API provides a consistent interface between the
Conductor service and the driver implementations. A driver is defined by
a class inheriting from the `BaseDriver`_ class, defining certain interfaces;
each interface is an instance of the relevant driver module.
For example, a fake driver class might look like this::
class FakePower(base.PowerInterface):
def get_properties(self):
return {}
def validate(self, task):
pass
def get_power_state(self, task):
return states.NOSTATE
def set_power_state(self, task, power_state):
pass
def reboot(self, task):
pass
class FakeDriver(base.BaseDriver):
def __init__(self):
self.power = FakePower()
There are three categories of driver interfaces:
- `Core` interfaces provide the essential functionality for Ironic within
OpenStack, and may be depended upon by other services. All drivers
must implement these interfaces. The Core interfaces are `power` and `deploy`.
- `Standard` interfaces provide functionality beyond the needs of OpenStack,
but which have been standardized across all drivers and becomes part of
Ironic's API. If a driver implements this interface, it must adhere to the
standard. This is presented to encourage vendors to work together with the
Ironic project and implement common features in a consistent way, thus
reducing the burden on consumers of the API. The Standard interfaces are
`management`, `console`, `boot`, `inspect`, and `raid`.
- The `Vendor` interface allows an exemption to the API contract when a vendor
wishes to expose unique functionality provided by their hardware and is
unable to do so within the `Core` or `Standard` interfaces. In this case,
Ironic will merely relay the message from the API service to the appropriate
driver.
a *hardware type* deriving from the AbstractHardwareType_ class, defining
supported *hardware interfaces*. See :doc:`/install/enabling-drivers`
for a more detailed explanation. See :doc:`drivers` for an explanation on how
to write new hardware types and interfaces.
Driver-Specific Periodic Tasks
------------------------------
@ -113,7 +74,7 @@ driver actions such as take-over or clean-up.
.. _API service: webapi.html
.. _BaseDriver: api/ironic.drivers.base.html#ironic.drivers.base.BaseDriver
.. _AbstractHardwareType: api/ironic.drivers.hardware_type.html#ironic.drivers.hardware_type.AbstractHardwareType
.. _Conductor service: api/ironic.conductor.manager.html
.. _DB API: api/ironic.db.api.html
.. _diskimage-builder: https://docs.openstack.org/diskimage-builder/latest/

View File

@ -270,14 +270,25 @@ want to run a MySQL server on it all the time).
#. Create a configuration file within the ironic source directory::
# generate a sample config
tox -egenconfig
# copy sample config and modify it as necessary
cp etc/ironic/ironic.conf.sample etc/ironic/ironic.conf.local
# disable auth since we are not running keystone here
sed -i "s/#auth_strategy = keystone/auth_strategy = noauth/" etc/ironic/ironic.conf.local
# Use the 'fake_ipmitool' test driver
sed -i "s/#enabled_drivers = pxe_ipmitool/enabled_drivers = fake_ipmitool/" etc/ironic/ironic.conf.local
# use the 'fake-hardware' test hardware type
sed -i "s/#enabled_hardware_types = .*/enabled_hardware_types = fake-hardware/" etc/ironic/ironic.conf.local
# use the 'fake' deploy and boot interfaces
sed -i "s/#enabled_deploy_interfaces = .*/enabled_deploy_interfaces = fake/" etc/ironic/ironic.conf.local
sed -i "s/#enabled_boot_interfaces = .*/enabled_boot_interfaces = fake/" etc/ironic/ironic.conf.local
# enable both fake and ipmitool management and power interfaces
sed -i "s/#enabled_management_interfaces = .*/enabled_management_interfaces = fake,ipmitool/" etc/ironic/ironic.conf.local
sed -i "s/#enabled_power_interfaces = .*/enabled_power_interfaces = fake,ipmitool/" etc/ironic/ironic.conf.local
# set a fake host name [useful if you want to test multiple services on the same host]
sed -i "s/#host = .*/host = test-host/" etc/ironic/ironic.conf.local
@ -321,7 +332,14 @@ present in the python virtualenv, and observe both services' debug outputs in
the other two windows. This is a good way to test new features or play with the
functionality without necessarily starting DevStack.
To get started, list the available commands and resources::
To get started, export the following variables to point the client at the
local instance of ironic and disable the authentication::
export OS_AUTH_TYPE=token_endpoint
export OS_TOKEN=fake
export OS_ENDPOINT=http://127.0.0.1:6385
Then list the available commands and resources::
# get a list of available commands
openstack help baremetal
@ -339,10 +357,13 @@ Here is an example walkthrough of creating a node::
IPMI_USER="admin" # replace with the BMC's user name
IPMI_PASS="pass" # replace with the BMC's password
# enroll the node with the "fake" deploy driver and the "ipmitool" power driver
# Note that driver info may be added at node creation time with "--driver-info"
# enroll the node with the fake hardware type and IPMI-based power and
# management interfaces. Note that driver info may be added at node
# creation time with "--driver-info"
NODE=$(openstack baremetal node create \
--driver fake_ipmitool \
--driver fake-hardware \
--management-interface ipmitool \
--power-interface ipmitool \
--driver-info ipmi_address=$IPMI_ADDR \
--driver-info ipmi_username=$IPMI_USER \
-f value -c uuid)
@ -429,10 +450,9 @@ Switch to the stack user and clone DevStack::
git clone https://git.openstack.org/openstack-dev/devstack.git devstack
Create devstack/local.conf with minimal settings required to enable Ironic.
You can use either of two drivers for deploy: agent\_\* or pxe\_\*, see
:doc:`/admin/interfaces/deploy` for explanation. An example local.conf that
enables both types of drivers and uses the ``agent_ipmitool`` driver
by default::
An example local.conf that enables both ``direct`` and ``iscsi``
:doc:`deploy interfaces </admin/interfaces/deploy>` and uses the ``ipmi``
hardware type by default::
cd devstack
cat >local.conf <<END
@ -452,7 +472,7 @@ by default::
# Disable nova novnc service, ironic does not support it anyway.
disable_service n-novnc
# Enable Swift for agent_* drivers
# Enable Swift for the direct deploy interface.
enable_service s-proxy
enable_service s-object
enable_service s-container
@ -464,7 +484,7 @@ by default::
# Disable Cinder
disable_service cinder c-sch c-api c-vol
# Swift temp URL's are required for agent_* drivers.
# Swift temp URL's are required for the direct deploy interface
SWIFT_ENABLE_TEMPURLS=True
# Create 3 virtual machines to pose as Ironic's baremetal nodes.
@ -472,12 +492,19 @@ by default::
IRONIC_BAREMETAL_BASIC_OPS=True
DEFAULT_INSTANCE_TYPE=baremetal
# Enable Ironic drivers.
IRONIC_ENABLED_DRIVERS=fake,agent_ipmitool,pxe_ipmitool
# Enable additional hardware types, if needed.
#IRONIC_ENABLED_HARDWARE_TYPES=ipmi,fake-hardware
# Don't forget that many hardware types require enabling of additional
# interfaces, most often power and management:
#IRONIC_ENABLED_MANAGEMENT_INTERFACES=ipmitool,fake
#IRONIC_ENABLED_POWER_INTERFACES=ipmitool,fake
# The 'ipmi' hardware type's default deploy interface is 'iscsi'.
# This would change the default to 'direct':
#IRONIC_DEFAULT_DEPLOY_INTERFACE=direct
# Change this to alter the default driver for nodes created by devstack.
# This driver should be in the enabled list above.
IRONIC_DEPLOY_DRIVER=agent_ipmitool
IRONIC_DEPLOY_DRIVER=ipmi
# The parameters below represent the minimum possible values to create
# functional nodes.
@ -518,9 +545,10 @@ by default::
enable_plugin ironic https://git.openstack.org/openstack/ironic
.. note::
When a \*_ipmitool driver is set and IRONIC_IS_HARDWARE variable is false devstack
will automatically set up `VirtualBMC <https://github.com/openstack/virtualbmc>`_
to control the power state of the virtual baremetal nodes.
When the ``ipmi`` hardware type is used and IRONIC_IS_HARDWARE variable is
``false`` devstack will automatically set up `VirtualBMC
<https://github.com/openstack/virtualbmc>`_ to control the power state of
the virtual baremetal nodes.
.. note::
When running QEMU as non-root user (e.g. ``qemu`` on Fedora or ``libvirt-qemu`` on Ubuntu),

View File

@ -6,23 +6,115 @@ Pluggable Drivers
Ironic supports a pluggable driver model. This allows contributors to easily
add new drivers, and operators to use third-party drivers or write their own.
A driver is built at runtime from a *hardware type* and *hardware interfaces*.
See :doc:`/install/enabling-drivers` for a detailed explanation of these
concepts.
Drivers are loaded by the ironic-conductor service during initialization, by
enumerating the python entrypoint "ironic.drivers" and attempting to load
all drivers specified in the "enabled_drivers" configuration option. A
complete list of drivers available on the system may be found by
Hardware types and interfaces are loaded by the ``ironic-conductor`` service
during initialization from the setuptools entrypoints ``ironic.hardware.types``
and ``ironic.hardware.interfaces.<INTERFACE>`` where ``<INTERFACE>`` is an
interface type (for example, ``deploy``). Only hardware types listed in the
configuration option ``enabled_hardware_types`` and interfaces listed in
configuration options ``enabled_<INTERFACE>_interfaces`` are loaded.
A complete list of hardware types available on the system may be found by
enumerating this entrypoint by running the following python script::
#!/usr/bin/env python
import pkg_resources as pkg
print [p.name for p in pkg.iter_entry_points("ironic.drivers") if not p.name.startswith("fake")]
print [p.name for p in pkg.iter_entry_points("ironic.hardware.types") if not p.name.startswith("fake")]
A list of drivers enabled in a running Ironic service may be found by issuing
the following command against that API end point::
openstack baremetal driver list
.. note::
This listing also includes *classic drivers* which are deprecated and
are not covered by this guide.
Writing a hardware type
-----------------------
A hardware type is a Python class, inheriting
:py:class:`ironic.drivers.hardware_type.AbstractHardwareType` and listed in
the setuptools entry point ``ironic.hardware.types``. Most of the real world
hardware types inherit :py:class:`ironic.drivers.generic.GenericHardware`
instead. This helper class provides useful implementations for interfaces that
are usually the same for all hardware types, such as ``deploy``.
The minimum required interfaces are:
* :doc:`boot </admin/interfaces/boot>` that specifies how to boot ramdisks and
instances on the hardware. A generic ``pxe`` implementation is provided
by the ``GenericHardware`` base class.
* :doc:`deploy </admin/interfaces/deploy>` that orchestrates the deployment.
A few common implementations are provided by the ``GenericHardware`` base
class.
.. note::
Most of the hardware types should not override this interface.
* `power` implements power actions for the hardware. These common
implementations may be used, if supported by the hardware:
* :py:class:`ironic.drivers.modules.ipmitool.IPMIPower`
* :py:class:`ironic.drivers.modules.redfish.power.RedfishPower`
Otherwise, you need to write your own implementation by subclassing
:py:class:`ironic.drivers.base.PowerInterface` and providing missing methods.
.. note::
Power actions in Ironic are blocking - methods of a power interface should
not return until the power action is finished or errors out.
* `management` implements additional out-of-band management actions, such as
setting a boot device. A few common implementations exist and may be used,
if supported by the hardware:
* :py:class:`ironic.drivers.modules.ipmitool.IPMIManagement`
* :py:class:`ironic.drivers.modules.redfish.management.RedfishManagement`
Some hardware types, such as ``snmp`` do not support out-of-band management.
They use the fake implementation in
:py:class:`ironic.drivers.modules.fake.FakeManagement` instead.
Otherwise, you need to write your own implementation by subclassing
:py:class:`ironic.drivers.base.ManagementInterface` and providing missing
methods.
Combine the interfaces in a hardware type by populating the lists of
supported interfaces. These lists are prioritized, with the most preferred
implementation first. For example:
.. code-block:: python
class MyHardware(generic.GenericHardware):
@property
def supported_management_interfaces(self):
"""List of supported management interfaces."""
return [MyManagement, ipmitool.IPMIManagement]
@property
def supported_power_interfaces(self):
"""List of supported power interfaces."""
return [MyPower, ipmitool.IPMIPower]
.. note::
In this example, all interfaces, except for ``management`` and ``power``
are taken from the ``GenericHardware`` base class.
Finally, give the new hardware type and new interfaces human-friendly names and
create entry points for them in the ``setup.cfg`` file::
ironic.hardware.types =
my-hardware = ironic.drivers.my_hardware:MyHardware
ironic.hardware.interfaces.power =
my-power = ironic.drivers.modules.my_hardware:MyPower
ironic.hardware.interfaces.management =
my-management = ironic.drivers.modules.my_hardware:MyManagement
Supported Drivers
-----------------

View File

@ -61,7 +61,6 @@ the developer community about any implementation using this functionality.
:maxdepth: 1
Driver Overview <drivers>
Driver Base Class Definition <api/ironic.drivers.base>
Writing "vendor_passthru" methods <vendor-passthru>
Third party continuous integration testing <third-party-ci>

View File

@ -43,7 +43,7 @@ description for DevStack is at :ref:`deploy_devstack`.
enable_service q-meta
enable_service neutron
# Enable Swift for agent_* drivers
# Enable Swift for the direct deploy interface.
enable_service s-proxy
enable_service s-object
enable_service s-container
@ -55,7 +55,7 @@ description for DevStack is at :ref:`deploy_devstack`.
# Disable Heat
disable_service heat h-api h-api-cfn h-api-cw h-eng
# Swift temp URL's are required for agent_* drivers.
# Swift temp URL's are required for the direct deploy interface.
SWIFT_ENABLE_TEMPURLS=True
# Create 3 virtual machines to pose as Ironic's baremetal nodes.
@ -63,12 +63,18 @@ description for DevStack is at :ref:`deploy_devstack`.
IRONIC_BAREMETAL_BASIC_OPS=True
DEFAULT_INSTANCE_TYPE=baremetal
# Enable Ironic drivers.
IRONIC_ENABLED_DRIVERS=fake,agent_ipmitool,pxe_ipmitool
# Enable additional hardware types, if needed.
#IRONIC_ENABLED_HARDWARE_TYPES=ipmi,fake-hardware
# Don't forget that many hardware types require enabling of additional
# interfaces, most often power and management:
#IRONIC_ENABLED_MANAGEMENT_INTERFACES=ipmitool,fake
#IRONIC_ENABLED_POWER_INTERFACES=ipmitool,fake
# The default deploy interface is 'iscsi', you can use 'direct' with
#IRONIC_DEFAULT_DEPLOY_INTERFACE=direct
# Change this to alter the default driver for nodes created by devstack.
# This driver should be in the enabled list above.
IRONIC_DEPLOY_DRIVER=agent_ipmitool
IRONIC_DEPLOY_DRIVER=ipmi
# The parameters below represent the minimum possible values to create
# functional nodes.

View File

@ -68,7 +68,7 @@ configured in Neutron.
# Disable nova novnc service, ironic does not support it anyway.
disable_service n-novnc
# Enable Swift for agent_* drivers
# Enable Swift for the direct deploy interface.
enable_service s-proxy
enable_service s-object
enable_service s-container
@ -83,19 +83,25 @@ configured in Neutron.
# Disable Tempest
disable_service tempest
# Swift temp URL's are required for agent_* drivers.
# Swift temp URL's are required for the direct deploy interface.
SWIFT_ENABLE_TEMPURLS=True
# Create 3 virtual machines to pose as Ironic's baremetal nodes.
IRONIC_VM_COUNT=3
IRONIC_BAREMETAL_BASIC_OPS=True
# Enable Ironic drivers.
IRONIC_ENABLED_DRIVERS=fake,agent_ipmitool,pxe_ipmitool
# Enable additional hardware types, if needed.
#IRONIC_ENABLED_HARDWARE_TYPES=ipmi,fake-hardware
# Don't forget that many hardware types require enabling of additional
# interfaces, most often power and management:
#IRONIC_ENABLED_MANAGEMENT_INTERFACES=ipmitool,fake
#IRONIC_ENABLED_POWER_INTERFACES=ipmitool,fake
# The default deploy interface is 'iscsi', you can use 'direct' with
#IRONIC_DEFAULT_DEPLOY_INTERFACE=direct
# Change this to alter the default driver for nodes created by devstack.
# This driver should be in the enabled list above.
IRONIC_DEPLOY_DRIVER=agent_ipmitool
IRONIC_DEPLOY_DRIVER=ipmi
# The parameters below represent the minimum possible values to create
# functional nodes.

View File

@ -10,25 +10,30 @@ a driver.
The first thing to note is that the Ironic API supports two vendor
endpoints: A driver vendor passthru and a node vendor passthru.
* The driver vendor passthru allows drivers to expose a custom top-level
* The ``VendorInterface`` allows hardware types to expose a custom top-level
functionality which is not specific to a Node. For example, let's say
the driver `pxe_ipmitool` exposed a method called `authentication_types`
the driver `ipmi` exposed a method called `authentication_types`
that would return what are the authentication types supported. It could
be accessed via the Ironic API like:
::
::
GET http://<address>:<port>/v1/drivers/pxe_ipmitool/vendor_passthru/authentication_types
GET http://<address>:<port>/v1/drivers/ipmi/vendor_passthru/authentication_types
.. warning::
The Bare Metal API currently only allows to use driver passthru for the
default ``vendor`` interface implementation for a given hardware type.
This limitation will be lifted in the future.
* The node vendor passthru allows drivers to expose custom functionality
on per-node basis. For example the same driver `pxe_ipmitool` exposing a
on per-node basis. For example the same driver `ipmi` exposing a
method called `send_raw` that would send raw bytes to the BMC, the method
also receives a parameter called `raw_bytes` which the value would be
the bytes to be sent. It could be accessed via the Ironic API like:
::
::
POST {'raw_bytes': '0x01 0x02'} http://<address>:<port>/v1/nodes/<node UUID>/vendor_passthru/send_raw
POST {'raw_bytes': '0x01 0x02'} http://<address>:<port>/v1/nodes/<node UUID>/vendor_passthru/send_raw
Writing Vendor Methods
@ -106,11 +111,11 @@ Both decorators accept these parameters:
if you want to use a different name this parameter is where this name
can be set. For example:
.. code-block:: python
.. code-block:: python
@passthru(['PUT'], method="alternative_name")
def name(self, task, **kwargs):
...
@passthru(['PUT'], method="alternative_name")
def name(self, task, **kwargs):
...
* description: A string containing a nice description about what that
method is supposed to do. Defaults to "" (empty string).
@ -138,6 +143,24 @@ parameter:
``ironic-conductor`` process. This can lead to starvation of the
thread pool, resulting in a denial of service.
Give the new vendor interface implementation a human-friendly name and create
an entry point for it in the ``setup.cfg``::
ironic.hardware.interfaces.vendor =
example = ironic.drivers.modules.example:ExampleVendor
Finally, add it to the list of supported vendor interfaces for relevant
hardware types, for example:
.. code-block:: python
class ExampleHardware(generic.GenericHardware):
...
@property
def supported_vendor_interfaces(self):
return [example.ExampleVendor]
Backwards Compatibility
=======================