diff --git a/.gitignore b/.gitignore
index ad83135f6..73b013cac 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,7 +6,7 @@
# Sphinx
_build
-doc/source/api/
+#doc/source/api/
# release notes build
releasenotes/build
diff --git a/README.rst b/README.rst
index 2af736630..73a9c0251 100644
--- a/README.rst
+++ b/README.rst
@@ -24,6 +24,9 @@ Refer to CONTRIBUTING.rst_ for instructions on how to contribute.
.. _Ironic: https://wiki.openstack.org/wiki/Ironic
.. _PyPI: https://pypi.python.org/pypi/ironic-inspector
.. _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::
**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.
* 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
(see Usage_).
@@ -110,543 +113,12 @@ Usual hardware introspection flow is as follows:
for a given node.
* 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
package and should be done separately.
.. _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
+.. _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 `_
-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
-`_
-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 `_
-(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 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 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 `_ 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 -i ipmi_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``.
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644
index 000000000..5cdf0aaab
--- /dev/null
+++ b/doc/Makefile
@@ -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 ' where 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."
\ No newline at end of file
diff --git a/doc/source/.gitignore b/doc/source/.gitignore
new file mode 100644
index 000000000..8647666aa
--- /dev/null
+++ b/doc/source/.gitignore
@@ -0,0 +1,2 @@
+target/
+build/
\ No newline at end of file
diff --git a/doc/source/api/HTTP-API.rst b/doc/source/api/HTTP-API.rst
new file mode 100644
index 000000000..363e683e7
--- /dev/null
+++ b/doc/source/api/HTTP-API.rst
@@ -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/`` initiate hardware introspection for node
+````. 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/`` 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//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/`` get one introspection rule by its ````.
+
+ Response
+
+ * 200 - OK
+ * 404 - not found
+
+ Response body: JSON dictionary with introspection rule representation
+ (see ``POST /v1/rules`` above).
+
+* ``DELETE /v1/rules/`` delete one introspection rule by its ````.
+
+ 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.
diff --git a/doc/source/conf.py b/doc/source/conf.py
new file mode 100644
index 000000000..1b0482b4d
--- /dev/null
+++ b/doc/source/conf.py
@@ -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"
\ No newline at end of file
diff --git a/doc/source/deploy/install-guide.rst b/doc/source/deploy/install-guide.rst
new file mode 100644
index 000000000..bd319f46c
--- /dev/null
+++ b/doc/source/deploy/install-guide.rst
@@ -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 `_
+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
+`_
+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 `_
+(note usage of old name).
diff --git a/doc/source/dev/contributing_link.rst b/doc/source/dev/contributing_link.rst
new file mode 100644
index 000000000..f4e26a51c
--- /dev/null
+++ b/doc/source/dev/contributing_link.rst
@@ -0,0 +1,3 @@
+.. _contributing_link:
+
+.. include:: ../../../CONTRIBUTING.rst
\ No newline at end of file
diff --git a/doc/source/index.rst b/doc/source/index.rst
new file mode 100644
index 000000000..1c2315e45
--- /dev/null
+++ b/doc/source/index.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
+ `_.
+
+.. _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
+ Usage
+ Troubleshooting
+
+Developer Guide
+===============
+
+Introduction
+------------
+
+.. toctree::
+ :maxdepth: 1
+
+ Contribution Guide
+
+API References
+--------------
+
+.. toctree::
+ :maxdepth: 1
+
+ HTTP API description
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
diff --git a/doc/source/troubleshooting/troubleshooting.rst b/doc/source/troubleshooting/troubleshooting.rst
new file mode 100644
index 000000000..7ff8519e0
--- /dev/null
+++ b/doc/source/troubleshooting/troubleshooting.rst
@@ -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``.
diff --git a/doc/source/usage/usage.rst b/doc/source/usage/usage.rst
new file mode 100644
index 000000000..9f666c341
--- /dev/null
+++ b/doc/source/usage/usage.rst
@@ -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 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 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 `_ 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 -i ipmi_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.
\ No newline at end of file
diff --git a/releasenotes/notes/sphinx-docs-4d0a5886261e57bf.yaml b/releasenotes/notes/sphinx-docs-4d0a5886261e57bf.yaml
new file mode 100644
index 000000000..6af5d57c0
--- /dev/null
+++ b/releasenotes/notes/sphinx-docs-4d0a5886261e57bf.yaml
@@ -0,0 +1,12 @@
+---
+prelude: >
+ This release includes automatic `docs` generation via Sphinx.
+other:
+ - |
+ Introduced new docs generation via `Sphinx `_
+ and `ReST `_.
+
+ * Separate `doc` folder includes `source` and `build`
+ * Integration with `tox `_ as `docs` target
+ * `makefile` for manual building
+ * `Openstack Theme `_ support
diff --git a/setup.cfg b/setup.cfg
index 0d44a1d1a..e96361674 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -66,3 +66,8 @@ input_file = ironic-inspector/locale/ironic-inspector.pot
keywords = _ gettext ngettext l_ lazy_gettext
mapping_file = babel.cfg
output_file = ironic-inspector/locale/ironic-inspector.pot
+
+[build_sphinx]
+all_files = 1
+build-dir = doc/build
+source-dir = doc/source
diff --git a/test-requirements.txt b/test-requirements.txt
index 601a45b56..0d893f882 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -8,3 +8,4 @@ mock>=1.2
sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2
oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0
reno>=0.1.1 # Apache2
+
diff --git a/tox.ini b/tox.ini
index 4c747ceeb..dc2a1fb99 100644
--- a/tox.ini
+++ b/tox.ini
@@ -57,3 +57,10 @@ max-complexity=15
[hacking]
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