diff --git a/doc/source/contributor/architecture.rst b/doc/source/contributor/architecture.rst index 8f3f3543d4..0a27435e5f 100644 --- a/doc/source/contributor/architecture.rst +++ b/doc/source/contributor/architecture.rst @@ -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/ diff --git a/doc/source/contributor/dev-quickstart.rst b/doc/source/contributor/dev-quickstart.rst index f97eee5b79..b8eac635ce 100644 --- a/doc/source/contributor/dev-quickstart.rst +++ b/doc/source/contributor/dev-quickstart.rst @@ -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 ` and uses the ``ipmi`` +hardware type by default:: cd devstack cat >local.conf <`_ - 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 + `_ 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), diff --git a/doc/source/contributor/drivers.rst b/doc/source/contributor/drivers.rst index a6f524b697..93f5e95a32 100644 --- a/doc/source/contributor/drivers.rst +++ b/doc/source/contributor/drivers.rst @@ -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.`` where ```` 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__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 ` that specifies how to boot ramdisks and + instances on the hardware. A generic ``pxe`` implementation is provided + by the ``GenericHardware`` base class. + +* :doc:`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 ----------------- diff --git a/doc/source/contributor/index.rst b/doc/source/contributor/index.rst index 572f4fa12d..94a347be39 100644 --- a/doc/source/contributor/index.rst +++ b/doc/source/contributor/index.rst @@ -61,7 +61,6 @@ the developer community about any implementation using this functionality. :maxdepth: 1 Driver Overview - Driver Base Class Definition Writing "vendor_passthru" methods Third party continuous integration testing diff --git a/doc/source/contributor/ironic-boot-from-volume.rst b/doc/source/contributor/ironic-boot-from-volume.rst index 22037a98b5..b168e404e1 100644 --- a/doc/source/contributor/ironic-boot-from-volume.rst +++ b/doc/source/contributor/ironic-boot-from-volume.rst @@ -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. diff --git a/doc/source/contributor/ironic-multitenant-networking.rst b/doc/source/contributor/ironic-multitenant-networking.rst index 60e40f4565..64ebb81f07 100644 --- a/doc/source/contributor/ironic-multitenant-networking.rst +++ b/doc/source/contributor/ironic-multitenant-networking.rst @@ -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. diff --git a/doc/source/contributor/vendor-passthru.rst b/doc/source/contributor/vendor-passthru.rst index 90eb044040..538b668f19 100644 --- a/doc/source/contributor/vendor-passthru.rst +++ b/doc/source/contributor/vendor-passthru.rst @@ -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://
:/v1/drivers/pxe_ipmitool/vendor_passthru/authentication_types + GET http://
:/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://
:/v1/nodes//vendor_passthru/send_raw + POST {'raw_bytes': '0x01 0x02'} http://
:/v1/nodes//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 =======================