Generate Sphinx docs
Change-Id: I540b28d6173b30baf6ee2e6e14d8ba5ffb67b660 Closes-Bug: #1514803
This commit is contained in:
parent
f5671a4376
commit
292e8c9cfd
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
# Sphinx
|
# Sphinx
|
||||||
_build
|
_build
|
||||||
doc/source/api/
|
#doc/source/api/
|
||||||
|
|
||||||
# release notes build
|
# release notes build
|
||||||
releasenotes/build
|
releasenotes/build
|
||||||
|
|
540
README.rst
540
README.rst
|
@ -24,6 +24,9 @@ Refer to CONTRIBUTING.rst_ for instructions on how to contribute.
|
||||||
.. _Ironic: https://wiki.openstack.org/wiki/Ironic
|
.. _Ironic: https://wiki.openstack.org/wiki/Ironic
|
||||||
.. _PyPI: https://pypi.python.org/pypi/ironic-inspector
|
.. _PyPI: https://pypi.python.org/pypi/ironic-inspector
|
||||||
.. _CONTRIBUTING.rst: https://github.com/openstack/ironic-inspector/blob/master/CONTRIBUTING.rst
|
.. _CONTRIBUTING.rst: https://github.com/openstack/ironic-inspector/blob/master/CONTRIBUTING.rst
|
||||||
|
.. _diskimage-builder: https://github.com/openstack/diskimage-builder
|
||||||
|
.. _ironic-discoverd-ramdisk element: https://github.com/openstack/diskimage-builder/tree/master/elements/ironic-discoverd-ramdisk
|
||||||
|
.. _Configuration: https://github.com/openstack/ironic-inspector/blob/master/doc/source/install-guide.rst
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
**ironic-inspector** was called *ironic-discoverd* before version 2.0.0.
|
**ironic-inspector** was called *ironic-discoverd* before version 2.0.0.
|
||||||
|
@ -66,7 +69,7 @@ Usual hardware introspection flow is as follows:
|
||||||
Power management credentials should be provided to Ironic at this step.
|
Power management credentials should be provided to Ironic at this step.
|
||||||
|
|
||||||
* Nodes are put in the correct state for introspection as described in
|
* Nodes are put in the correct state for introspection as described in
|
||||||
`Node States`_.
|
:ref:`node_states`.
|
||||||
|
|
||||||
* Operator sends nodes on introspection using **ironic-inspector** API or CLI
|
* Operator sends nodes on introspection using **ironic-inspector** API or CLI
|
||||||
(see Usage_).
|
(see Usage_).
|
||||||
|
@ -110,543 +113,12 @@ Usual hardware introspection flow is as follows:
|
||||||
for a given node.
|
for a given node.
|
||||||
|
|
||||||
* Nodes are put in the correct state for deploying as described in
|
* Nodes are put in the correct state for deploying as described in
|
||||||
`Node States`_.
|
:ref:`node_states`.
|
||||||
|
|
||||||
Starting DHCP server and configuring PXE boot environment is not part of this
|
Starting DHCP server and configuring PXE boot environment is not part of this
|
||||||
package and should be done separately.
|
package and should be done separately.
|
||||||
|
|
||||||
.. _instack-undercloud: https://www.rdoproject.org/Deploying_an_RDO_Undercloud_with_Instack
|
.. _instack-undercloud: https://www.rdoproject.org/Deploying_an_RDO_Undercloud_with_Instack
|
||||||
.. _Ironic inspection documentation: http://docs.openstack.org/developer/ironic/deploy/install-guide.html#hardware-inspection
|
.. _Ironic inspection documentation: http://docs.openstack.org/developer/ironic/deploy/install-guide.html#hardware-inspection
|
||||||
|
.. _Usage: https://github.com/openstack/ironic-inspector/blob/master/doc/source/usage.rst
|
||||||
|
|
||||||
Installation
|
|
||||||
------------
|
|
||||||
|
|
||||||
Install from PyPI_ (you may want to use virtualenv to isolate your
|
|
||||||
environment)::
|
|
||||||
|
|
||||||
pip install ironic-inspector
|
|
||||||
|
|
||||||
Also there is a `DevStack <http://docs.openstack.org/developer/devstack/>`_
|
|
||||||
plugin for **ironic-inspector** - see CONTRIBUTING.rst_ for the current status.
|
|
||||||
|
|
||||||
Finally, some distributions (e.g. Fedora) provide **ironic-inspector**
|
|
||||||
packaged, some of them - under its old name *ironic-discoverd*.
|
|
||||||
|
|
||||||
Configuration
|
|
||||||
~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Copy ``example.conf`` to some permanent place
|
|
||||||
(e.g. ``/etc/ironic-inspector/inspector.conf``).
|
|
||||||
Fill in at least these configuration values:
|
|
||||||
|
|
||||||
* ``os_username``, ``os_password``, ``os_tenant_name`` - Keystone credentials
|
|
||||||
to use when accessing other services and check client authentication tokens;
|
|
||||||
|
|
||||||
* ``os_auth_url``, ``identity_uri`` - Keystone endpoints for validating
|
|
||||||
authentication tokens and checking user roles;
|
|
||||||
|
|
||||||
* ``connection`` in the ``database`` section - SQLAlchemy connection string
|
|
||||||
for the database;
|
|
||||||
|
|
||||||
* ``dnsmasq_interface`` - interface on which ``dnsmasq`` (or another DHCP
|
|
||||||
service) listens for PXE boot requests (defaults to ``br-ctlplane`` which is
|
|
||||||
a sane default for TripleO-based installations but is unlikely to work for
|
|
||||||
other cases).
|
|
||||||
|
|
||||||
See comments inside `example.conf
|
|
||||||
<https://github.com/openstack/ironic-inspector/blob/master/example.conf>`_
|
|
||||||
for the other possible configuration options.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
Configuration file contains a password and thus should be owned by ``root``
|
|
||||||
and should have access rights like ``0600``.
|
|
||||||
|
|
||||||
**ironic-inspector** requires root rights for managing iptables. It gets them
|
|
||||||
by running ``ironic-inspector-rootwrap`` utility with ``sudo``.
|
|
||||||
To allow it, copy file ``rootwrap.conf`` and directory ``rootwrap.d`` to the
|
|
||||||
configuration directory (e.g. ``/etc/ironic-inspector/``) and create file
|
|
||||||
``/etc/sudoers.d/ironic-inspector-rootwrap`` with the following content::
|
|
||||||
|
|
||||||
stack ALL=(root) NOPASSWD: /usr/bin/ironic-inspector-rootwrap /etc/ironic-inspector/rootwrap.conf *
|
|
||||||
|
|
||||||
.. DANGER::
|
|
||||||
Be very careful about typos in ``/etc/sudoers.d/ironic-inspector-rootwrap``
|
|
||||||
as any typo will break sudo for **ALL** users on the system. Especially,
|
|
||||||
make sure there is a new line at the end of this file.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
``rootwrap.conf`` and all files in ``rootwrap.d`` must be writeable
|
|
||||||
only by root.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
If you store ``rootwrap.d`` in a different location, make sure to update
|
|
||||||
the *filters_path* option in ``rootwrap.conf`` to reflect the change.
|
|
||||||
|
|
||||||
If your ``rootwrap.conf`` is in a different location, then you need
|
|
||||||
to update the *rootwrap_config* option in ``ironic-inspector.conf``
|
|
||||||
to point to that location.
|
|
||||||
|
|
||||||
Replace ``stack`` with whatever user you'll be using to run
|
|
||||||
**ironic-inspector**.
|
|
||||||
|
|
||||||
Configuring PXE
|
|
||||||
^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
As for PXE boot environment, you'll need:
|
|
||||||
|
|
||||||
* TFTP server running and accessible (see below for using *dnsmasq*).
|
|
||||||
Ensure ``pxelinux.0`` is present in the TFTP root.
|
|
||||||
|
|
||||||
|
|
||||||
* You need PXE boot server (e.g. *dnsmasq*) running on **the same** machine as
|
|
||||||
**ironic-inspector**. Don't do any firewall configuration:
|
|
||||||
**ironic-inspector** will handle it for you. In **ironic-inspector**
|
|
||||||
configuration file set ``dnsmasq_interface`` to the interface your
|
|
||||||
PXE boot server listens on. Here is an example *dnsmasq.conf*::
|
|
||||||
|
|
||||||
port=0
|
|
||||||
interface={INTERFACE}
|
|
||||||
bind-interfaces
|
|
||||||
dhcp-range={DHCP IP RANGE, e.g. 192.168.0.50,192.168.0.150}
|
|
||||||
enable-tftp
|
|
||||||
tftp-root={TFTP ROOT, e.g. /tftpboot}
|
|
||||||
dhcp-boot=pxelinux.0
|
|
||||||
|
|
||||||
* You have to install and configure one of 2 available ramdisks: simple
|
|
||||||
bash-based (see `Using simple ramdisk`_) or more complex based on
|
|
||||||
ironic-python-agent_ (See `Using IPA`_).
|
|
||||||
|
|
||||||
Here is *inspector.conf* you may end up with::
|
|
||||||
|
|
||||||
[DEFAULT]
|
|
||||||
debug = false
|
|
||||||
[ironic]
|
|
||||||
identity_uri = http://127.0.0.1:35357
|
|
||||||
os_auth_url = http://127.0.0.1:5000/v2.0
|
|
||||||
os_username = admin
|
|
||||||
os_password = password
|
|
||||||
os_tenant_name = admin
|
|
||||||
[firewall]
|
|
||||||
dnsmasq_interface = br-ctlplane
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
Set ``debug = true`` if you want to see complete logs.
|
|
||||||
|
|
||||||
Using simple ramdisk
|
|
||||||
^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
* Build and put into your TFTP the kernel and ramdisk created using the
|
|
||||||
diskimage-builder_ `ironic-discoverd-ramdisk element`_::
|
|
||||||
|
|
||||||
ramdisk-image-create -o discovery fedora ironic-discoverd-ramdisk
|
|
||||||
|
|
||||||
You need diskimage-builder_ 0.1.38 or newer to do it (using the latest one
|
|
||||||
is always advised).
|
|
||||||
|
|
||||||
* Configure your ``$TFTPROOT/pxelinux.cfg/default`` with something like::
|
|
||||||
|
|
||||||
default introspect
|
|
||||||
|
|
||||||
label introspect
|
|
||||||
kernel discovery.kernel
|
|
||||||
append initrd=discovery.initramfs discoverd_callback_url=http://{IP}:5050/v1/continue
|
|
||||||
|
|
||||||
ipappend 3
|
|
||||||
|
|
||||||
Replace ``{IP}`` with IP of the machine (do not use loopback interface, it
|
|
||||||
will be accessed by ramdisk on a booting machine).
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
There are some prebuilt images which use obsolete ``ironic_callback_url``
|
|
||||||
instead of ``discoverd_callback_url``. Modify ``pxelinux.cfg/default``
|
|
||||||
accordingly if you have one of these.
|
|
||||||
|
|
||||||
Using IPA
|
|
||||||
^^^^^^^^^
|
|
||||||
|
|
||||||
ironic-python-agent_ is a new ramdisk developed for Ironic. During the Liberty
|
|
||||||
cycle support for **ironic-inspector** was added. This is experimental
|
|
||||||
for now, but we plan on making IPA the default ramdisk in Mitaka cycle.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
You need at least 1.5 GiB of RAM on the machines to use this ramdisk.
|
|
||||||
|
|
||||||
To build an ironic-python-agent ramdisk, do the following:
|
|
||||||
|
|
||||||
* Get the latest diskimage-builder_::
|
|
||||||
|
|
||||||
sudo pip install -U "diskimage-builder>=1.1.2"
|
|
||||||
|
|
||||||
* Build the ramdisk::
|
|
||||||
|
|
||||||
disk-image-create ironic-agent fedora -o ironic-agent
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
Replace "fedora" with your distribution of choice.
|
|
||||||
|
|
||||||
* Copy resulting files ``ironic-agent.vmlinuz`` and ``ironic-agent.initramfs``
|
|
||||||
to the TFTP root directory.
|
|
||||||
|
|
||||||
Next, set up ``$TFTPROOT/pxelinux.cfg/default`` as follows::
|
|
||||||
|
|
||||||
default introspect
|
|
||||||
|
|
||||||
label introspect
|
|
||||||
kernel ironic-agent.vmlinuz
|
|
||||||
append initrd=ironic-agent.initramfs ipa-inspection-callback-url=http://{IP}:5050/v1/continue systemd.journald.forward_to_console=yes
|
|
||||||
|
|
||||||
ipappend 3
|
|
||||||
|
|
||||||
Replace ``{IP}`` with IP of the machine (do not use loopback interface, it
|
|
||||||
will be accessed by ramdisk on a booting machine).
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
While ``systemd.journald.forward_to_console=yes`` is not actually
|
|
||||||
required, it will substantially simplify debugging if something goes wrong.
|
|
||||||
|
|
||||||
.. _diskimage-builder: https://github.com/openstack/diskimage-builder
|
|
||||||
.. _ironic-discoverd-ramdisk element: https://github.com/openstack/diskimage-builder/tree/master/elements/ironic-discoverd-ramdisk
|
|
||||||
.. _ironic-python-agent: https://github.com/openstack/ironic-python-agent
|
|
||||||
|
|
||||||
Managing the **ironic-inspector** database
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
**ironic-inspector** provides a command line client for managing its database,
|
|
||||||
this client can be used for upgrading, and downgrading the database using
|
|
||||||
alembic migrations.
|
|
||||||
|
|
||||||
If this is your first time running **ironic-inspector** to migrate the
|
|
||||||
database simply run:
|
|
||||||
::
|
|
||||||
|
|
||||||
ironic-inspector-dbsync --config-file /etc/ironic-inspector/inspector.conf upgrade
|
|
||||||
|
|
||||||
If you have previously run a version of **ironic-inspector** earlier than
|
|
||||||
2.2.0, the safest thing is to delete the existing SQLite database and run
|
|
||||||
``upgrade`` as shown above. If you, however, want to save the existing
|
|
||||||
database, to ensure your database will work with the migrations, you'll need to
|
|
||||||
run an extra step before upgrading the database. You only need to do this the
|
|
||||||
first time running version 2.2.0 or later.
|
|
||||||
|
|
||||||
If you are upgrading from **ironic-inspector** version 2.1.0 or lower:
|
|
||||||
::
|
|
||||||
|
|
||||||
ironic-inspector-dbsync --config-file /etc/ironic-inspector/inspector.conf stamp --revision 578f84f38d
|
|
||||||
ironic-inspector-dbsync --config-file /etc/ironic-inspector/inspector.conf upgrade
|
|
||||||
|
|
||||||
If you are upgrading from a git master install of **ironic-inspector** from
|
|
||||||
after `Introspection Rules`_ were introduced:
|
|
||||||
::
|
|
||||||
|
|
||||||
ironic-inspector-dbsync --config-file /etc/ironic-inspector/inspector.conf stamp --revision d588418040d
|
|
||||||
ironic-inspector-dbsync --config-file /etc/ironic-inspector/inspector.conf upgrade
|
|
||||||
|
|
||||||
Other available commands can be discovered by running::
|
|
||||||
|
|
||||||
ironic-inspector-dbsync --help
|
|
||||||
|
|
||||||
Running
|
|
||||||
~~~~~~~
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
ironic-inspector --config-file /etc/ironic-inspector/inspector.conf
|
|
||||||
|
|
||||||
A good starting point for writing your own *systemd* unit should be `one used
|
|
||||||
in Fedora <http://pkgs.fedoraproject.org/cgit/openstack-ironic-discoverd.git/plain/openstack-ironic-discoverd.service>`_
|
|
||||||
(note usage of old name).
|
|
||||||
|
|
||||||
Usage
|
|
||||||
-----
|
|
||||||
|
|
||||||
Refer to HTTP-API.rst_ for information on the HTTP API.
|
|
||||||
Refer to the `client page`_ for information on how to use CLI and Python
|
|
||||||
library.
|
|
||||||
|
|
||||||
.. _HTTP-API.rst: https://github.com/openstack/ironic-inspector/blob/master/HTTP-API.rst
|
|
||||||
.. _HTTP API: https://github.com/openstack/ironic-inspector/blob/master/HTTP-API.rst
|
|
||||||
.. _client page: https://pypi.python.org/pypi/python-ironic-inspector-client
|
|
||||||
|
|
||||||
Using from Ironic API
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Ironic Kilo introduced support for hardware introspection under name of
|
|
||||||
"inspection". **ironic-inspector** introspection is supported for some generic
|
|
||||||
drivers, please refer to `Ironic inspection documentation`_ for details.
|
|
||||||
|
|
||||||
Node States
|
|
||||||
~~~~~~~~~~~
|
|
||||||
|
|
||||||
* The nodes should be moved to ``MANAGEABLE`` provision state before
|
|
||||||
introspection (requires *python-ironicclient* of version 0.5.0 or newer)::
|
|
||||||
|
|
||||||
ironic node-set-provision-state <UUID> manage
|
|
||||||
|
|
||||||
* After successful introspection and before deploying nodes should be made
|
|
||||||
available to Nova, by moving them to ``AVAILABLE`` state::
|
|
||||||
|
|
||||||
ironic node-set-provision-state <UUID> provide
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
Due to how Nova interacts with Ironic driver, you should wait 1 minute
|
|
||||||
before Nova becomes aware of available nodes after issuing this command.
|
|
||||||
Use ``nova hypervisor-stats`` command output to check it.
|
|
||||||
|
|
||||||
Introspection Rules
|
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Inspector supports a simple JSON-based DSL to define rules to run during
|
|
||||||
introspection. Inspector provides an API to manage such rules, and will run
|
|
||||||
them automatically after running all processing hooks.
|
|
||||||
|
|
||||||
A rule consists of conditions to check, and actions to run. If conditions
|
|
||||||
evaluate to true on the introspection data, then actions are run on a node.
|
|
||||||
All actions have "rollback actions" associated with them, which are run when
|
|
||||||
conditions evaluate to false. This way we can safely rerun introspection.
|
|
||||||
|
|
||||||
Available conditions and actions are defined by plugins, and can be extended,
|
|
||||||
see CONTRIBUTING.rst_ for details. See `HTTP API`_ for specific calls to define
|
|
||||||
introspection rules.
|
|
||||||
|
|
||||||
Conditions
|
|
||||||
^^^^^^^^^^
|
|
||||||
|
|
||||||
A condition is represented by an object with fields:
|
|
||||||
|
|
||||||
``op`` the type of comparison operation, default available operators include :
|
|
||||||
``eq``, ``le``, ``ge``, ``ne``, ``lt``, ``gt`` (basic comparison operators),
|
|
||||||
``in-net`` (checks that IP address is in a given network).
|
|
||||||
|
|
||||||
``field`` a `JSON path <http://goessner.net/articles/JsonPath/>`_ to the field
|
|
||||||
in the introspection data to use in comparison.
|
|
||||||
|
|
||||||
``multiple`` how to treat situations where the ``field`` query returns multiple
|
|
||||||
results (e.g. the field contains a list), available options are:
|
|
||||||
|
|
||||||
* ``any`` (the default) require any to match,
|
|
||||||
* ``all`` require all to match,
|
|
||||||
* ``first`` requrie the first to match.
|
|
||||||
|
|
||||||
All other fields are passed to the condition plugin, e.g. numeric comparison
|
|
||||||
operations require a ``value`` field to compare against.
|
|
||||||
|
|
||||||
Actions
|
|
||||||
^^^^^^^
|
|
||||||
|
|
||||||
An action is represented by an object with fields:
|
|
||||||
|
|
||||||
``action`` type of action. Possible values are defined by plugins.
|
|
||||||
|
|
||||||
All other fields are passed to the action plugin.
|
|
||||||
|
|
||||||
Default available actions include:
|
|
||||||
|
|
||||||
* ``fail`` fail introspection. Requires a ``message`` parameter for the failure
|
|
||||||
message.
|
|
||||||
|
|
||||||
* ``set-attribute`` sets an attribute on an Ironic node. Requires a ``path``
|
|
||||||
field, which is the path to the attribute as used by ironic (e.g.
|
|
||||||
``/properties/something``), and a ``value`` to set.
|
|
||||||
|
|
||||||
* ``set-capability`` sets a capability on an Ironic node. Requires ``name``
|
|
||||||
and ``value`` fields, which are the name and the value for a new capability
|
|
||||||
accordingly. Existing value for this same capability is replaced.
|
|
||||||
|
|
||||||
* ``extend-attribute`` the same as ``set-attribute``, but treats existing
|
|
||||||
value as a list and appends value to it. If optional ``unique`` parameter is
|
|
||||||
set to ``True``, nothing will be added if given value is already in a list.
|
|
||||||
|
|
||||||
Setting IPMI Credentials
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
If you have physical access to your nodes, you can use **ironic-inspector** to
|
|
||||||
set IPMI credentials for them without knowing the original ones. The workflow
|
|
||||||
is as follows:
|
|
||||||
|
|
||||||
* Ensure nodes will PXE boot on the right network by default.
|
|
||||||
|
|
||||||
* Set ``enable_setting_ipmi_credentials = true`` in the **ironic-inspector**
|
|
||||||
configuration file, restart **ironic-inspector**.
|
|
||||||
|
|
||||||
* Enroll nodes in Ironic with setting their ``ipmi_address`` only (or
|
|
||||||
equivalent driver-specific property, as per ``ipmi_address_fields``
|
|
||||||
configuration option).
|
|
||||||
|
|
||||||
With Ironic Liberty use ironic API version ``1.11``, so that new node gets
|
|
||||||
into ``enroll`` provision state::
|
|
||||||
|
|
||||||
ironic --ironic-api-version 1.11 node-create -d <DRIVER> -i ipmi_address=<ADDRESS>
|
|
||||||
|
|
||||||
Providing ``ipmi_address`` allows **ironic-inspector** to distinguish nodes.
|
|
||||||
|
|
||||||
* With Ironic Kilo or older, set maintenance mode on nodes.
|
|
||||||
That's an important step, otherwise Ironic might interfere with introspection
|
|
||||||
process. This is replaced by ``enroll`` state in Ironic Liberty.
|
|
||||||
|
|
||||||
* Start introspection with providing additional parameters:
|
|
||||||
|
|
||||||
* ``new_ipmi_password`` IPMI password to set,
|
|
||||||
* ``new_ipmi_username`` IPMI user name to set, defaults to one in node
|
|
||||||
driver_info.
|
|
||||||
|
|
||||||
* Manually power on the nodes and wait.
|
|
||||||
|
|
||||||
* After introspection is finished (watch nodes power state or use
|
|
||||||
**ironic-inspector** status API) you can move node to ``manageable`` and
|
|
||||||
then ``available`` states - see `Node States`_. With Ironic Kilo you have to
|
|
||||||
move a node out of maintenance mode.
|
|
||||||
|
|
||||||
Note that due to various limitations on password value in different BMC,
|
|
||||||
**ironic-inspector** will only accept passwords with length between 1 and 20
|
|
||||||
consisting only of letters and numbers.
|
|
||||||
|
|
||||||
Plugins
|
|
||||||
~~~~~~~
|
|
||||||
|
|
||||||
**ironic-inspector** heavily relies on plugins for data processing. Even the
|
|
||||||
standard functionality is largely based on plugins. Set ``processing_hooks``
|
|
||||||
option in the configuration file to change the set of plugins to be run on
|
|
||||||
introspection data. Note that order does matter in this option.
|
|
||||||
|
|
||||||
These are plugins that are enabled by default and should not be disabled,
|
|
||||||
unless you understand what you're doing:
|
|
||||||
|
|
||||||
``ramdisk_error``
|
|
||||||
reports error, if ``error`` field is set by the ramdisk, also optionally
|
|
||||||
stores logs from ``logs`` field, see `HTTP API`_ for details.
|
|
||||||
``scheduler``
|
|
||||||
validates and updates basic hardware scheduling properties: CPU number and
|
|
||||||
architecture, memory and disk size.
|
|
||||||
``validate_interfaces``
|
|
||||||
validates network interfaces information.
|
|
||||||
|
|
||||||
Here are some plugins that can be additionally enabled:
|
|
||||||
|
|
||||||
``example``
|
|
||||||
example plugin logging it's input and output.
|
|
||||||
``raid_device`` (deprecated name ``root_device_hint``)
|
|
||||||
gathers block devices from ramdisk and exposes root device in multiple
|
|
||||||
runs.
|
|
||||||
``extra_hardware``
|
|
||||||
stores the value of the 'data' key returned by the ramdisk as a JSON
|
|
||||||
encoded string in a Swift object. The plugin will also attempt to convert
|
|
||||||
the data into a format usable by introspection rules. If this is successful
|
|
||||||
then the new format will be stored in the 'extra' key. The 'data' key is
|
|
||||||
then deleted from the introspection data, as unless converted it's assumed
|
|
||||||
unusable by introspection rules.
|
|
||||||
|
|
||||||
Refer to CONTRIBUTING.rst_ for information on how to write your own plugin.
|
|
||||||
|
|
||||||
Troubleshooting
|
|
||||||
---------------
|
|
||||||
|
|
||||||
Errors when starting introspection
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
* *Invalid provision state "available"*
|
|
||||||
|
|
||||||
In Kilo release with *python-ironicclient* 0.5.0 or newer Ironic
|
|
||||||
defaults to reporting provision state ``AVAILABLE`` for newly enrolled
|
|
||||||
nodes. **ironic-inspector** will refuse to conduct introspection in
|
|
||||||
this state, as such nodes are supposed to be used by Nova for scheduling.
|
|
||||||
See `Node States`_ for instructions on how to put nodes into
|
|
||||||
the correct state.
|
|
||||||
|
|
||||||
Introspection times out
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
There may be 3 reasons why introspection can time out after some time
|
|
||||||
(defaulting to 60 minutes, altered by ``timeout`` configuration option):
|
|
||||||
|
|
||||||
#. Fatal failure in processing chain before node was found in the local cache.
|
|
||||||
See `Troubleshooting data processing`_ for the hints.
|
|
||||||
|
|
||||||
#. Failure to load the ramdisk on the target node. See `Troubleshooting
|
|
||||||
PXE boot`_ for the hints.
|
|
||||||
|
|
||||||
#. Failure during ramdisk run. See `Troubleshooting ramdisk run`_ for the
|
|
||||||
hints.
|
|
||||||
|
|
||||||
Troubleshooting data processing
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
In this case **ironic-inspector** logs should give a good idea what went wrong.
|
|
||||||
E.g. for RDO or Fedora the following command will output the full log::
|
|
||||||
|
|
||||||
sudo journalctl -u openstack-ironic-inspector
|
|
||||||
|
|
||||||
(use ``openstack-ironic-discoverd`` for version < 2.0.0).
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
Service name and specific command might be different for other Linux
|
|
||||||
distributions (and for old version of **ironic-inspector**).
|
|
||||||
|
|
||||||
If ``ramdisk_error`` plugin is enabled and ``ramdisk_logs_dir`` configuration
|
|
||||||
option is set, **ironic-inspector** will store logs received from the ramdisk
|
|
||||||
to the ``ramdisk_logs_dir`` directory. This depends, however, on the ramdisk
|
|
||||||
implementation.
|
|
||||||
|
|
||||||
Troubleshooting PXE boot
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
PXE booting most often becomes a problem for bare metal environments with
|
|
||||||
several physical networks. If the hardware vendor provides a remote console
|
|
||||||
(e.g. iDRAC for DELL), use it to connect to the machine and see what is going
|
|
||||||
on. You may need to restart introspection.
|
|
||||||
|
|
||||||
Another source of information is DHCP and TFTP server logs. Their location
|
|
||||||
depends on how the servers were installed and run. For RDO or Fedora use::
|
|
||||||
|
|
||||||
$ sudo journalctl -u openstack-ironic-inspector-dnsmasq
|
|
||||||
|
|
||||||
(use ``openstack-ironic-discoverd-dnsmasq`` for version < 2.0.0).
|
|
||||||
|
|
||||||
The last resort is ``tcpdump`` utility. Use something like
|
|
||||||
::
|
|
||||||
|
|
||||||
$ sudo tcpdump -i any port 67 or port 68 or port 69
|
|
||||||
|
|
||||||
to watch both DHCP and TFTP traffic going through your machine. Replace
|
|
||||||
``any`` with a specific network interface to check that DHCP and TFTP
|
|
||||||
requests really reach it.
|
|
||||||
|
|
||||||
If you see node not attempting PXE boot or attempting PXE boot on the wrong
|
|
||||||
network, reboot the machine into BIOS settings and make sure that only one
|
|
||||||
relevant NIC is allowed to PXE boot.
|
|
||||||
|
|
||||||
If you see node attempting PXE boot using the correct NIC but failing, make
|
|
||||||
sure that:
|
|
||||||
|
|
||||||
#. network switches configuration does not prevent PXE boot requests from
|
|
||||||
propagating,
|
|
||||||
|
|
||||||
#. there is no additional firewall rules preventing access to port 67 on the
|
|
||||||
machine where *ironic-inspector* and its DHCP server are installed.
|
|
||||||
|
|
||||||
If you see node receiving DHCP address and then failing to get kernel and/or
|
|
||||||
ramdisk or to boot them, make sure that:
|
|
||||||
|
|
||||||
#. TFTP server is running and accessible (use ``tftp`` utility to verify),
|
|
||||||
|
|
||||||
#. no firewall rules prevent access to TFTP port,
|
|
||||||
|
|
||||||
#. DHCP server is correctly set to point to the TFTP server,
|
|
||||||
|
|
||||||
#. ``pxelinux.cfg/default`` within TFTP root contains correct reference to the
|
|
||||||
kernel and ramdisk.
|
|
||||||
|
|
||||||
Troubleshooting ramdisk run
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
Connect to the remote console as described in `Troubleshooting PXE boot`_ to
|
|
||||||
see what is going on with the ramdisk. The ramdisk drops into emergency shell
|
|
||||||
on failure, which you can use to look around. There should be file called
|
|
||||||
``logs`` with the current ramdisk logs.
|
|
||||||
|
|
||||||
Troubleshooting DNS issues on Ubuntu
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
Ubuntu uses local DNS caching, so tries localhost for DNS results first
|
|
||||||
before calling out to an external DNS server. When DNSmasq is installed and
|
|
||||||
configured for use with ironic-inspector, it can cause problems by interfering
|
|
||||||
with the local DNS cache. To fix this issue ensure that ``/etc/resolve.conf``
|
|
||||||
points to your external DNS servers and not to ``127.0.0.1``.
|
|
||||||
|
|
|
@ -0,0 +1,159 @@
|
||||||
|
# Makefile for Sphinx documentation
|
||||||
|
#
|
||||||
|
|
||||||
|
# You can set these variables from the command line.
|
||||||
|
SPHINXOPTS =
|
||||||
|
SPHINXBUILD = sphinx-build
|
||||||
|
PAPER =
|
||||||
|
BUILDDIR = build
|
||||||
|
|
||||||
|
# Internal variables.
|
||||||
|
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||||
|
PAPEROPT_letter = -D latex_paper_size=letter
|
||||||
|
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
|
||||||
|
# the i18n builder cannot share the environment and doctrees with the others
|
||||||
|
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
|
||||||
|
|
||||||
|
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
|
||||||
|
|
||||||
|
help:
|
||||||
|
@echo "Please use \`make <target>' where <target> is one of"
|
||||||
|
@echo " html to make standalone HTML files"
|
||||||
|
@echo " dirhtml to make HTML files named index.html in directories"
|
||||||
|
@echo " singlehtml to make a single large HTML file"
|
||||||
|
@echo " pickle to make pickle files"
|
||||||
|
@echo " json to make JSON files"
|
||||||
|
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||||
|
@echo " qthelp to make HTML files and a qthelp project"
|
||||||
|
@echo " devhelp to make HTML files and a Devhelp project"
|
||||||
|
@echo " epub to make an epub"
|
||||||
|
@echo " xml to make Docutils-native XML files"
|
||||||
|
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||||
|
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||||
|
@echo " text to make text files"
|
||||||
|
@echo " man to make manual pages"
|
||||||
|
@echo " texinfo to make Texinfo files"
|
||||||
|
@echo " info to make Texinfo files and run them through makeinfo"
|
||||||
|
@echo " gettext to make PO message catalogs"
|
||||||
|
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||||
|
@echo " linkcheck to check all external links for integrity"
|
||||||
|
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||||
|
|
||||||
|
clean:
|
||||||
|
-rm -rf $(BUILDDIR)/*
|
||||||
|
|
||||||
|
html:
|
||||||
|
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||||
|
|
||||||
|
dirhtml:
|
||||||
|
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||||
|
|
||||||
|
singlehtml:
|
||||||
|
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||||
|
|
||||||
|
pickle:
|
||||||
|
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||||
|
@echo
|
||||||
|
@echo "Build finished; now you can process the pickle files."
|
||||||
|
|
||||||
|
json:
|
||||||
|
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||||
|
@echo
|
||||||
|
@echo "Build finished; now you can process the JSON files."
|
||||||
|
|
||||||
|
htmlhelp:
|
||||||
|
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||||
|
@echo
|
||||||
|
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||||
|
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||||
|
|
||||||
|
qthelp:
|
||||||
|
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||||
|
@echo
|
||||||
|
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||||
|
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||||
|
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Heat.qhcp"
|
||||||
|
@echo "To view the help file:"
|
||||||
|
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Heat.qhc"
|
||||||
|
|
||||||
|
devhelp:
|
||||||
|
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||||
|
@echo
|
||||||
|
@echo "Build finished."
|
||||||
|
@echo "To view the help file:"
|
||||||
|
@echo "# mkdir -p $$HOME/.local/share/devhelp/Heat"
|
||||||
|
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Heat"
|
||||||
|
@echo "# devhelp"
|
||||||
|
|
||||||
|
epub:
|
||||||
|
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||||
|
|
||||||
|
xml:
|
||||||
|
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The xml files are in $(BUILDDIR)/xml."
|
||||||
|
|
||||||
|
latex:
|
||||||
|
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||||
|
@echo
|
||||||
|
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||||
|
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||||
|
"(use \`make latexpdf' here to do that automatically)."
|
||||||
|
|
||||||
|
latexpdf:
|
||||||
|
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||||
|
@echo "Running LaTeX files through pdflatex..."
|
||||||
|
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
||||||
|
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||||
|
|
||||||
|
text:
|
||||||
|
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||||
|
|
||||||
|
man:
|
||||||
|
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||||
|
|
||||||
|
texinfo:
|
||||||
|
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
|
||||||
|
@echo "Run \`make' in that directory to run these through makeinfo" \
|
||||||
|
"(use \`make info' here to do that automatically)."
|
||||||
|
|
||||||
|
info:
|
||||||
|
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||||
|
@echo "Running Texinfo files through makeinfo..."
|
||||||
|
make -C $(BUILDDIR)/texinfo info
|
||||||
|
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
||||||
|
|
||||||
|
gettext:
|
||||||
|
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
||||||
|
|
||||||
|
changes:
|
||||||
|
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||||
|
@echo
|
||||||
|
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||||
|
|
||||||
|
linkcheck:
|
||||||
|
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||||
|
@echo
|
||||||
|
@echo "Link check complete; look for any errors in the above output " \
|
||||||
|
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||||
|
|
||||||
|
doctest:
|
||||||
|
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||||
|
@echo "Testing of doctests in the sources finished, look at the " \
|
||||||
|
"results in $(BUILDDIR)/doctest/output.txt."
|
|
@ -0,0 +1,2 @@
|
||||||
|
target/
|
||||||
|
build/
|
|
@ -0,0 +1,274 @@
|
||||||
|
HTTP API
|
||||||
|
--------
|
||||||
|
|
||||||
|
By default **ironic-inspector** listens on ``0.0.0.0:5050``, port
|
||||||
|
can be changed in configuration. Protocol is JSON over HTTP.
|
||||||
|
|
||||||
|
Start Introspection
|
||||||
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
``POST /v1/introspection/<UUID>`` initiate hardware introspection for node
|
||||||
|
``<UUID>``. All power management configuration for this node needs to be done
|
||||||
|
prior to calling the endpoint (except when `Setting IPMI Credentials`_).
|
||||||
|
|
||||||
|
Requires X-Auth-Token header with Keystone token for authentication.
|
||||||
|
|
||||||
|
Optional parameters:
|
||||||
|
|
||||||
|
* ``new_ipmi_password`` if set, **ironic-inspector** will try to set IPMI
|
||||||
|
password on the machine to this value. Power credentials validation will be
|
||||||
|
skipped and manual power on will be required. See `Setting IPMI
|
||||||
|
credentials`_ for details.
|
||||||
|
|
||||||
|
* ``new_ipmi_username`` provides new IPMI user name in addition to password
|
||||||
|
set by ``new_ipmi_password``. Defaults to current ``ipmi_username`` in
|
||||||
|
node ``driver_info`` field.
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
* 202 - accepted introspection request
|
||||||
|
* 400 - bad request
|
||||||
|
* 401, 403 - missing or invalid authentication
|
||||||
|
* 404 - node cannot be found
|
||||||
|
|
||||||
|
Get Introspection Status
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
``GET /v1/introspection/<UUID>`` get hardware introspection status.
|
||||||
|
|
||||||
|
Requires X-Auth-Token header with Keystone token for authentication.
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
* 200 - OK
|
||||||
|
* 400 - bad request
|
||||||
|
* 401, 403 - missing or invalid authentication
|
||||||
|
* 404 - node cannot be found
|
||||||
|
|
||||||
|
Response body: JSON dictionary with keys:
|
||||||
|
|
||||||
|
* ``finished`` (boolean) whether introspection is finished
|
||||||
|
(``true`` on introspection completion or if it ends because of an error)
|
||||||
|
* ``error`` error string or ``null``
|
||||||
|
|
||||||
|
Get Introspection Data
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
``GET /v1/introspection/<UUID>/data`` get stored data from successful
|
||||||
|
introspection.
|
||||||
|
|
||||||
|
Requires X-Auth-Token header with Keystone token for authentication.
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
* 200 - OK
|
||||||
|
* 400 - bad request
|
||||||
|
* 401, 403 - missing or invalid authentication
|
||||||
|
* 404 - data cannot be found or data storage not configured
|
||||||
|
|
||||||
|
Response body: JSON dictionary with introspection data
|
||||||
|
|
||||||
|
Introspection Rules
|
||||||
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
See `Introspection Rules documentation`_ for details.
|
||||||
|
|
||||||
|
All these API endpoints require X-Auth-Token header with Keystone token for
|
||||||
|
authentication.
|
||||||
|
|
||||||
|
* ``POST /v1/rules`` create a new introspection rule.
|
||||||
|
|
||||||
|
Request body: JSON dictionary with keys:
|
||||||
|
|
||||||
|
* ``conditions`` rule conditions, see `Introspection Rules documentation`_
|
||||||
|
* ``actions`` rule actions, see `Introspection Rules documentation`_
|
||||||
|
* ``description`` (optional) human-readable description
|
||||||
|
* ``uuid`` (optional) rule UUID, autogenerated if missing
|
||||||
|
|
||||||
|
Response
|
||||||
|
|
||||||
|
* 200 - OK
|
||||||
|
* 400 - bad request
|
||||||
|
|
||||||
|
Response body: JSON dictionary with introspection rule representation (the
|
||||||
|
same as above with UUID filled in).
|
||||||
|
|
||||||
|
* ``GET /v1/rules`` list all introspection rules.
|
||||||
|
|
||||||
|
Response
|
||||||
|
|
||||||
|
* 200 - OK
|
||||||
|
|
||||||
|
Response body: JSON dictionary with key ``rules`` - list of short rule
|
||||||
|
representations. Short rule representation is a JSON dictionary with keys:
|
||||||
|
|
||||||
|
* ``uuid`` rule UUID
|
||||||
|
* ``description`` human-readable description
|
||||||
|
* ``links`` list of HTTP links, use one with ``rel=self`` to get the full
|
||||||
|
rule details
|
||||||
|
|
||||||
|
* ``DELETE /v1/rules`` delete all introspection rules.
|
||||||
|
|
||||||
|
Response
|
||||||
|
|
||||||
|
* 204 - OK
|
||||||
|
|
||||||
|
* ``GET /v1/rules/<UUID>`` get one introspection rule by its ``<UUID>``.
|
||||||
|
|
||||||
|
Response
|
||||||
|
|
||||||
|
* 200 - OK
|
||||||
|
* 404 - not found
|
||||||
|
|
||||||
|
Response body: JSON dictionary with introspection rule representation
|
||||||
|
(see ``POST /v1/rules`` above).
|
||||||
|
|
||||||
|
* ``DELETE /v1/rules/<UUID>`` delete one introspection rule by its ``<UUID>``.
|
||||||
|
|
||||||
|
Response
|
||||||
|
|
||||||
|
* 204 - OK
|
||||||
|
* 404 - not found
|
||||||
|
|
||||||
|
.. _Introspection Rules documentation: https://github.com/openstack/ironic-inspector#introspection-rules
|
||||||
|
|
||||||
|
Ramdisk Callback
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
``POST /v1/continue`` internal endpoint for the ramdisk to post back
|
||||||
|
discovered data. Should not be used for anything other than implementing
|
||||||
|
the ramdisk. Request body: JSON dictionary with at least these keys:
|
||||||
|
|
||||||
|
* ``cpus`` number of CPU
|
||||||
|
* ``cpu_arch`` architecture of the CPU
|
||||||
|
* ``memory_mb`` RAM in MiB
|
||||||
|
* ``local_gb`` hard drive size in GiB
|
||||||
|
* ``interfaces`` dictionary filled with data from all NIC's, keys being
|
||||||
|
interface names, values being dictionaries with keys:
|
||||||
|
|
||||||
|
* ``mac`` MAC address
|
||||||
|
* ``ip`` IP address
|
||||||
|
|
||||||
|
* ``ipmi_address`` IP address of BMC, may be missing on VM
|
||||||
|
* ``boot_interface`` optional MAC address of the NIC that the machine
|
||||||
|
PXE booted from either in standard format ``11:22:33:44:55:66`` or
|
||||||
|
in *PXELinux* ``BOOTIF`` format ``01-11-22-33-44-55-66``.
|
||||||
|
|
||||||
|
* ``error`` optional error happened during ramdisk run, interpreted by
|
||||||
|
``ramdisk_error`` plugin
|
||||||
|
|
||||||
|
* ``logs`` optional base64-encoded logs from the ramdisk
|
||||||
|
|
||||||
|
* ``block_devices`` optional block devices information for
|
||||||
|
``root_device_hint`` plugin, dictionary with keys:
|
||||||
|
|
||||||
|
* ``serials`` list of serial numbers of block devices.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
This list highly depends on enabled plugins, provided above are
|
||||||
|
expected keys for the default set of plugins. See Plugins_ for details.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
This endpoint is not expected to be versioned, though versioning will work
|
||||||
|
on it.
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
* 200 - OK
|
||||||
|
* 400 - bad request
|
||||||
|
* 403 - node is not on introspection
|
||||||
|
* 404 - node cannot be found or multiple nodes found
|
||||||
|
|
||||||
|
Response body: JSON dictionary. If `Setting IPMI Credentials`_ is requested,
|
||||||
|
body will contain the following keys:
|
||||||
|
|
||||||
|
* ``ipmi_setup_credentials`` boolean ``True``
|
||||||
|
* ``ipmi_username`` new IPMI user name
|
||||||
|
* ``ipmi_password`` new IPMI password
|
||||||
|
|
||||||
|
.. _Setting IPMI Credentials: https://github.com/openstack/ironic-inspector#setting-ipmi-credentials
|
||||||
|
.. _Plugins: https://github.com/openstack/ironic-inspector#plugins
|
||||||
|
|
||||||
|
Error Response
|
||||||
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
If an error happens during request processing, **Ironic Inspector** returns
|
||||||
|
a response with an appropriate HTTP code set, e.g. 400 for bad request or
|
||||||
|
404 when something was not found (usually node in cache or node in ironic).
|
||||||
|
The following JSON body is returned::
|
||||||
|
|
||||||
|
{
|
||||||
|
"error": {
|
||||||
|
"message": "Full error message"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
This body may be extended in the future to include details that are more error
|
||||||
|
specific.
|
||||||
|
|
||||||
|
API Versioning
|
||||||
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The API supports optional API versioning. You can query for minimum and
|
||||||
|
maximum API version supported by the server. You can also declare required API
|
||||||
|
version in your requests, so that the server rejects request of unsupported
|
||||||
|
version.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
Versioning was introduced in **Ironic Inspector 2.1.0**.
|
||||||
|
|
||||||
|
All versions must be supplied as string in form of ``X.Y``, where ``X`` is a
|
||||||
|
major version and is always ``1`` for now, ``Y`` is a minor version.
|
||||||
|
|
||||||
|
* If ``X-OpenStack-Ironic-Inspector-API-Version`` header is sent with request,
|
||||||
|
the server will check if it supports this version. HTTP error 406 will be
|
||||||
|
returned for unsupported API version.
|
||||||
|
|
||||||
|
* All HTTP responses contain
|
||||||
|
``X-OpenStack-Ironic-Inspector-API-Minimum-Version`` and
|
||||||
|
``X-OpenStack-Ironic-Inspector-API-Maximum-Version`` headers with minimum
|
||||||
|
and maximum API versions supported by the server.
|
||||||
|
|
||||||
|
API Discovery
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The API supports API discovery. You can query different parts of the API to
|
||||||
|
discover what other endpoints are avaliable.
|
||||||
|
|
||||||
|
* ``GET /`` List API Versions
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
* 200 - OK
|
||||||
|
|
||||||
|
Response body: JSON dictionary containing a list of ``versions``, each
|
||||||
|
version contains:
|
||||||
|
|
||||||
|
* ``status`` Either CURRENT or SUPPORTED
|
||||||
|
* ``id`` The version identifier
|
||||||
|
* ``links`` A list of links to this version endpoint containing:
|
||||||
|
|
||||||
|
* ``href`` The URL
|
||||||
|
* ``rel`` The relationship between the version and the href
|
||||||
|
|
||||||
|
* ``GET /v1`` List API v1 resources
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
* 200 - OK
|
||||||
|
|
||||||
|
Response body: JSON dictionary containing a list of ``resources``, each
|
||||||
|
resource contains:
|
||||||
|
|
||||||
|
* ``name`` The name of this resources
|
||||||
|
* ``links`` A list of link to this resource containing:
|
||||||
|
|
||||||
|
* ``href`` The URL
|
||||||
|
* ``rel`` The relationship between the resource and the href
|
||||||
|
|
||||||
|
Version History
|
||||||
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
**1.0** version of API at the moment of introducing versioning.
|
||||||
|
**1.1** adds endpoint to retrieve stored introspection data.
|
||||||
|
**1.2** endpoints for manipulating introspection rules.
|
|
@ -0,0 +1,90 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
|
||||||
|
# -- General configuration ----------------------------------------------------
|
||||||
|
|
||||||
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||||
|
extensions = ['sphinx.ext.autodoc',
|
||||||
|
'sphinx.ext.viewcode',
|
||||||
|
'oslosphinx'
|
||||||
|
]
|
||||||
|
|
||||||
|
wsme_protocols = ['restjson']
|
||||||
|
|
||||||
|
# autodoc generation is a bit aggressive and a nuisance when doing heavy
|
||||||
|
# text edit cycles.
|
||||||
|
# execute "export SPHINX_DEBUG=1" in your terminal to disable
|
||||||
|
|
||||||
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
|
templates_path = ['_templates']
|
||||||
|
|
||||||
|
# The suffix of source filenames.
|
||||||
|
source_suffix = '.rst'
|
||||||
|
|
||||||
|
# The master toctree document.
|
||||||
|
master_doc = 'index'
|
||||||
|
|
||||||
|
# General information about the project.
|
||||||
|
project = u'Ironic Inspector'
|
||||||
|
copyright = u'OpenStack Foundation'
|
||||||
|
|
||||||
|
# The version info for the project you're documenting, acts as replacement for
|
||||||
|
# |version| and |release|, also used in various other places throughout the
|
||||||
|
# built documents.
|
||||||
|
#
|
||||||
|
# The short X.Y version.
|
||||||
|
#from ironic import version as ironic_version
|
||||||
|
# The full version, including alpha/beta/rc tags.
|
||||||
|
#release = ironic_version.version_info.release_string()
|
||||||
|
# The short X.Y version.
|
||||||
|
#version = ironic_version.version_info.version_string()
|
||||||
|
|
||||||
|
# A list of ignored prefixes for module index sorting.
|
||||||
|
modindex_common_prefix = ['ironic.']
|
||||||
|
|
||||||
|
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||||
|
add_function_parentheses = True
|
||||||
|
|
||||||
|
# If true, the current module name will be prepended to all description
|
||||||
|
# unit titles (such as .. function::).
|
||||||
|
add_module_names = True
|
||||||
|
|
||||||
|
# The name of the Pygments (syntax highlighting) style to use.
|
||||||
|
pygments_style = 'sphinx'
|
||||||
|
|
||||||
|
# NOTE(cinerama): mock out nova modules so docs can build without warnings
|
||||||
|
#import mock
|
||||||
|
#import sys
|
||||||
|
#MOCK_MODULES = ['nova', 'nova.compute', 'nova.context']
|
||||||
|
#for module in MOCK_MODULES:
|
||||||
|
# sys.modules[module] = mock.Mock()
|
||||||
|
|
||||||
|
# -- Options for HTML output --------------------------------------------------
|
||||||
|
|
||||||
|
# The theme to use for HTML and HTML Help pages. Major themes that come with
|
||||||
|
# Sphinx are currently 'default' and 'sphinxdoc'.
|
||||||
|
#html_theme_path = ["."]
|
||||||
|
#html_theme = '_theme'
|
||||||
|
#html_static_path = ['_static']
|
||||||
|
|
||||||
|
# Output file base name for HTML help builder.
|
||||||
|
htmlhelp_basename = '%sdoc' % project
|
||||||
|
|
||||||
|
|
||||||
|
# Grouping the document tree into LaTeX files. List of tuples
|
||||||
|
# (source start file, target name, title, author, documentclass
|
||||||
|
# [howto/manual]).
|
||||||
|
latex_documents = [
|
||||||
|
(
|
||||||
|
'index',
|
||||||
|
'%s.tex' % project,
|
||||||
|
u'%s Documentation' % project,
|
||||||
|
u'OpenStack Foundation',
|
||||||
|
'manual'
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
# -- Options for seqdiag ------------------------------------------------------
|
||||||
|
|
||||||
|
seqdiag_html_image_format = "SVG"
|
|
@ -0,0 +1,241 @@
|
||||||
|
.. _install_guide:
|
||||||
|
|
||||||
|
Installation
|
||||||
|
------------
|
||||||
|
|
||||||
|
Install from PyPI_ (you may want to use virtualenv to isolate your
|
||||||
|
environment)::
|
||||||
|
|
||||||
|
pip install ironic-inspector
|
||||||
|
|
||||||
|
Also there is a `DevStack <http://docs.openstack.org/developer/devstack/>`_
|
||||||
|
plugin for **ironic-inspector** - see :ref:`contributing_link` for the current status.
|
||||||
|
|
||||||
|
Finally, some distributions (e.g. Fedora) provide **ironic-inspector**
|
||||||
|
packaged, some of them - under its old name *ironic-discoverd*.
|
||||||
|
|
||||||
|
.. _PyPI: https://pypi.python.org/pypi/ironic-inspector
|
||||||
|
|
||||||
|
Configuration
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Copy ``example.conf`` to some permanent place
|
||||||
|
(e.g. ``/etc/ironic-inspector/inspector.conf``).
|
||||||
|
Fill in at least these configuration values:
|
||||||
|
|
||||||
|
* ``os_username``, ``os_password``, ``os_tenant_name`` - Keystone credentials
|
||||||
|
to use when accessing other services and check client authentication tokens;
|
||||||
|
|
||||||
|
* ``os_auth_url``, ``identity_uri`` - Keystone endpoints for validating
|
||||||
|
authentication tokens and checking user roles;
|
||||||
|
|
||||||
|
* ``connection`` in the ``database`` section - SQLAlchemy connection string
|
||||||
|
for the database;
|
||||||
|
|
||||||
|
* ``dnsmasq_interface`` - interface on which ``dnsmasq`` (or another DHCP
|
||||||
|
service) listens for PXE boot requests (defaults to ``br-ctlplane`` which is
|
||||||
|
a sane default for TripleO-based installations but is unlikely to work for
|
||||||
|
other cases).
|
||||||
|
|
||||||
|
See comments inside `example.conf
|
||||||
|
<https://github.com/openstack/ironic-inspector/blob/master/example.conf>`_
|
||||||
|
for the other possible configuration options.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
Configuration file contains a password and thus should be owned by ``root``
|
||||||
|
and should have access rights like ``0600``.
|
||||||
|
|
||||||
|
**ironic-inspector** requires root rights for managing iptables. It gets them
|
||||||
|
by running ``ironic-inspector-rootwrap`` utility with ``sudo``.
|
||||||
|
To allow it, copy file ``rootwrap.conf`` and directory ``rootwrap.d`` to the
|
||||||
|
configuration directory (e.g. ``/etc/ironic-inspector/``) and create file
|
||||||
|
``/etc/sudoers.d/ironic-inspector-rootwrap`` with the following content::
|
||||||
|
|
||||||
|
stack ALL=(root) NOPASSWD: /usr/bin/ironic-inspector-rootwrap /etc/ironic-inspector/rootwrap.conf *
|
||||||
|
|
||||||
|
.. DANGER::
|
||||||
|
Be very careful about typos in ``/etc/sudoers.d/ironic-inspector-rootwrap``
|
||||||
|
as any typo will break sudo for **ALL** users on the system. Especially,
|
||||||
|
make sure there is a new line at the end of this file.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
``rootwrap.conf`` and all files in ``rootwrap.d`` must be writeable
|
||||||
|
only by root.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
If you store ``rootwrap.d`` in a different location, make sure to update
|
||||||
|
the *filters_path* option in ``rootwrap.conf`` to reflect the change.
|
||||||
|
|
||||||
|
If your ``rootwrap.conf`` is in a different location, then you need
|
||||||
|
to update the *rootwrap_config* option in ``ironic-inspector.conf``
|
||||||
|
to point to that location.
|
||||||
|
|
||||||
|
Replace ``stack`` with whatever user you'll be using to run
|
||||||
|
**ironic-inspector**.
|
||||||
|
|
||||||
|
Configuring PXE
|
||||||
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
As for PXE boot environment, you'll need:
|
||||||
|
|
||||||
|
* TFTP server running and accessible (see below for using *dnsmasq*).
|
||||||
|
Ensure ``pxelinux.0`` is present in the TFTP root.
|
||||||
|
|
||||||
|
|
||||||
|
* You need PXE boot server (e.g. *dnsmasq*) running on **the same** machine as
|
||||||
|
**ironic-inspector**. Don't do any firewall configuration:
|
||||||
|
**ironic-inspector** will handle it for you. In **ironic-inspector**
|
||||||
|
configuration file set ``dnsmasq_interface`` to the interface your
|
||||||
|
PXE boot server listens on. Here is an example *dnsmasq.conf*::
|
||||||
|
|
||||||
|
port=0
|
||||||
|
interface={INTERFACE}
|
||||||
|
bind-interfaces
|
||||||
|
dhcp-range={DHCP IP RANGE, e.g. 192.168.0.50,192.168.0.150}
|
||||||
|
enable-tftp
|
||||||
|
tftp-root={TFTP ROOT, e.g. /tftpboot}
|
||||||
|
dhcp-boot=pxelinux.0
|
||||||
|
|
||||||
|
* You have to install and configure one of 2 available ramdisks: simple
|
||||||
|
bash-based (see `Using simple ramdisk`_) or more complex based on
|
||||||
|
ironic-python-agent_ (See `Using IPA`_).
|
||||||
|
|
||||||
|
Here is *inspector.conf* you may end up with::
|
||||||
|
|
||||||
|
[DEFAULT]
|
||||||
|
debug = false
|
||||||
|
[ironic]
|
||||||
|
identity_uri = http://127.0.0.1:35357
|
||||||
|
os_auth_url = http://127.0.0.1:5000/v2.0
|
||||||
|
os_username = admin
|
||||||
|
os_password = password
|
||||||
|
os_tenant_name = admin
|
||||||
|
[firewall]
|
||||||
|
dnsmasq_interface = br-ctlplane
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
Set ``debug = true`` if you want to see complete logs.
|
||||||
|
|
||||||
|
Using simple ramdisk
|
||||||
|
^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
* Build and put into your TFTP the kernel and ramdisk created using the
|
||||||
|
diskimage-builder_ `ironic-discoverd-ramdisk element`_::
|
||||||
|
|
||||||
|
ramdisk-image-create -o discovery fedora ironic-discoverd-ramdisk
|
||||||
|
|
||||||
|
You need diskimage-builder_ 0.1.38 or newer to do it (using the latest one
|
||||||
|
is always advised).
|
||||||
|
|
||||||
|
* Configure your ``$TFTPROOT/pxelinux.cfg/default`` with something like::
|
||||||
|
|
||||||
|
default introspect
|
||||||
|
|
||||||
|
label introspect
|
||||||
|
kernel discovery.kernel
|
||||||
|
append initrd=discovery.initramfs discoverd_callback_url=http://{IP}:5050/v1/continue
|
||||||
|
|
||||||
|
ipappend 3
|
||||||
|
|
||||||
|
Replace ``{IP}`` with IP of the machine (do not use loopback interface, it
|
||||||
|
will be accessed by ramdisk on a booting machine).
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
There are some prebuilt images which use obsolete ``ironic_callback_url``
|
||||||
|
instead of ``discoverd_callback_url``. Modify ``pxelinux.cfg/default``
|
||||||
|
accordingly if you have one of these.
|
||||||
|
|
||||||
|
Using IPA
|
||||||
|
^^^^^^^^^
|
||||||
|
|
||||||
|
ironic-python-agent_ is a new ramdisk developed for Ironic. During the Liberty
|
||||||
|
cycle support for **ironic-inspector** was added. This is experimental
|
||||||
|
for now, but we plan on making IPA the default ramdisk in Mitaka cycle.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
You need at least 1.5 GiB of RAM on the machines to use this ramdisk.
|
||||||
|
|
||||||
|
To build an ironic-python-agent ramdisk, do the following:
|
||||||
|
|
||||||
|
* Get the latest diskimage-builder_::
|
||||||
|
|
||||||
|
sudo pip install -U "diskimage-builder>=1.1.2"
|
||||||
|
|
||||||
|
* Build the ramdisk::
|
||||||
|
|
||||||
|
disk-image-create ironic-agent fedora -o ironic-agent
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
Replace "fedora" with your distribution of choice.
|
||||||
|
|
||||||
|
* Copy resulting files ``ironic-agent.vmlinuz`` and ``ironic-agent.initramfs``
|
||||||
|
to the TFTP root directory.
|
||||||
|
|
||||||
|
Next, set up ``$TFTPROOT/pxelinux.cfg/default`` as follows::
|
||||||
|
|
||||||
|
default introspect
|
||||||
|
|
||||||
|
label introspect
|
||||||
|
kernel ironic-agent.vmlinuz
|
||||||
|
append initrd=ironic-agent.initramfs ipa-inspection-callback-url=http://{IP}:5050/v1/continue systemd.journald.forward_to_console=yes
|
||||||
|
|
||||||
|
ipappend 3
|
||||||
|
|
||||||
|
Replace ``{IP}`` with IP of the machine (do not use loopback interface, it
|
||||||
|
will be accessed by ramdisk on a booting machine).
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
While ``systemd.journald.forward_to_console=yes`` is not actually
|
||||||
|
required, it will substantially simplify debugging if something goes wrong.
|
||||||
|
|
||||||
|
.. _diskimage-builder: https://github.com/openstack/diskimage-builder
|
||||||
|
.. _ironic-discoverd-ramdisk element: https://github.com/openstack/diskimage-builder/tree/master/elements/ironic-discoverd-ramdisk
|
||||||
|
.. _ironic-python-agent: https://github.com/openstack/ironic-python-agent
|
||||||
|
|
||||||
|
Managing the **ironic-inspector** database
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
**ironic-inspector** provides a command line client for managing its database,
|
||||||
|
this client can be used for upgrading, and downgrading the database using
|
||||||
|
alembic migrations.
|
||||||
|
|
||||||
|
If this is your first time running **ironic-inspector** to migrate the
|
||||||
|
database simply run:
|
||||||
|
::
|
||||||
|
|
||||||
|
ironic-inspector-dbsync --config-file /etc/ironic-inspector/inspector.conf upgrade
|
||||||
|
|
||||||
|
If you have previously run a version of **ironic-inspector** earlier than
|
||||||
|
2.2.0, the safest thing is to delete the existing SQLite database and run
|
||||||
|
``upgrade`` as shown above. If you, however, want to save the existing
|
||||||
|
database, to ensure your database will work with the migrations, you'll need to
|
||||||
|
run an extra step before upgrading the database. You only need to do this the
|
||||||
|
first time running version 2.2.0 or later.
|
||||||
|
|
||||||
|
If you are upgrading from **ironic-inspector** version 2.1.0 or lower:
|
||||||
|
::
|
||||||
|
|
||||||
|
ironic-inspector-dbsync --config-file /etc/ironic-inspector/inspector.conf stamp --revision 578f84f38d
|
||||||
|
ironic-inspector-dbsync --config-file /etc/ironic-inspector/inspector.conf upgrade
|
||||||
|
|
||||||
|
If you are upgrading from a git master install of **ironic-inspector** from
|
||||||
|
after :ref:`introspection_rules` were introduced:
|
||||||
|
::
|
||||||
|
|
||||||
|
ironic-inspector-dbsync --config-file /etc/ironic-inspector/inspector.conf stamp --revision d588418040d
|
||||||
|
ironic-inspector-dbsync --config-file /etc/ironic-inspector/inspector.conf upgrade
|
||||||
|
|
||||||
|
Other available commands can be discovered by running::
|
||||||
|
|
||||||
|
ironic-inspector-dbsync --help
|
||||||
|
|
||||||
|
Running
|
||||||
|
~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
ironic-inspector --config-file /etc/ironic-inspector/inspector.conf
|
||||||
|
|
||||||
|
A good starting point for writing your own *systemd* unit should be `one used
|
||||||
|
in Fedora <http://pkgs.fedoraproject.org/cgit/openstack-ironic-discoverd.git/plain/openstack-ironic-discoverd.service>`_
|
||||||
|
(note usage of old name).
|
|
@ -0,0 +1,3 @@
|
||||||
|
.. _contributing_link:
|
||||||
|
|
||||||
|
.. include:: ../../../CONTRIBUTING.rst
|
|
@ -0,0 +1,73 @@
|
||||||
|
Hardware introspection for OpenStack Bare Metal
|
||||||
|
===============================================
|
||||||
|
|
||||||
|
This is an auxiliary service for discovering hardware properties for a
|
||||||
|
node managed by `Ironic`_. Hardware introspection or hardware
|
||||||
|
properties discovery is a process of getting hardware parameters required for
|
||||||
|
scheduling from a bare metal node, given it's power management credentials
|
||||||
|
(e.g. IPMI address, user name and password).
|
||||||
|
|
||||||
|
A special ramdisk is required to collect the information on a
|
||||||
|
node. The default one can be built using diskimage-builder_ and
|
||||||
|
`ironic-discoverd-ramdisk element`_ (see :ref:`install_guide`).
|
||||||
|
|
||||||
|
* Free software: Apache license
|
||||||
|
* Source: http://git.openstack.org/cgit/openstack/ironic-inspector
|
||||||
|
* Bugs: http://bugs.launchpad.net/ironic-inspector
|
||||||
|
* Blueprints: https://blueprints.launchpad.net/ironic-inspector
|
||||||
|
* Downloads: https://pypi.python.org/pypi/ironic-inspector
|
||||||
|
* Python client library and CLI tool: `python-ironic-inspector-client
|
||||||
|
<https://pypi.python.org/pypi/python-ironic-inspector-client>`_.
|
||||||
|
|
||||||
|
.. _Ironic: https://wiki.openstack.org/wiki/Ironic
|
||||||
|
.. _PyPI: https://pypi.python.org/pypi/ironic-inspector
|
||||||
|
.. _diskimage-builder: https://github.com/openstack/diskimage-builder
|
||||||
|
.. _ironic-discoverd-ramdisk element: https://github.com/openstack/diskimage-builder/tree/master/elements/ironic-discoverd-ramdisk
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
**ironic-inspector** was called *ironic-discoverd* before version 2.0.0.
|
||||||
|
|
||||||
|
For information on any current or prior version, see `the release
|
||||||
|
notes`_ and `the wiki pages`_.
|
||||||
|
|
||||||
|
.. _the release notes: releasenotes/index.html
|
||||||
|
.. _the wiki pages: https://wiki.openstack.org/wiki/Ironic/ReleaseNotes
|
||||||
|
|
||||||
|
Admin Guide
|
||||||
|
===========
|
||||||
|
|
||||||
|
Overview
|
||||||
|
--------
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
Installation Guide <deploy/install-guide>
|
||||||
|
Usage <usage/usage>
|
||||||
|
Troubleshooting <troubleshooting/troubleshooting>
|
||||||
|
|
||||||
|
Developer Guide
|
||||||
|
===============
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
------------
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
Contribution Guide <dev/contributing_link>
|
||||||
|
|
||||||
|
API References
|
||||||
|
--------------
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
HTTP API description <api/HTTP-API>
|
||||||
|
|
||||||
|
Indices and tables
|
||||||
|
==================
|
||||||
|
|
||||||
|
* :ref:`genindex`
|
||||||
|
* :ref:`modindex`
|
||||||
|
* :ref:`search`
|
|
@ -0,0 +1,113 @@
|
||||||
|
Troubleshooting
|
||||||
|
===============
|
||||||
|
|
||||||
|
Errors when starting introspection
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
* *Invalid provision state "available"*
|
||||||
|
|
||||||
|
In Kilo release with *python-ironicclient* 0.5.0 or newer Ironic
|
||||||
|
defaults to reporting provision state ``AVAILABLE`` for newly enrolled
|
||||||
|
nodes. **ironic-inspector** will refuse to conduct introspection in
|
||||||
|
this state, as such nodes are supposed to be used by Nova for scheduling.
|
||||||
|
See :ref:`node_states` for instructions on how to put nodes into
|
||||||
|
the correct state.
|
||||||
|
|
||||||
|
Introspection times out
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
There may be 3 reasons why introspection can time out after some time
|
||||||
|
(defaulting to 60 minutes, altered by ``timeout`` configuration option):
|
||||||
|
|
||||||
|
#. Fatal failure in processing chain before node was found in the local cache.
|
||||||
|
See `Troubleshooting data processing`_ for the hints.
|
||||||
|
|
||||||
|
#. Failure to load the ramdisk on the target node. See `Troubleshooting
|
||||||
|
PXE boot`_ for the hints.
|
||||||
|
|
||||||
|
#. Failure during ramdisk run. See `Troubleshooting ramdisk run`_ for the
|
||||||
|
hints.
|
||||||
|
|
||||||
|
Troubleshooting data processing
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
In this case **ironic-inspector** logs should give a good idea what went wrong.
|
||||||
|
E.g. for RDO or Fedora the following command will output the full log::
|
||||||
|
|
||||||
|
sudo journalctl -u openstack-ironic-inspector
|
||||||
|
|
||||||
|
(use ``openstack-ironic-discoverd`` for version < 2.0.0).
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
Service name and specific command might be different for other Linux
|
||||||
|
distributions (and for old version of **ironic-inspector**).
|
||||||
|
|
||||||
|
If ``ramdisk_error`` plugin is enabled and ``ramdisk_logs_dir`` configuration
|
||||||
|
option is set, **ironic-inspector** will store logs received from the ramdisk
|
||||||
|
to the ``ramdisk_logs_dir`` directory. This depends, however, on the ramdisk
|
||||||
|
implementation.
|
||||||
|
|
||||||
|
Troubleshooting PXE boot
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
PXE booting most often becomes a problem for bare metal environments with
|
||||||
|
several physical networks. If the hardware vendor provides a remote console
|
||||||
|
(e.g. iDRAC for DELL), use it to connect to the machine and see what is going
|
||||||
|
on. You may need to restart introspection.
|
||||||
|
|
||||||
|
Another source of information is DHCP and TFTP server logs. Their location
|
||||||
|
depends on how the servers were installed and run. For RDO or Fedora use::
|
||||||
|
|
||||||
|
$ sudo journalctl -u openstack-ironic-inspector-dnsmasq
|
||||||
|
|
||||||
|
(use ``openstack-ironic-discoverd-dnsmasq`` for version < 2.0.0).
|
||||||
|
|
||||||
|
The last resort is ``tcpdump`` utility. Use something like
|
||||||
|
::
|
||||||
|
|
||||||
|
$ sudo tcpdump -i any port 67 or port 68 or port 69
|
||||||
|
|
||||||
|
to watch both DHCP and TFTP traffic going through your machine. Replace
|
||||||
|
``any`` with a specific network interface to check that DHCP and TFTP
|
||||||
|
requests really reach it.
|
||||||
|
|
||||||
|
If you see node not attempting PXE boot or attempting PXE boot on the wrong
|
||||||
|
network, reboot the machine into BIOS settings and make sure that only one
|
||||||
|
relevant NIC is allowed to PXE boot.
|
||||||
|
|
||||||
|
If you see node attempting PXE boot using the correct NIC but failing, make
|
||||||
|
sure that:
|
||||||
|
|
||||||
|
#. network switches configuration does not prevent PXE boot requests from
|
||||||
|
propagating,
|
||||||
|
|
||||||
|
#. there is no additional firewall rules preventing access to port 67 on the
|
||||||
|
machine where *ironic-inspector* and its DHCP server are installed.
|
||||||
|
|
||||||
|
If you see node receiving DHCP address and then failing to get kernel and/or
|
||||||
|
ramdisk or to boot them, make sure that:
|
||||||
|
|
||||||
|
#. TFTP server is running and accessible (use ``tftp`` utility to verify),
|
||||||
|
|
||||||
|
#. no firewall rules prevent access to TFTP port,
|
||||||
|
|
||||||
|
#. DHCP server is correctly set to point to the TFTP server,
|
||||||
|
|
||||||
|
#. ``pxelinux.cfg/default`` within TFTP root contains correct reference to the
|
||||||
|
kernel and ramdisk.
|
||||||
|
|
||||||
|
Troubleshooting ramdisk run
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Connect to the remote console as described in `Troubleshooting PXE boot`_ to
|
||||||
|
see what is going on with the ramdisk. The ramdisk drops into emergency shell
|
||||||
|
on failure, which you can use to look around. There should be file called
|
||||||
|
``logs`` with the current ramdisk logs.
|
||||||
|
|
||||||
|
Troubleshooting DNS issues on Ubuntu
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Ubuntu uses local DNS caching, so tries localhost for DNS results first
|
||||||
|
before calling out to an external DNS server. When DNSmasq is installed and
|
||||||
|
configured for use with ironic-inspector, it can cause problems by interfering
|
||||||
|
with the local DNS cache. To fix this issue ensure that ``/etc/resolve.conf``
|
||||||
|
points to your external DNS servers and not to ``127.0.0.1``.
|
|
@ -0,0 +1,187 @@
|
||||||
|
Usage
|
||||||
|
=====
|
||||||
|
|
||||||
|
|
||||||
|
Refer to HTTP-API.rst_ for information on the HTTP API.
|
||||||
|
Refer to the `client page`_ for information on how to use CLI and Python
|
||||||
|
library.
|
||||||
|
|
||||||
|
.. _HTTP-API.rst: https://github.com/openstack/ironic-inspector/blob/master/HTTP-API.rst
|
||||||
|
.. _HTTP API: https://github.com/openstack/ironic-inspector/blob/master/HTTP-API.rst
|
||||||
|
.. _client page: https://pypi.python.org/pypi/python-ironic-inspector-client
|
||||||
|
|
||||||
|
Using from Ironic API
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Ironic Kilo introduced support for hardware introspection under name of
|
||||||
|
"inspection". **ironic-inspector** introspection is supported for some generic
|
||||||
|
drivers, please refer to `Ironic inspection documentation`_ for details.
|
||||||
|
|
||||||
|
.. _Ironic inspection documentation: http://docs.openstack.org/developer/ironic/deploy/install-guide.html#hardware-inspection
|
||||||
|
|
||||||
|
.. _node_states:
|
||||||
|
|
||||||
|
Node States
|
||||||
|
~~~~~~~~~~~
|
||||||
|
|
||||||
|
* The nodes should be moved to ``MANAGEABLE`` provision state before
|
||||||
|
introspection (requires *python-ironicclient* of version 0.5.0 or newer)::
|
||||||
|
|
||||||
|
ironic node-set-provision-state <UUID> manage
|
||||||
|
|
||||||
|
* After successful introspection and before deploying nodes should be made
|
||||||
|
available to Nova, by moving them to ``AVAILABLE`` state::
|
||||||
|
|
||||||
|
ironic node-set-provision-state <UUID> provide
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
Due to how Nova interacts with Ironic driver, you should wait 1 minute
|
||||||
|
before Nova becomes aware of available nodes after issuing this command.
|
||||||
|
Use ``nova hypervisor-stats`` command output to check it.
|
||||||
|
|
||||||
|
.. _introspection_rules:
|
||||||
|
|
||||||
|
Introspection Rules
|
||||||
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Inspector supports a simple JSON-based DSL to define rules to run during
|
||||||
|
introspection. Inspector provides an API to manage such rules, and will run
|
||||||
|
them automatically after running all processing hooks.
|
||||||
|
|
||||||
|
A rule consists of conditions to check, and actions to run. If conditions
|
||||||
|
evaluate to true on the introspection data, then actions are run on a node.
|
||||||
|
All actions have "rollback actions" associated with them, which are run when
|
||||||
|
conditions evaluate to false. This way we can safely rerun introspection.
|
||||||
|
|
||||||
|
Available conditions and actions are defined by plugins, and can be extended,
|
||||||
|
see :ref:`contributing_link` for details. See `HTTP API`_ for specific calls to define
|
||||||
|
introspection rules.
|
||||||
|
|
||||||
|
Conditions
|
||||||
|
^^^^^^^^^^
|
||||||
|
|
||||||
|
A condition is represented by an object with fields:
|
||||||
|
|
||||||
|
``op`` the type of comparison operation, default available operators include :
|
||||||
|
``eq``, ``le``, ``ge``, ``ne``, ``lt``, ``gt`` (basic comparison operators),
|
||||||
|
``in-net`` (checks that IP address is in a given network).
|
||||||
|
|
||||||
|
``field`` a `JSON path <http://goessner.net/articles/JsonPath/>`_ to the field
|
||||||
|
in the introspection data to use in comparison.
|
||||||
|
|
||||||
|
``multiple`` how to treat situations where the ``field`` query returns multiple
|
||||||
|
results (e.g. the field contains a list), available options are:
|
||||||
|
|
||||||
|
* ``any`` (the default) require any to match,
|
||||||
|
* ``all`` require all to match,
|
||||||
|
* ``first`` requrie the first to match.
|
||||||
|
|
||||||
|
All other fields are passed to the condition plugin, e.g. numeric comparison
|
||||||
|
operations require a ``value`` field to compare against.
|
||||||
|
|
||||||
|
Actions
|
||||||
|
^^^^^^^
|
||||||
|
|
||||||
|
An action is represented by an object with fields:
|
||||||
|
|
||||||
|
``action`` type of action. Possible values are defined by plugins.
|
||||||
|
|
||||||
|
All other fields are passed to the action plugin.
|
||||||
|
|
||||||
|
Default available actions include:
|
||||||
|
|
||||||
|
* ``fail`` fail introspection. Requires a ``message`` parameter for the failure
|
||||||
|
message.
|
||||||
|
|
||||||
|
* ``set-attribute`` sets an attribute on an Ironic node. Requires a ``path``
|
||||||
|
field, which is the path to the attribute as used by ironic (e.g.
|
||||||
|
``/properties/something``), and a ``value`` to set.
|
||||||
|
|
||||||
|
* ``set-capability`` sets a capability on an Ironic node. Requires ``name``
|
||||||
|
and ``value`` fields, which are the name and the value for a new capability
|
||||||
|
accordingly. Existing value for this same capability is replaced.
|
||||||
|
|
||||||
|
* ``extend-attribute`` the same as ``set-attribute``, but treats existing
|
||||||
|
value as a list and appends value to it. If optional ``unique`` parameter is
|
||||||
|
set to ``True``, nothing will be added if given value is already in a list.
|
||||||
|
|
||||||
|
Setting IPMI Credentials
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
If you have physical access to your nodes, you can use **ironic-inspector** to
|
||||||
|
set IPMI credentials for them without knowing the original ones. The workflow
|
||||||
|
is as follows:
|
||||||
|
|
||||||
|
* Ensure nodes will PXE boot on the right network by default.
|
||||||
|
|
||||||
|
* Set ``enable_setting_ipmi_credentials = true`` in the **ironic-inspector**
|
||||||
|
configuration file, restart **ironic-inspector**.
|
||||||
|
|
||||||
|
* Enroll nodes in Ironic with setting their ``ipmi_address`` only (or
|
||||||
|
equivalent driver-specific property, as per ``ipmi_address_fields``
|
||||||
|
configuration option).
|
||||||
|
|
||||||
|
With Ironic Liberty use ironic API version ``1.11``, so that new node gets
|
||||||
|
into ``enroll`` provision state::
|
||||||
|
|
||||||
|
ironic --ironic-api-version 1.11 node-create -d <DRIVER> -i ipmi_address=<ADDRESS>
|
||||||
|
|
||||||
|
Providing ``ipmi_address`` allows **ironic-inspector** to distinguish nodes.
|
||||||
|
|
||||||
|
* With Ironic Kilo or older, set maintenance mode on nodes.
|
||||||
|
That's an important step, otherwise Ironic might interfere with introspection
|
||||||
|
process. This is replaced by ``enroll`` state in Ironic Liberty.
|
||||||
|
|
||||||
|
* Start introspection with providing additional parameters:
|
||||||
|
|
||||||
|
* ``new_ipmi_password`` IPMI password to set,
|
||||||
|
* ``new_ipmi_username`` IPMI user name to set, defaults to one in node
|
||||||
|
driver_info.
|
||||||
|
|
||||||
|
* Manually power on the nodes and wait.
|
||||||
|
|
||||||
|
* After introspection is finished (watch nodes power state or use
|
||||||
|
**ironic-inspector** status API) you can move node to ``manageable`` and
|
||||||
|
then ``available`` states - see `Node States`_. With Ironic Kilo you have to
|
||||||
|
move a node out of maintenance mode.
|
||||||
|
|
||||||
|
Note that due to various limitations on password value in different BMC,
|
||||||
|
**ironic-inspector** will only accept passwords with length between 1 and 20
|
||||||
|
consisting only of letters and numbers.
|
||||||
|
|
||||||
|
Plugins
|
||||||
|
~~~~~~~
|
||||||
|
|
||||||
|
**ironic-inspector** heavily relies on plugins for data processing. Even the
|
||||||
|
standard functionality is largely based on plugins. Set ``processing_hooks``
|
||||||
|
option in the configuration file to change the set of plugins to be run on
|
||||||
|
introspection data. Note that order does matter in this option.
|
||||||
|
|
||||||
|
These are plugins that are enabled by default and should not be disabled,
|
||||||
|
unless you understand what you're doing:
|
||||||
|
|
||||||
|
``ramdisk_error``
|
||||||
|
reports error, if ``error`` field is set by the ramdisk, also optionally
|
||||||
|
stores logs from ``logs`` field, see `HTTP API`_ for details.
|
||||||
|
``scheduler``
|
||||||
|
validates and updates basic hardware scheduling properties: CPU number and
|
||||||
|
architecture, memory and disk size.
|
||||||
|
``validate_interfaces``
|
||||||
|
validates network interfaces information.
|
||||||
|
|
||||||
|
Here are some plugins that can be additionally enabled:
|
||||||
|
|
||||||
|
``example``
|
||||||
|
example plugin logging it's input and output.
|
||||||
|
``raid_device`` (deprecated name ``root_device_hint``)
|
||||||
|
gathers block devices from ramdisk and exposes root device in multiple
|
||||||
|
runs.
|
||||||
|
``extra_hardware``
|
||||||
|
stores the value of the 'data' key returned by the ramdisk as a JSON
|
||||||
|
encoded string in a Swift object. The plugin will also attempt to convert
|
||||||
|
the data into a format usable by introspection rules. If this is successful
|
||||||
|
then the new format will be stored in the 'extra' key. The 'data' key is
|
||||||
|
then deleted from the introspection data, as unless converted it's assumed
|
||||||
|
unusable by introspection rules.
|
||||||
|
|
||||||
|
Refer to :ref:`contributing_link` for information on how to write your own plugin.
|
|
@ -0,0 +1,12 @@
|
||||||
|
---
|
||||||
|
prelude: >
|
||||||
|
This release includes automatic `docs` generation via Sphinx.
|
||||||
|
other:
|
||||||
|
- |
|
||||||
|
Introduced new docs generation via `Sphinx <http://sphinx-doc.org/contents.html>`_
|
||||||
|
and `ReST <http://docutils.sourceforge.net/rst.html>`_.
|
||||||
|
|
||||||
|
* Separate `doc` folder includes `source` and `build`
|
||||||
|
* Integration with `tox <https://testrun.org/tox/latest/index.html>`_ as `docs` target
|
||||||
|
* `makefile` for manual building
|
||||||
|
* `Openstack Theme <https://github.com/openstack/oslosphinx>`_ support
|
|
@ -66,3 +66,8 @@ input_file = ironic-inspector/locale/ironic-inspector.pot
|
||||||
keywords = _ gettext ngettext l_ lazy_gettext
|
keywords = _ gettext ngettext l_ lazy_gettext
|
||||||
mapping_file = babel.cfg
|
mapping_file = babel.cfg
|
||||||
output_file = ironic-inspector/locale/ironic-inspector.pot
|
output_file = ironic-inspector/locale/ironic-inspector.pot
|
||||||
|
|
||||||
|
[build_sphinx]
|
||||||
|
all_files = 1
|
||||||
|
build-dir = doc/build
|
||||||
|
source-dir = doc/source
|
||||||
|
|
|
@ -8,3 +8,4 @@ mock>=1.2
|
||||||
sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2
|
sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2
|
||||||
oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0
|
oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0
|
||||||
reno>=0.1.1 # Apache2
|
reno>=0.1.1 # Apache2
|
||||||
|
|
||||||
|
|
7
tox.ini
7
tox.ini
|
@ -57,3 +57,10 @@ max-complexity=15
|
||||||
|
|
||||||
[hacking]
|
[hacking]
|
||||||
import_exceptions = ironicclient.exceptions,ironic_inspector.common.i18n
|
import_exceptions = ironicclient.exceptions,ironic_inspector.common.i18n
|
||||||
|
|
||||||
|
[testenv:docs]
|
||||||
|
setenv = PYTHONHASHSEED=0
|
||||||
|
sitepackages = False
|
||||||
|
deps = -r{toxinidir}/test-requirements.txt
|
||||||
|
commands =
|
||||||
|
python setup.py build_sphinx
|
||||||
|
|
Loading…
Reference in New Issue