Initial commit

This patch adds initial formula that allow to install Ironic api
and conductor.

Change-Id: I21fe4cd93454ed64277ba6756a591155d0052dc8
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
new file mode 100644
index 0000000..9be1929
--- /dev/null
+++ b/CHANGELOG.rst
@@ -0,0 +1,6 @@
+ironic formula
+=========================================
+
+0.1 (2017-04-27)
+
+- Initial formula setup
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..ea2818f
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,13 @@
+Copyright (c) Mirantis Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..4a83bf8
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,35 @@
+DESTDIR=/
+SALTENVDIR=/usr/share/salt-formulas/env
+RECLASSDIR=/usr/share/salt-formulas/reclass
+FORMULANAME=$(shell grep name: metadata.yml|head -1|cut -d : -f 2|grep -Eo '[a-z0-9\-\_]*')
+
+MAKE_PID := $(shell echo $$PPID)
+JOB_FLAG := $(filter -j%, $(subst -j ,-j,$(shell ps T | grep "^\s*$(MAKE_PID).*$(MAKE)")))
+
+ifneq ($(subst -j,,$(JOB_FLAG)),)
+JOBS := $(subst -j,,$(JOB_FLAG))
+else
+JOBS := 1
+endif
+
+all:
+	@echo "make install - Install into DESTDIR"
+	@echo "make test    - Run tests"
+	@echo "make clean   - Cleanup after tests run"
+
+install:
+	# Formula
+	[ -d $(DESTDIR)/$(SALTENVDIR) ] || mkdir -p $(DESTDIR)/$(SALTENVDIR)
+	cp -a $(FORMULANAME) $(DESTDIR)/$(SALTENVDIR)/
+	[ ! -d _modules ] || cp -a _modules $(DESTDIR)/$(SALTENVDIR)/
+	[ ! -d _states ] || cp -a _states $(DESTDIR)/$(SALTENVDIR)/ || true
+	# Metadata
+	[ -d $(DESTDIR)/$(RECLASSDIR)/service/$(FORMULANAME) ] || mkdir -p $(DESTDIR)/$(RECLASSDIR)/service/$(FORMULANAME)
+	cp -a metadata/service/* $(DESTDIR)/$(RECLASSDIR)/service/$(FORMULANAME)
+
+test:
+	[ ! -d tests ] || (cd tests; ./run_tests.sh)
+
+clean:
+	[ ! -d tests/build ] || rm -rf tests/build
+	[ ! -d build ] || rm -rf build
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..1beb5ac
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,105 @@
+
+==================================
+ironic
+==================================
+
+Service ironic description
+
+Sample pillars
+==============
+
+Single ironic service
+
+.. code-block:: yaml
+
+  ironic:
+    api:
+      enabled: true
+      version: mitaka
+      bind:
+        address: 0.0.0.0
+        port: 6385
+      database:
+        engine: mysql
+        host: localhost
+        port: 3306
+        name: ironic
+        user: ironic
+        password: password
+      identity:
+        engine: keystone
+        region: RegionOne
+        host: localhost
+        port: 35357
+        user: ironic
+        password: password
+        tenant: service
+      message_queue:
+        engine: rabbitmq
+        host: localhost
+        port: 5672
+        user: openstack
+        password: password
+        virtual_host: '/openstack'
+    conductor:
+      enabled: true
+      version: mitaka
+      database:
+        engine: mysql
+        host: localhost
+        port: 3306
+        name: ironic
+        user: ironic
+        password: password
+      message_queue:
+        engine: rabbitmq
+        host: localhost
+        port: 5672
+        user: openstack
+        password: password
+        virtual_host: '/openstack'
+
+Standalone ironic without keystone
+
+.. code-block:: yaml
+
+  ironic:
+    api:
+      version: mitaka
+      enabled: true
+      bind:
+        address: 0.0.0.0
+        port: 6385
+      database:
+        engine: mysql
+        host: localhost
+        port: 3306
+        name: ironic
+        user: ironic
+        password: password
+      identity:
+        engine: noauth
+      message_queue:
+        engine: rabbitmq
+        host: localhost
+        port: 5672
+        user: openstack
+        password: password
+        virtual_host: '/openstack'
+    conductor:
+      enabled: true
+      version: mitaka
+      database:
+        engine: mysql
+        host: localhost
+        port: 3306
+        name: ironic
+        user: ironic
+        password: password
+      message_queue:
+        engine: rabbitmq
+        host: localhost
+        port: 5672
+        user: openstack
+        password: password
+        virtual_host: '/openstack'
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..49d5957
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+0.1
diff --git a/_modules/ironicng.py b/_modules/ironicng.py
new file mode 100644
index 0000000..9ed55ef
--- /dev/null
+++ b/_modules/ironicng.py
@@ -0,0 +1,136 @@
+# -*- coding: utf-8 -*-
+
+import logging
+from functools import wraps
+LOG = logging.getLogger(__name__)
+
+# Import third party libs
+HAS_IRONIC = False
+try:
+    from ironicclient import client
+    HAS_IRONIC = True
+except ImportError:
+    pass
+
+__opts__ = {}
+
+
+def __virtual__():
+    '''
+    Only load this module if ironic is installed on this minion.
+    '''
+    if HAS_IRONIC:
+        return 'ironicng'
+    return False
+
+
+def _autheticate(func_name):
+    '''
+    Authenticate requests with the salt keystone module and format return data
+    '''
+    @wraps(func_name)
+    def decorator_method(*args, **kwargs):
+        '''
+        Authenticate request and format return data
+        '''
+        connection_args = {'profile': kwargs.pop('profile', None)}
+        nkwargs = {}
+        for kwarg in kwargs:
+            if 'connection_' in kwarg:
+                connection_args.update({kwarg: kwargs[kwarg]})
+            elif '__' not in kwarg:
+                nkwargs.update({kwarg: kwargs[kwarg]})
+        kstone = __salt__['keystone.auth'](**connection_args)
+        token = kstone.auth_token
+
+        if kwargs.get('connection_endpoint_type') == None:
+            endpoint_type = 'internalURL'
+        else:
+            endpoint_type = kwargs.get('connection_endpoint_type')
+
+        endpoint = kstone.service_catalog.url_for(
+            service_type='baremetal',
+            endpoint_type=endpoint_type)
+        ironic_interface = client.get_client(
+            1,
+            ironic_url=endpoint, os_auth_token=token)
+        return func_name(ironic_interface, *args, **nkwargs)
+    return decorator_method
+
+
+@_autheticate
+def list_nodes(ironic_interface, **kwargs):
+    '''
+    list all ironic nodes
+    CLI Example:
+    .. code-block:: bash
+        salt '*' ironic.list_nodes
+    '''
+    return {'nodes': [x.to_dict() for x
+                      in ironic_interface.node.list(**kwargs)]}
+
+
+@_autheticate
+def create_node(ironic_interface, **kwargs):
+    '''
+    create ironic node
+    CLI Example:
+    .. code-block:: bash
+        salt '*' ironic.create_node
+    '''
+    return ironic_interface.node.create(**kwargs).to_dict()
+
+
+@_autheticate
+def delete_node(ironic_interface, node_id):
+    '''
+    delete ironic node
+
+    :param node_id: UUID or Name of the node.
+    CLI Example:
+    .. code-block:: bash
+        salt '*' ironic.delete_node
+    '''
+    ironic_interface.node.delete(node_id)
+
+
+@_autheticate
+def show_node(ironic_interface, node_id):
+    '''
+    show info about ironic node
+    :param node_id: UUID or Name of the node.
+    CLI Example:
+    .. code-block:: bash
+        salt '*' ironic.show_node
+    '''
+    return ironic_interface.node.get(node_id).to_dict()
+
+
+@_autheticate
+def create_port(ironic_interface, address, node_name=None,
+                node_uuid=None, **kwargs):
+    '''
+    create ironic port
+    CLI Example:
+    .. code-block:: bash
+        salt '*' ironic.crate_port
+    '''
+    node_uuid = node_uuid or ironic_interface.node.get(
+        node_name).to_dict()['uuid']
+    return ironic_interface.port.create(
+        address=address, node_uuid=node_uuid, **kwargs).to_dict()
+
+
+@_autheticate
+def list_ports(ironic_interface, **kwargs):
+    '''
+    list all ironic ports
+    CLI Example:
+    .. code-block:: bash
+        salt '*' ironic.list_ports
+    '''
+
+    return {'ports': [x.to_dict() for x
+                      in ironic_interface.port.list(**kwargs)]}
+
+
diff --git a/_states/ironicng.py b/_states/ironicng.py
new file mode 100644
index 0000000..9012c74
--- /dev/null
+++ b/_states/ironicng.py
@@ -0,0 +1,254 @@
+# -*- coding: utf-8 -*-
+'''
+Management of Ironic resources
+===============================
+:depends:   - ironicclient Python module
+:configuration: See :py:mod:`salt.modules.ironic` for setup instructions.
+.. code-block:: yaml
+    ironicng node present:
+      ironicng.node_present:
+        - name: node-1
+        - provider_physical_network: PHysnet1
+        - provider_network_type: vlan
+'''
+import logging
+from functools import wraps
+LOG = logging.getLogger(__name__)
+
+
+def __virtual__():
+    '''
+    Only load if ironic module is present in __salt__
+    '''
+    return 'ironicng' if 'ironicng.list_nodes' in __salt__ else False
+
+
+def _test_call(method):
+    (resource, functionality) = method.func_name.split('_')
+    if functionality == 'present':
+        functionality = 'updated'
+    else:
+        functionality = 'removed'
+
+    @wraps(method)
+    def check_for_testing(name, *args, **kwargs):
+        if __opts__.get('test', None):
+            return _no_change(name, resource, test=functionality)
+        return method(name, *args, **kwargs)
+    return check_for_testing
+
+
+def _ironic_module_call(method, *args, **kwargs):
+    return __salt__['ironicng.{0}'.format(method)](*args, **kwargs)
+
+def _auth(profile=None, endpoint_type=None,
+          ironic_api_version=None):
+    '''
+    Set up ironic credentials
+    '''
+    if profile:
+        credentials = __salt__['config.option'](profile)
+        user = credentials['keystone.user']
+        password = credentials['keystone.password']
+        tenant = credentials['keystone.tenant']
+        auth_url = credentials['keystone.auth_url']
+    kwargs = {
+        'connection_user': user,
+        'connection_password': password,
+        'connection_tenant': tenant,
+        'connection_auth_url': auth_url,
+        'connection_endpoint_type': endpoint_type,
+        'connection_ironic_api_version': ironic_api_version,
+        'profile': profile
+    }
+
+    return kwargs
+
+@_test_call
+def node_present(name,
+                 driver,
+                 driver_info=None,
+                 properties=None,
+                 extra=None,
+                 console_enabled=None,
+                 resource_class=None,
+                 boot_interface=None,
+                 console_interface=None,
+                 deploy_interface=None,
+                 inspect_interface=None,
+                 management_interface=None,
+                 network_interface=None,
+                 power_interface=None,
+                 raid_interface=None,
+                 vendor_interface=None,
+                 maintenance=None,
+                 maintenance_reason=None,
+                 ports=None,
+                 profile=None,
+                 endpoint_type=None,
+                 ironic_api_version=None):
+    '''
+    Ensure that the ironic node is present with the specified properties.
+    '''
+    connection_args = _auth(profile, endpoint_type,
+                            ironic_api_version=ironic_api_version)
+
+    existing_nodes = _ironic_module_call(
+        'list_nodes', detail=True, **connection_args)['nodes']
+    existing_nodes = [node for node in existing_nodes if node['name'] == name]
+
+    node_arguments = _get_non_null_args(
+        name=name,
+        driver=driver,
+        driver_info=driver_info,
+        properties=properties,
+        extra=extra,
+        console_enabled=console_enabled,
+        resource_class=resource_class,
+        boot_interface=boot_interface,
+        console_interface=console_interface,
+        deploy_interface=deploy_interface,
+        inspect_interface=inspect_interface,
+        management_interface=management_interface,
+        network_interface=network_interface,
+        power_interface=power_interface,
+        raid_interface=raid_interface,
+        vendor_interface=vendor_interface,
+        maintenance=maintenance,
+        maintenance_reason=maintenance_reason)
+
+    # In ironic node names are unique
+    if len(existing_nodes) == 0:
+        node_arguments.update(connection_args)
+        res = _ironic_module_call(
+            'create_node', **node_arguments)
+
+        if res.get('name') == name:
+            return _created(name, 'node', res)
+
+    elif len(existing_nodes) == 1:
+        # TODO(vsaienko) add update with deep comparison
+        return _no_change(name, 'node')
+        existing_node = existing_nodes[0]
+    return _create_failed(name, 'node')
+
+
+@_test_call
+def node_absent(name, uuid=None, profile=None, endpoint_type=None):
+    connection_args = _auth(profile, endpoint_type)
+    identifier = uuid or name
+    _ironic_module_call(
+        'delete_node', identifier, **connection_args)
+    return _absent(identifier, 'node')
+
+@_test_call
+def port_present(name,
+                 address,
+                 node_name=None,
+                 node_uuid=None,
+                 local_link_connection=None,
+                 extra=None,
+                 profile=None,
+                 endpoint_type=None, ironic_api_version=None):
+    connection_args = _auth(profile, endpoint_type,
+                            ironic_api_version=ironic_api_version)
+    identifier = node_uuid or node_name
+    existing_ports =  _ironic_module_call('list_ports', detail=True,
+                                          address=address,
+                                          **connection_args)['ports']
+    # we filtered ports by address, so if port found only one item will
+    # exist since address is unique.
+    existing_port = existing_ports[0] if len(existing_ports) else {}
+
+    existing_node = _ironic_module_call('show_node', node_id=identifier,
+        **connection_args)
+
+    port_arguments = _get_non_null_args(
+            address=address,
+            node_uuid=existing_node['uuid'],
+            local_link_connection=local_link_connection,
+            extra=extra)
+
+    if not existing_port:
+        port_arguments.update(connection_args)
+        res = _ironic_module_call('create_port', **port_arguments)
+        return _created(address, 'port', res)
+    else:
+        # generate differential
+        # TODO(vsaienko) add update with deep comparison
+        return _no_change(address, 'port')
+
+def _created(name, resource, resource_definition):
+    changes_dict = {'name': name,
+                    'changes': resource_definition,
+                    'result': True,
+                    'comment': '{0} {1} created'.format(resource, name)}
+    return changes_dict
+
+def _updated(name, resource, resource_definition):
+    changes_dict = {'name': name,
+                    'changes': resource_definition,
+                    'result': True,
+                    'comment': '{0} {1} updated'.format(resource, name)}
+    return changes_dict
+
+def _no_change(name, resource, test=False):
+    changes_dict = {'name': name,
+                    'changes': {},
+                    'result': True}
+    if test:
+        changes_dict['comment'] = \
+            '{0} {1} will be {2}'.format(resource, name, test)
+    else:
+        changes_dict['comment'] = \
+            '{0} {1} is in correct state'.format(resource, name)
+    return changes_dict
+
+
+def _deleted(name, resource, resource_definition):
+    changes_dict = {'name': name,
+                    'changes': {},
+                    'comment': '{0} {1} removed'.format(resource, name),
+                    'result': True}
+    return changes_dict
+
+
+def _absent(name, resource):
+    changes_dict = {'name': name,
+                    'changes': {},
+                    'comment': '{0} {1} not present'.format(resource, name),
+                    'result': True}
+    return changes_dict
+
+
+def _delete_failed(name, resource):
+    changes_dict = {'name': name,
+                    'changes': {},
+                    'comment': '{0} {1} failed to delete'.format(resource,
+                                                                 name),
+                    'result': False}
+    return changes_dict
+
+def _create_failed(name, resource):
+    changes_dict = {'name': name,
+                    'changes': {},
+                    'comment': '{0} {1} failed to create'.format(resource,
+                                                                 name),
+                    'result': False}
+    return changes_dict
+
+def _update_failed(name, resource):
+    changes_dict = {'name': name,
+                    'changes': {},
+                    'comment': '{0} {1} failed to update'.format(resource,
+                                                                 name),
+                    'result': False}
+    return changes_dict
+
+
+def _get_non_null_args(**kwargs):
+    '''
+    Return those kwargs which are not null
+    '''
+    return dict((key, value,) for key, value in kwargs.iteritems()
+                if value is not None)
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..214009a
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,5 @@
+salt-formula-ironic (0.1) trusty; urgency=medium
+
+  * Initial release
+
+ -- Vasyl Saienko <vsaienko@mirantis.com>  Thu, 27 Apr 2017 23:23:41 +0200
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..ec63514
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+9
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..f31c779
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,15 @@
+Source: salt-formula-ironic
+Maintainer: moc-ironic <mos-ironic@mirantis.com>
+Section: admin
+Priority: optional
+Build-Depends: debhelper (>= 9), salt-master, python, python-yaml
+Standards-Version: 3.9.6
+Homepage: https://www.mirantis.com/
+Vcs-Browser: https://github.com/salt-formulas/salt-formula-ironic
+Vcs-Git: https://github.com/salt-formulas/salt-formula-ironic.git
+
+Package: salt-formula-ironic
+Architecture: all
+Depends: ${misc:Depends}, salt-master, reclass
+Description: ironic salt formula
+ Install and configure ironic system.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..904c048
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,15 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: salt-formula-ironic
+Upstream-Contact:
+Source: https://github.com/salt-formulas/salt-formula-ironic
+
+Files: *
+Copyright: Mirantis Inc.
+License: Apache-2.0
+  Copyright (C) Mirantis Inc.
+  .
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  .
+  On a Debian system you can find a copy of this license in
+  /usr/share/common-licenses/Apache-2.0.
diff --git a/debian/docs b/debian/docs
new file mode 100644
index 0000000..d585829
--- /dev/null
+++ b/debian/docs
@@ -0,0 +1,3 @@
+README.rst
+CHANGELOG.rst
+VERSION
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..abde6ef
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,5 @@
+#!/usr/bin/make -f
+
+%:
+	dh $@
+
diff --git a/debian/source/format b/debian/source/format
new file mode 100644
index 0000000..89ae9db
--- /dev/null
+++ b/debian/source/format
@@ -0,0 +1 @@
+3.0 (native)
diff --git a/doc/source/conf.py b/doc/source/conf.py
new file mode 100644
index 0000000..f868efd
--- /dev/null
+++ b/doc/source/conf.py
@@ -0,0 +1,73 @@
+# -*- coding: utf-8 -*-
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import sys
+
+sys.path.insert(0, os.path.abspath('../..'))
+# -- 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',
+]
+
+# 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
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'salt-formula-ironic'
+copyright = u'2017, Mirantis Inc.'
+
+# 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'
+
+# -- 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'),
+]
+
+# Example configuration for intersphinx: refer to the Python standard library.
+# intersphinx_mapping = {'http://docs.python.org/': None}
diff --git a/doc/source/index.rst b/doc/source/index.rst
new file mode 100644
index 0000000..a6210d3
--- /dev/null
+++ b/doc/source/index.rst
@@ -0,0 +1 @@
+.. include:: ../../README.rst
diff --git a/ironic/_common.sls b/ironic/_common.sls
new file mode 100644
index 0000000..e549ac4
--- /dev/null
+++ b/ironic/_common.sls
@@ -0,0 +1,18 @@
+{%- from "ironic/map.jinja" import api,conductor with context %}
+{%- if api.get("enabled", False) %}
+  {%- set ironic = api %}
+{%- elif conductor.get('enabled', False) %}
+  {%- set ironic = conductor %}
+{%- endif %}
+
+ironic_common_pkgs:
+  pkg.installed:
+    - name: 'ironic-common'
+    - install_recommends: False
+
+/etc/ironic/ironic.conf:
+  file.managed:
+  - source: salt://ironic/files/{{ ironic.version }}/ironic.conf
+  - template: jinja
+  - require:
+    - pkg: ironic_common_pkgs
diff --git a/ironic/api.sls b/ironic/api.sls
new file mode 100644
index 0000000..96af429
--- /dev/null
+++ b/ironic/api.sls
@@ -0,0 +1,24 @@
+{%- from "ironic/map.jinja" import api with context %}
+{%- if api.enabled %}
+include:
+  - ironic._common
+
+ironic_api_packages:
+  pkg.installed:
+  - names: {{ api.pkgs }}
+  - install_recommends: False
+
+ironic_install_database:
+  cmd.run:
+  - names:
+    - ironic-dbsync --config-file /etc/ironic/ironic.conf upgrade
+  - require:
+    - file: /etc/ironic/ironic.conf
+
+{{ api.service }}:
+  service.running:
+    - enable: true
+    - full_restart: true
+    - watch:
+      - file: /etc/ironic/ironic.conf
+{%- endif %}
diff --git a/ironic/client.sls b/ironic/client.sls
new file mode 100644
index 0000000..8a672d2
--- /dev/null
+++ b/ironic/client.sls
@@ -0,0 +1,33 @@
+{%- from "ironic/map.jinja" import client with context %}
+{%- if client.enabled %}
+
+ironic_client_pkg:
+  pkg.installed:
+    - names: {{ client.pkgs }}
+    - install_recommends: False
+
+{%- for identity_name, nodes in client.nodes.iteritems() %}
+  {%- for node in nodes %}
+
+node_{{ node.name }}_present:
+  ironicng.node_present:
+    - name: {{ node.name }}
+    - driver: {{ node.driver }}
+    - properties: {{ node.properties }}
+    - profile: {{ identity_name }}
+    - driver_info: {{ node.driver_info }}
+
+  {%- for port in node.ports %}
+
+{{ node.name }}_port{{ loop.index }}_present:
+  ironicng.port_present:
+    - address: {{ port.address }}
+    - node_name: {{ node.name }}
+    - profile: {{ identity_name }}
+
+  {%- endfor %} # end for ports
+
+  {%- endfor %} # end for nodes
+{%- endfor %} # end client.nodes.iteritems
+
+{%- endif %} # end if client.enabled
diff --git a/ironic/conductor.sls b/ironic/conductor.sls
new file mode 100644
index 0000000..c4093dc
--- /dev/null
+++ b/ironic/conductor.sls
@@ -0,0 +1,71 @@
+{%- from "ironic/map.jinja" import conductor with context %}
+{%- if conductor.enabled %}
+include:
+  - ironic._common
+
+ironic_conductor_packages:
+  pkg.installed:
+  - names: {{ conductor.pkgs }}
+  - install_recommends: False
+
+{{ conductor.service }}:
+  service.running:
+    - enable: true
+    - full_restart: true
+    - watch:
+      - file: /etc/ironic/ironic.conf
+
+ironic_dirs:
+  file.directory:
+    - names:
+      - {{ conductor.tftp_root }}
+      - {{ conductor.http_root }}
+      makedirs: True
+      user: 'ironic'
+      group: 'ironic'
+    - require:
+      - pkg: ironic_conductor_packages
+
+ironic_copy_pxelinux.0:
+  file.managed:
+    - name: {{ conductor.tftp_root }}/pxelinux.0
+    - source: {{ conductor.pxelinux_path }}/pxelinux.0
+    - user: 'ironic'
+    - group: 'ironic'
+    - require:
+      - file: ironic_dirs
+
+{% for file in conductor.syslinux_files %}
+ironic_copy_{{ file }}:
+  file.managed:
+    - name: {{ conductor.tftp_root }}/{{ file }}
+    - source: {{ conductor.syslinux_path }}/{{ file }}
+    - user: 'ironic'
+    - group: 'ironic'
+    - require:
+      - file: ironic_dirs
+{%- endfor %}
+
+{% for file in conductor.ipxe_rom_files %}
+ironic_copy_{{ file }}:
+  file.managed:
+    - name: {{ conductor.tftp_root }}/{{ file }}
+    - source: {{ conductor.ipxe_rom_path }}/{{ file }}
+    - user: 'ironic'
+    - group: 'ironic'
+    - require:
+      - file: ironic_dirs
+{%- endfor %}
+
+ironic_tftp_map_file:
+  file.managed:
+    - name: {{ conductor.tftp_root }}/map-file
+    - contents: |
+        r ^([^/]) {{ conductor.tftp_root }}/\\1
+        r ^(/tftpboot/) {{ conductor.tftp_root }}/\2
+    - user: 'ironic'
+    - group: 'ironic'
+    - require:
+      - file: ironic_dirs
+
+{%- endif %}
diff --git a/ironic/files/newton/ironic.conf b/ironic/files/newton/ironic.conf
new file mode 100644
index 0000000..2a40f9e
--- /dev/null
+++ b/ironic/files/newton/ironic.conf
@@ -0,0 +1,3616 @@
+{%- from "ironic/map.jinja" import api,conductor with context -%}
+{%- if api.get("enabled", False) %}
+  {%- set ironic = api %}
+{%- elif conductor.get('enabled', False) %}
+  {%- set ironic = conductor %}
+{%- endif %}
+[DEFAULT]
+
+#
+# From ironic
+#
+
+# Authentication strategy used by ironic-api. "noauth" should
+# not be used in a production environment because all
+# authentication will be disabled. (string value)
+# Allowed values: noauth, keystone
+{%- if ironic.identity is defined %}
+auth_strategy = {{ ironic.identity.engine }}
+{%- else %}
+#auth_strategy = keystone
+{%- endif %}
+
+# Specify the list of drivers to load during service
+# initialization. Missing drivers, or drivers which fail to
+# initialize, will prevent the conductor service from
+# starting. The option default is a recommended set of
+# production-oriented drivers. A complete list of drivers
+# present on your system may be found by enumerating the
+# "ironic.drivers" entrypoint. An example may be found in the
+# developer documentation online. (list value)
+{%- if conductor.get('enabled_drivers') %}
+enabled_drivers = {{ ','.join(conductor.enabled_drivers) }}
+{%- else %}
+#enabled_drivers = pxe_ipmitool
+{%- endif %}
+
+# Specify the list of network interfaces to load during
+# service initialization. Missing network interfaces, or
+# network interfaces which fail to initialize, will prevent
+# the ironic-conductor service from starting. At least one
+# network interface that is supported by each enabled hardware
+# type must be enabled here, or the ironic-conductor service
+# will not start. Must not be an empty list. The default value
+# is a recommended set of production-oriented network
+# interfaces. A complete list of network interfaces present on
+# your system may be found by enumerating the
+# "ironic.hardware.interfaces.network" entrypoint. When
+# setting this value, please make sure that every enabled
+# hardware type will have the same set of enabled network
+# interfaces on every ironic-conductor service. (list value)
+{%- if conductor.get('enabled_network_interfaces') %}
+enabled_network_interfaces = {{ ','.join(conductor.enabled_network_interfaces) }}
+{%- else %}
+#enabled_network_interfaces = flat,noop
+{%- endif %}
+
+# Default network interface to be used for nodes that do not
+# have network_interface field set. A complete list of network
+# interfaces present on your system may be found by
+# enumerating the "ironic.hardware.interfaces.network"
+# entrypoint. (string value)
+{%- if conductor.get('default_network_interface') %}
+default_network_interface = {{ conductor.default_network_interface }}
+{%- else %}
+#default_network_interface = <None>
+{%- endif %}
+
+# Used if there is a formatting error when generating an
+# exception message (a programming error). If True, raise an
+# exception; if False, use the unformatted message. (boolean
+# value)
+#fatal_exception_format_errors = false
+
+# Exponent to determine number of hash partitions to use when
+# distributing load across conductors. Larger values will
+# result in more even distribution of load and less load when
+# rebalancing the ring, but more memory usage. Number of
+# partitions per conductor is (2^hash_partition_exponent).
+# This determines the granularity of rebalancing: given 10
+# hosts, and an exponent of the 2, there are 40 partitions in
+# the ring.A few thousand partitions should make rebalancing
+# smooth in most cases. The default is suitable for up to a
+# few hundred conductors. Configuring for too many partitions
+# has a negative impact on CPU usage. (integer value)
+#hash_partition_exponent = 5
+
+# [Experimental Feature] Number of hosts to map onto each hash
+# partition. Setting this to more than one will cause
+# additional conductor services to prepare deployment
+# environments and potentially allow the Ironic cluster to
+# recover more quickly if a conductor instance is terminated.
+# (integer value)
+#hash_distribution_replicas = 1
+
+# Interval (in seconds) between hash ring resets. (integer
+# value)
+#hash_ring_reset_interval = 180
+
+# If True, convert backing images to "raw" disk image format.
+# (boolean value)
+#force_raw_images = true
+
+# Path to isolinux binary file. (string value)
+#isolinux_bin = /usr/lib/syslinux/isolinux.bin
+
+# Template file for isolinux configuration file. (string
+# value)
+#isolinux_config_template = $pybasedir/common/isolinux_common.template
+
+# Template file for grub configuration file. (string value)
+#grub_config_template = $pybasedir/common/grub_conf.template
+
+# Run image downloads and raw format conversions in parallel.
+# (boolean value)
+#parallel_image_downloads = false
+
+# IP address of this host. If unset, will determine the IP
+# programmatically. If unable to do so, will use "127.0.0.1".
+# (string value)
+#my_ip = 127.0.0.1
+
+# Specifies the minimum level for which to send notifications.
+# If not set, no notifications will be sent. The default is
+# for this option to be unset. (string value)
+# Allowed values: debug, info, warning, error, critical
+#notification_level = <None>
+
+# Directory where the ironic python module is installed.
+# (string value)
+#pybasedir = /usr/lib/python/site-packages/ironic/ironic
+
+# Directory where ironic binaries are installed. (string
+# value)
+#bindir = $pybasedir/bin
+
+# Top-level directory for maintaining ironic's state. (string
+# value)
+#state_path = $pybasedir
+
+# Name of this node. This can be an opaque identifier. It is
+# not necessarily a hostname, FQDN, or IP address. However,
+# the node name must be valid within an AMQP key, and if using
+# ZeroMQ, a valid hostname, FQDN, or IP address. (string
+# value)
+# host = localhost
+
+# Path to the rootwrap configuration file to use for running
+# commands as root. (string value)
+#rootwrap_config = /etc/ironic/rootwrap.conf
+
+# Temporary working directory, default is Python temp dir.
+# (string value)
+#tempdir = /tmp
+
+#
+# From oslo.log
+#
+
+# If set to true, the logging level will be set to DEBUG
+# instead of the default INFO level. (boolean value)
+# Note: This option can be changed without restarting.
+{%- if ironic.logging is defined and ironic.logging.debug is defined %}
+debug = {{ ironic.logging.debug }}
+{%- else %}
+#debug = false
+{%- endif %}
+
+# The name of a logging configuration file. This file is
+# appended to any existing logging configuration files. For
+# details about logging configuration files, see the Python
+# logging module documentation. Note that when logging
+# configuration files are used then all logging configuration
+# is set in the configuration file and other logging
+# configuration options are ignored (for example,
+# logging_context_format_string). (string value)
+# Note: This option can be changed without restarting.
+# Deprecated group/name - [DEFAULT]/log_config
+#log_config_append = <None>
+
+# Defines the format string for %%(asctime)s in log records.
+# Default: %(default)s . This option is ignored if
+# log_config_append is set. (string value)
+#log_date_format = %Y-%m-%d %H:%M:%S
+
+# (Optional) Name of log file to send logging output to. If no
+# default is set, logging will go to stderr as defined by
+# use_stderr. This option is ignored if log_config_append is
+# set. (string value)
+# Deprecated group/name - [DEFAULT]/logfile
+#log_file = <None>
+
+# (Optional) The base directory used for relative log_file
+# paths. This option is ignored if log_config_append is set.
+# (string value)
+# Deprecated group/name - [DEFAULT]/logdir
+#log_dir = <None>
+
+# Uses logging handler designed to watch file system. When log
+# file is moved or removed this handler will open a new log
+# file with specified path instantaneously. It makes sense
+# only if log_file option is specified and Linux platform is
+# used. This option is ignored if log_config_append is set.
+# (boolean value)
+#watch_log_file = false
+
+# Use syslog for logging. Existing syslog format is DEPRECATED
+# and will be changed later to honor RFC5424. This option is
+# ignored if log_config_append is set. (boolean value)
+#use_syslog = false
+
+# Syslog facility to receive log lines. This option is ignored
+# if log_config_append is set. (string value)
+#syslog_log_facility = LOG_USER
+
+# Log output to standard error. This option is ignored if
+# log_config_append is set. (boolean value)
+#use_stderr = false
+
+# Format string to use for log messages with context. (string
+# value)
+#logging_context_format_string = %(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [%(request_id)s %(user_identity)s] %(instance)s%(message)s
+
+# Format string to use for log messages when context is
+# undefined. (string value)
+#logging_default_format_string = %(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [-] %(instance)s%(message)s
+
+# Additional data to append to log message when logging level
+# for the message is DEBUG. (string value)
+#logging_debug_format_suffix = %(funcName)s %(pathname)s:%(lineno)d
+
+# Prefix each line of exception output with this format.
+# (string value)
+#logging_exception_prefix = %(asctime)s.%(msecs)03d %(process)d ERROR %(name)s %(instance)s
+
+# Defines the format string for %(user_identity)s that is used
+# in logging_context_format_string. (string value)
+#logging_user_identity_format = %(user)s %(tenant)s %(domain)s %(user_domain)s %(project_domain)s
+
+# List of package logging levels in logger=LEVEL pairs. This
+# option is ignored if log_config_append is set. (list value)
+#default_log_levels = amqp=WARN,amqplib=WARN,boto=WARN,qpid=WARN,sqlalchemy=WARN,suds=INFO,oslo.messaging=INFO,iso8601=WARN,requests.packages.urllib3.connectionpool=WARN,urllib3.connectionpool=WARN,websocket=WARN,requests.packages.urllib3.util.retry=WARN,urllib3.util.retry=WARN,keystonemiddleware=WARN,routes.middleware=WARN,stevedore=WARN,taskflow=WARN,keystoneauth=WARN,oslo.cache=INFO,dogpile.core.dogpile=INFO
+
+# Enables or disables publication of error events. (boolean
+# value)
+#publish_errors = false
+
+# The format for an instance that is passed with the log
+# message. (string value)
+#instance_format = "[instance: %(uuid)s] "
+
+# The format for an instance UUID that is passed with the log
+# message. (string value)
+#instance_uuid_format = "[instance: %(uuid)s] "
+
+# Interval, number of seconds, of log rate limiting. (integer
+# value)
+#rate_limit_interval = 0
+
+# Maximum number of logged messages per rate_limit_interval.
+# (integer value)
+#rate_limit_burst = 0
+
+# Log level name used by rate limiting: CRITICAL, ERROR, INFO,
+# WARNING, DEBUG or empty string. Logs with level greater or
+# equal to rate_limit_except_level are not filtered. An empty
+# string means that all levels are filtered. (string value)
+#rate_limit_except_level = CRITICAL
+
+# Enables or disables fatal status of deprecations. (boolean
+# value)
+#fatal_deprecations = false
+
+#
+# From oslo.messaging
+#
+
+# Size of RPC connection pool. (integer value)
+# Deprecated group/name - [DEFAULT]/rpc_conn_pool_size
+#rpc_conn_pool_size = 30
+
+# The pool size limit for connections expiration policy
+# (integer value)
+#conn_pool_min_size = 2
+
+# The time-to-live in sec of idle connections in the pool
+# (integer value)
+#conn_pool_ttl = 1200
+
+# ZeroMQ bind address. Should be a wildcard (*), an ethernet
+# interface, or IP. The "host" option should point or resolve
+# to this address. (string value)
+# Deprecated group/name - [DEFAULT]/rpc_zmq_bind_address
+#rpc_zmq_bind_address = *
+
+# MatchMaker driver. (string value)
+# Allowed values: redis, sentinel, dummy
+# Deprecated group/name - [DEFAULT]/rpc_zmq_matchmaker
+#rpc_zmq_matchmaker = redis
+
+# Number of ZeroMQ contexts, defaults to 1. (integer value)
+# Deprecated group/name - [DEFAULT]/rpc_zmq_contexts
+#rpc_zmq_contexts = 1
+
+# Maximum number of ingress messages to locally buffer per
+# topic. Default is unlimited. (integer value)
+# Deprecated group/name - [DEFAULT]/rpc_zmq_topic_backlog
+#rpc_zmq_topic_backlog = <None>
+
+# Directory for holding IPC sockets. (string value)
+# Deprecated group/name - [DEFAULT]/rpc_zmq_ipc_dir
+#rpc_zmq_ipc_dir = /var/run/openstack
+
+# Name of this node. Must be a valid hostname, FQDN, or IP
+# address. Must match "host" option, if running Nova. (string
+# value)
+# Deprecated group/name - [DEFAULT]/rpc_zmq_host
+#rpc_zmq_host = localhost
+
+# Number of seconds to wait before all pending messages will
+# be sent after closing a socket. The default value of -1
+# specifies an infinite linger period. The value of 0
+# specifies no linger period. Pending messages shall be
+# discarded immediately when the socket is closed. Positive
+# values specify an upper bound for the linger period.
+# (integer value)
+# Deprecated group/name - [DEFAULT]/rpc_cast_timeout
+#zmq_linger = -1
+
+# The default number of seconds that poll should wait. Poll
+# raises timeout exception when timeout expired. (integer
+# value)
+# Deprecated group/name - [DEFAULT]/rpc_poll_timeout
+#rpc_poll_timeout = 1
+
+# Expiration timeout in seconds of a name service record about
+# existing target ( < 0 means no timeout). (integer value)
+# Deprecated group/name - [DEFAULT]/zmq_target_expire
+#zmq_target_expire = 300
+
+# Update period in seconds of a name service record about
+# existing target. (integer value)
+# Deprecated group/name - [DEFAULT]/zmq_target_update
+#zmq_target_update = 180
+
+# Use PUB/SUB pattern for fanout methods. PUB/SUB always uses
+# proxy. (boolean value)
+# Deprecated group/name - [DEFAULT]/use_pub_sub
+#use_pub_sub = false
+
+# Use ROUTER remote proxy. (boolean value)
+# Deprecated group/name - [DEFAULT]/use_router_proxy
+#use_router_proxy = false
+
+# This option makes direct connections dynamic or static. It
+# makes sense only with use_router_proxy=False which means to
+# use direct connections for direct message types (ignored
+# otherwise). (boolean value)
+#use_dynamic_connections = false
+
+# How many additional connections to a host will be made for
+# failover reasons. This option is actual only in dynamic
+# connections mode. (integer value)
+#zmq_failover_connections = 2
+
+# Minimal port number for random ports range. (port value)
+# Minimum value: 0
+# Maximum value: 65535
+# Deprecated group/name - [DEFAULT]/rpc_zmq_min_port
+#rpc_zmq_min_port = 49153
+
+# Maximal port number for random ports range. (integer value)
+# Minimum value: 1
+# Maximum value: 65536
+# Deprecated group/name - [DEFAULT]/rpc_zmq_max_port
+#rpc_zmq_max_port = 65536
+
+# Number of retries to find free port number before fail with
+# ZMQBindError. (integer value)
+# Deprecated group/name - [DEFAULT]/rpc_zmq_bind_port_retries
+#rpc_zmq_bind_port_retries = 100
+
+# Default serialization mechanism for
+# serializing/deserializing outgoing/incoming messages (string
+# value)
+# Allowed values: json, msgpack
+# Deprecated group/name - [DEFAULT]/rpc_zmq_serialization
+#rpc_zmq_serialization = json
+
+# This option configures round-robin mode in zmq socket. True
+# means not keeping a queue when server side disconnects.
+# False means to keep queue and messages even if server is
+# disconnected, when the server appears we send all
+# accumulated messages to it. (boolean value)
+#zmq_immediate = true
+
+# Enable/disable TCP keepalive (KA) mechanism. The default
+# value of -1 (or any other negative value) means to skip any
+# overrides and leave it to OS default; 0 and 1 (or any other
+# positive value) mean to disable and enable the option
+# respectively. (integer value)
+#zmq_tcp_keepalive = -1
+
+# The duration between two keepalive transmissions in idle
+# condition. The unit is platform dependent, for example,
+# seconds in Linux, milliseconds in Windows etc. The default
+# value of -1 (or any other negative value and 0) means to
+# skip any overrides and leave it to OS default. (integer
+# value)
+#zmq_tcp_keepalive_idle = -1
+
+# The number of retransmissions to be carried out before
+# declaring that remote end is not available. The default
+# value of -1 (or any other negative value and 0) means to
+# skip any overrides and leave it to OS default. (integer
+# value)
+#zmq_tcp_keepalive_cnt = -1
+
+# The duration between two successive keepalive
+# retransmissions, if acknowledgement to the previous
+# keepalive transmission is not received. The unit is platform
+# dependent, for example, seconds in Linux, milliseconds in
+# Windows etc. The default value of -1 (or any other negative
+# value and 0) means to skip any overrides and leave it to OS
+# default. (integer value)
+#zmq_tcp_keepalive_intvl = -1
+
+# Maximum number of (green) threads to work concurrently.
+# (integer value)
+#rpc_thread_pool_size = 100
+
+# Expiration timeout in seconds of a sent/received message
+# after which it is not tracked anymore by a client/server.
+# (integer value)
+#rpc_message_ttl = 300
+
+# Wait for message acknowledgements from receivers. This
+# mechanism works only via proxy without PUB/SUB. (boolean
+# value)
+#rpc_use_acks = false
+
+# Number of seconds to wait for an ack from a cast/call. After
+# each retry attempt this timeout is multiplied by some
+# specified multiplier. (integer value)
+#rpc_ack_timeout_base = 15
+
+# Number to multiply base ack timeout by after each retry
+# attempt. (integer value)
+#rpc_ack_timeout_multiplier = 2
+
+# Default number of message sending attempts in case of any
+# problems occurred: positive value N means at most N retries,
+# 0 means no retries, None or -1 (or any other negative
+# values) mean to retry forever. This option is used only if
+# acknowledgments are enabled. (integer value)
+#rpc_retry_attempts = 3
+
+# List of publisher hosts SubConsumer can subscribe on. This
+# option has higher priority then the default publishers list
+# taken from the matchmaker. (list value)
+#subscribe_on =
+
+# Size of executor thread pool. (integer value)
+# Deprecated group/name - [DEFAULT]/rpc_thread_pool_size
+#executor_thread_pool_size = 64
+
+# Seconds to wait for a response from a call. (integer value)
+#rpc_response_timeout = 60
+
+# A URL representing the messaging driver to use and its full
+# configuration. (string value)
+{%- set mq = ironic.message_queue %}
+{%- set rmq_port = mq.get('port', 5672) %}
+{%- if mq.members is defined %}
+transport_url = rabbit://{% for member in mq.members -%}
+                         {{ mq.user }}:{{ mq.password }}@{{ member.host }}:{{ member.get('port', rmq_port) }}
+                         {%- if not loop.last -%},{%- endif -%}
+                         {%- endfor -%}/{{ mq.virtual_host }}
+{%- else %}
+transport_url = rabbit://{{ mq.user }}:{{ mq.password }}@{{ mq.host }}:{{ rmq_port }}/{{ mq.virtual_host }}
+{%- endif %}
+
+# The default exchange under which topics are scoped. May be
+# overridden by an exchange name specified in the
+# transport_url option. (string value)
+#control_exchange = openstack
+
+#
+# From oslo.service.periodic_task
+#
+
+# Some periodic tasks can be run in a separate process. Should
+# we run them here? (boolean value)
+#run_external_periodic_tasks = true
+
+#
+# From oslo.service.service
+#
+
+# Enable eventlet backdoor. Acceptable values are 0, <port>,
+# and <start>:<end>, where 0 results in listening on a random
+# tcp port number; <port> results in listening on the
+# specified port number (and not enabling backdoor if that
+# port is in use); and <start>:<end> results in listening on
+# the smallest unused port number within the specified range
+# of port numbers. The chosen port is displayed in the
+# service's log file. (string value)
+#backdoor_port = <None>
+
+# Enable eventlet backdoor, using the provided path as a unix
+# socket that can receive connections. This option is mutually
+# exclusive with 'backdoor_port' in that only one should be
+# provided. If both are provided then the existence of this
+# option overrides the usage of that option. (string value)
+#backdoor_socket = <None>
+
+# Enables or disables logging values of all registered options
+# when starting a service (at DEBUG level). (boolean value)
+#log_options = true
+
+# Specify a timeout after which a gracefully shutdown server
+# will exit. Zero value means endless wait. (integer value)
+#graceful_shutdown_timeout = 60
+
+
+[agent]
+
+#
+# From ironic
+#
+
+# Whether Ironic will manage booting of the agent ramdisk. If
+# set to False, you will need to configure your mechanism to
+# allow booting the agent ramdisk. (boolean value)
+#manage_agent_boot = true
+
+# The memory size in MiB consumed by agent when it is booted
+# on a bare metal node. This is used for checking if the image
+# can be downloaded and deployed on the bare metal node after
+# booting agent ramdisk. This may be set according to the
+# memory consumed by the agent ramdisk image. (integer value)
+#memory_consumed_by_agent = 0
+
+# Whether the agent ramdisk should stream raw images directly
+# onto the disk or not. By streaming raw images directly onto
+# the disk the agent ramdisk will not spend time copying the
+# image to a tmpfs partition (therefore consuming less memory)
+# prior to writing it to the disk. Unless the disk where the
+# image will be copied to is really slow, this option should
+# be set to True. Defaults to True. (boolean value)
+#stream_raw_images = true
+
+# Number of times to retry getting power state to check if
+# bare metal node has been powered off after a soft power off.
+# (integer value)
+#post_deploy_get_power_state_retries = 6
+
+# Amount of time (in seconds) to wait between polling power
+# state after trigger soft poweroff. (integer value)
+#post_deploy_get_power_state_retry_interval = 5
+
+# API version to use for communicating with the ramdisk agent.
+# (string value)
+#agent_api_version = v1
+
+# Whether Ironic should collect the deployment logs on
+# deployment failure (on_failure), always or never. (string
+# value)
+# Allowed values: always, on_failure, never
+#deploy_logs_collect = on_failure
+
+# The name of the storage backend where the logs will be
+# stored. (string value)
+# Allowed values: local, swift
+#deploy_logs_storage_backend = local
+
+# The path to the directory where the logs should be stored,
+# used when the deploy_logs_storage_backend is configured to
+# "local". (string value)
+#deploy_logs_local_path = /var/log/ironic/deploy
+
+# The name of the Swift container to store the logs, used when
+# the deploy_logs_storage_backend is configured to "swift".
+# (string value)
+#deploy_logs_swift_container = ironic_deploy_logs_container
+
+# Number of days before a log object is marked as expired in
+# Swift. If None, the logs will be kept forever or until
+# manually deleted. Used when the deploy_logs_storage_backend
+# is configured to "swift". (integer value)
+#deploy_logs_swift_days_to_expire = 30
+
+
+[api]
+
+#
+# From ironic
+#
+
+# The IP address on which ironic-api listens. (string value)
+{%- if api.get('bind', {}).get('address') %}
+host_ip = {{ api.bind.address }}
+{%- else %}
+#host_ip = 0.0.0.0
+{%- endif %}
+
+# The TCP port on which ironic-api listens. (port value)
+# Minimum value: 0
+# Maximum value: 65535
+{%- if api.get('bind', {}).get('port') %}
+port = {{ api.bind.port }}
+{%- else %}
+#port = 6385
+{%- endif %}
+
+# The maximum number of items returned in a single response
+# from a collection resource. (integer value)
+#max_limit = 1000
+
+# Public URL to use when building the links to the API
+# resources (for example, "https://ironic.rocks:6384"). If
+# None the links will be built using the request's host URL.
+# If the API is operating behind a proxy, you will want to
+# change this to represent the proxy's URL. Defaults to None.
+# (string value)
+#public_endpoint = <None>
+
+# Number of workers for OpenStack Ironic API service. The
+# default is equal to the number of CPUs available if that can
+# be determined, else a default worker count of 1 is returned.
+# (integer value)
+#api_workers = <None>
+
+# Enable the integrated stand-alone API to service requests
+# via HTTPS instead of HTTP. If there is a front-end service
+# performing HTTPS offloading from the service, this option
+# should be False; note, you will want to change public API
+# endpoint to represent SSL termination URL with
+# 'public_endpoint' option. (boolean value)
+#enable_ssl_api = false
+
+# Whether to restrict the lookup API to only nodes in certain
+# states. (boolean value)
+#restrict_lookup = true
+
+# Maximum interval (in seconds) for agent heartbeats. (integer
+# value)
+# Deprecated group/name - [agent]/heartbeat_timeout
+#ramdisk_heartbeat_timeout = 300
+
+
+[audit]
+
+#
+# From ironic
+#
+
+# Enable auditing of API requests (for ironic-api service).
+# (boolean value)
+#enabled = false
+
+# Path to audit map file for ironic-api service. Used only
+# when API audit is enabled. (string value)
+#audit_map_file = /etc/ironic/api_audit_map.conf
+
+# Comma separated list of Ironic REST API HTTP methods to be
+# ignored during audit logging. For example: auditing will not
+# be done on any GET or POST requests if this is set to
+# "GET,POST". It is used only when API audit is enabled.
+# (string value)
+#ignore_req_list =
+
+
+[cimc]
+
+#
+# From ironic
+#
+
+# Number of times a power operation needs to be retried
+# (integer value)
+#max_retry = 6
+
+# Amount of time in seconds to wait in between power
+# operations (integer value)
+#action_interval = 10
+
+
+[cisco_ucs]
+
+#
+# From ironic
+#
+
+# Number of times a power operation needs to be retried
+# (integer value)
+#max_retry = 6
+
+# Amount of time in seconds to wait in between power
+# operations (integer value)
+#action_interval = 5
+
+
+[conductor]
+
+#
+# From ironic
+#
+
+# The size of the workers greenthread pool. Note that 2
+# threads will be reserved by the conductor itself for
+# handling heart beats and periodic tasks. (integer value)
+# Minimum value: 3
+#workers_pool_size = 100
+
+# Seconds between conductor heart beats. (integer value)
+#heartbeat_interval = 10
+
+# URL of Ironic API service. If not set ironic can get the
+# current value from the keystone service catalog. If set, the
+# value must start with either http:// or https://. (string
+# value)
+{%- if conductor.get('api', {}).get('url') %}
+api_url = {{ conductor.api.url }}
+{%- else %}
+#api_url = <None>
+{%- endif %}
+
+# Maximum time (in seconds) since the last check-in of a
+# conductor. A conductor is considered inactive when this time
+# has been exceeded. (integer value)
+#heartbeat_timeout = 60
+
+# Interval between syncing the node power state to the
+# database, in seconds. (integer value)
+#sync_power_state_interval = 60
+
+# Interval between checks of provision timeouts, in seconds.
+# (integer value)
+#check_provision_state_interval = 60
+
+# Timeout (seconds) to wait for a callback from a deploy
+# ramdisk. Set to 0 to disable timeout. (integer value)
+#deploy_callback_timeout = 1800
+
+# During sync_power_state, should the hardware power state be
+# set to the state recorded in the database (True) or should
+# the database be updated based on the hardware state (False).
+# (boolean value)
+#force_power_state_during_sync = true
+
+# During sync_power_state failures, limit the number of times
+# Ironic should try syncing the hardware node power state with
+# the node power state in DB (integer value)
+#power_state_sync_max_retries = 3
+
+# Maximum number of worker threads that can be started
+# simultaneously by a periodic task. Should be less than RPC
+# thread pool size. (integer value)
+#periodic_max_workers = 8
+
+# Number of attempts to grab a node lock. (integer value)
+#node_locked_retry_attempts = 3
+
+# Seconds to sleep between node lock attempts. (integer value)
+#node_locked_retry_interval = 1
+
+# Enable sending sensor data message via the notification bus
+# (boolean value)
+#send_sensor_data = false
+
+# Seconds between conductor sending sensor data message to
+# ceilometer via the notification bus. (integer value)
+#send_sensor_data_interval = 600
+
+# The maximum number of workers that can be started
+# simultaneously for send data from sensors periodic task.
+# (integer value)
+# Minimum value: 1
+#send_sensor_data_workers = 4
+
+# The time in seconds to wait for send sensors data periodic
+# task to be finished before allowing periodic call to happen
+# again. Should be less than send_sensor_data_interval value.
+# (integer value)
+#send_sensor_data_wait_timeout = 300
+
+# List of comma separated meter types which need to be sent to
+# Ceilometer. The default value, "ALL", is a special value
+# meaning send all the sensor data. (list value)
+#send_sensor_data_types = ALL
+
+# When conductors join or leave the cluster, existing
+# conductors may need to update any persistent local state as
+# nodes are moved around the cluster. This option controls how
+# often, in seconds, each conductor will check for nodes that
+# it should "take over". Set it to a negative value to disable
+# the check entirely. (integer value)
+#sync_local_state_interval = 180
+
+# Whether to upload the config drive to Swift. (boolean value)
+#configdrive_use_swift = false
+
+# Name of the Swift container to store config drive data. Used
+# when configdrive_use_swift is True. (string value)
+#configdrive_swift_container = ironic_configdrive_container
+
+# Timeout (seconds) for waiting for node inspection. 0 -
+# unlimited. (integer value)
+#inspect_timeout = 1800
+
+# Enables or disables automated cleaning. Automated cleaning
+# is a configurable set of steps, such as erasing disk drives,
+# that are performed on the node to ensure it is in a baseline
+# state and ready to be deployed to. This is done after
+# instance deletion as well as during the transition from a
+# "manageable" to "available" state. When enabled, the
+# particular steps performed to clean a node depend on which
+# driver that node is managed by; see the individual driver's
+# documentation for details. NOTE: The introduction of the
+# cleaning operation causes instance deletion to take
+# significantly longer. In an environment where all tenants
+# are trusted (eg, because there is only one tenant), this
+# option could be safely disabled. (boolean value)
+{%- if conductor.automated_clean is defined %}
+automated_clean = {{ conductor.automated_clean }}
+{%- else %}
+#automated_clean = true
+{%- endif %}
+
+# Timeout (seconds) to wait for a callback from the ramdisk
+# doing the cleaning. If the timeout is reached the node will
+# be put in the "clean failed" provision state. Set to 0 to
+# disable timeout. (integer value)
+#clean_callback_timeout = 1800
+
+# Timeout (in seconds) of soft reboot and soft power off
+# operation. This value always has to be positive. (integer
+# value)
+# Minimum value: 1
+#soft_power_off_timeout = 600
+
+
+[console]
+
+#
+# From ironic
+#
+
+# Path to serial console terminal program. Used only by Shell
+# In A Box console. (string value)
+#terminal = shellinaboxd
+
+# Directory containing the terminal SSL cert (PEM) for serial
+# console access. Used only by Shell In A Box console. (string
+# value)
+#terminal_cert_dir = <None>
+
+# Directory for holding terminal pid files. If not specified,
+# the temporary directory will be used. (string value)
+#terminal_pid_dir = <None>
+
+# Time interval (in seconds) for checking the status of
+# console subprocess. (integer value)
+#subprocess_checking_interval = 1
+
+# Time (in seconds) to wait for the console subprocess to
+# start. (integer value)
+#subprocess_timeout = 10
+
+
+[cors]
+
+#
+# From oslo.middleware.cors
+#
+
+# Indicate whether this resource may be shared with the domain
+# received in the requests "origin" header. Format:
+# "<protocol>://<host>[:<port>]", no trailing slash. Example:
+# https://horizon.example.com (list value)
+#allowed_origin = <None>
+
+# Indicate that the actual request can include user
+# credentials (boolean value)
+#allow_credentials = true
+
+# Indicate which headers are safe to expose to the API.
+# Defaults to HTTP Simple Headers. (list value)
+#expose_headers =
+
+# Maximum cache age of CORS preflight requests. (integer
+# value)
+#max_age = 3600
+
+# Indicate which methods can be used during the actual
+# request. (list value)
+#allow_methods = OPTIONS,GET,HEAD,POST,PUT,DELETE,TRACE,PATCH
+
+# Indicate which header field names may be used during the
+# actual request. (list value)
+#allow_headers =
+
+
+[database]
+
+#
+# From ironic
+#
+
+# MySQL engine to use. (string value)
+#mysql_engine = InnoDB
+
+#
+# From oslo.db
+#
+
+# DEPRECATED: The file name to use with SQLite. (string value)
+# Deprecated group/name - [DEFAULT]/sqlite_db
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Should use config option connection or
+# slave_connection to connect the database.
+#sqlite_db = oslo.sqlite
+
+# If True, SQLite uses synchronous mode. (boolean value)
+# Deprecated group/name - [DEFAULT]/sqlite_synchronous
+#sqlite_synchronous = true
+
+# The back end to use for the database. (string value)
+# Deprecated group/name - [DEFAULT]/db_backend
+#backend = sqlalchemy
+
+# The SQLAlchemy connection string to use to connect to the
+# database. (string value)
+# Deprecated group/name - [DEFAULT]/sql_connection
+# Deprecated group/name - [DATABASE]/sql_connection
+# Deprecated group/name - [sql]/connection
+connection = {{ ironic.database.engine }}+pymysql://{{ ironic.database.user }}:{{ ironic.database.password }}@{{ ironic.database.host }}/{{ ironic.database.name }}?charset=utf8
+
+# The SQLAlchemy connection string to use to connect to the
+# slave database. (string value)
+#slave_connection = <None>
+
+# The SQL mode to be used for MySQL sessions. This option,
+# including the default, overrides any server-set SQL mode. To
+# use whatever SQL mode is set by the server configuration,
+# set this to no value. Example: mysql_sql_mode= (string
+# value)
+#mysql_sql_mode = TRADITIONAL
+
+# Timeout before idle SQL connections are reaped. (integer
+# value)
+# Deprecated group/name - [DEFAULT]/sql_idle_timeout
+# Deprecated group/name - [DATABASE]/sql_idle_timeout
+# Deprecated group/name - [sql]/idle_timeout
+#idle_timeout = 3600
+
+# Minimum number of SQL connections to keep open in a pool.
+# (integer value)
+# Deprecated group/name - [DEFAULT]/sql_min_pool_size
+# Deprecated group/name - [DATABASE]/sql_min_pool_size
+#min_pool_size = 1
+
+# Maximum number of SQL connections to keep open in a pool.
+# Setting a value of 0 indicates no limit. (integer value)
+# Deprecated group/name - [DEFAULT]/sql_max_pool_size
+# Deprecated group/name - [DATABASE]/sql_max_pool_size
+#max_pool_size = 5
+
+# Maximum number of database connection retries during
+# startup. Set to -1 to specify an infinite retry count.
+# (integer value)
+# Deprecated group/name - [DEFAULT]/sql_max_retries
+# Deprecated group/name - [DATABASE]/sql_max_retries
+#max_retries = 10
+
+# Interval between retries of opening a SQL connection.
+# (integer value)
+# Deprecated group/name - [DEFAULT]/sql_retry_interval
+# Deprecated group/name - [DATABASE]/reconnect_interval
+#retry_interval = 10
+
+# If set, use this value for max_overflow with SQLAlchemy.
+# (integer value)
+# Deprecated group/name - [DEFAULT]/sql_max_overflow
+# Deprecated group/name - [DATABASE]/sqlalchemy_max_overflow
+#max_overflow = 50
+
+# Verbosity of SQL debugging information: 0=None,
+# 100=Everything. (integer value)
+# Minimum value: 0
+# Maximum value: 100
+# Deprecated group/name - [DEFAULT]/sql_connection_debug
+#connection_debug = 0
+
+# Add Python stack traces to SQL as comment strings. (boolean
+# value)
+# Deprecated group/name - [DEFAULT]/sql_connection_trace
+#connection_trace = false
+
+# If set, use this value for pool_timeout with SQLAlchemy.
+# (integer value)
+# Deprecated group/name - [DATABASE]/sqlalchemy_pool_timeout
+#pool_timeout = <None>
+
+# Enable the experimental use of database reconnect on
+# connection lost. (boolean value)
+#use_db_reconnect = false
+
+# Seconds between retries of a database transaction. (integer
+# value)
+#db_retry_interval = 1
+
+# If True, increases the interval between retries of a
+# database operation up to db_max_retry_interval. (boolean
+# value)
+#db_inc_retry_interval = true
+
+# If db_inc_retry_interval is set, the maximum seconds between
+# retries of a database operation. (integer value)
+#db_max_retry_interval = 10
+
+# Maximum retries in case of connection error or deadlock
+# error before error is raised. Set to -1 to specify an
+# infinite retry count. (integer value)
+#db_max_retries = 20
+
+
+[deploy]
+
+#
+# From ironic
+#
+
+# ironic-conductor node's HTTP server URL. Example:
+# http://192.1.2.3:8080 (string value)
+{%- if conductor.get('http_url') %}
+http_url = {{ conductor.http_url }}
+{%- else %}
+#http_url = <None>
+{%- endif %}
+
+# ironic-conductor node's HTTP root path. (string value)
+{%- if conductor.get('http_root') %}
+http_root = {{ conductor.http_root }}
+{%- else %}
+#http_root = /httpboot
+{%- endif %}
+
+# Priority to run in-band erase devices via the Ironic Python
+# Agent ramdisk. If unset, will use the priority set in the
+# ramdisk (defaults to 10 for the GenericHardwareManager). If
+# set to 0, will not run during cleaning. (integer value)
+#erase_devices_priority = <None>
+
+# Priority to run in-band clean step that erases metadata from
+# devices, via the Ironic Python Agent ramdisk. If unset, will
+# use the priority set in the ramdisk (defaults to 99 for the
+# GenericHardwareManager). If set to 0, will not run during
+# cleaning. (integer value)
+#erase_devices_metadata_priority = <None>
+
+# During shred, overwrite all block devices N times with
+# random data. This is only used if a device could not be ATA
+# Secure Erased. Defaults to 1. (integer value)
+# Minimum value: 0
+#shred_random_overwrite_iterations = 1
+
+# Whether to write zeros to a node's block devices after
+# writing random data. This will write zeros to the device
+# even when deploy.shred_random_overwrite_iterations is 0.
+# This option is only used if a device could not be ATA Secure
+# Erased. Defaults to True. (boolean value)
+#shred_final_overwrite_with_zeros = true
+
+# Defines what to do if an ATA secure erase operation fails
+# during cleaning in the Ironic Python Agent. If False, the
+# cleaning operation will fail and the node will be put in
+# ``clean failed`` state. If True, shred will be invoked and
+# cleaning will continue. (boolean value)
+#continue_if_disk_secure_erase_fails = false
+
+# Whether to power off a node after deploy failure. Defaults
+# to True. (boolean value)
+#power_off_after_deploy_failure = true
+
+# Default boot option to use when no boot option is requested
+# in node's driver_info. Currently the default is "netboot",
+# but it will be changed to "local" in the future. It is
+# recommended to set an explicit value for this option.
+# (string value)
+# Allowed values: netboot, local
+#default_boot_option = <None>
+
+
+[dhcp]
+
+#
+# From ironic
+#
+
+# DHCP provider to use. "neutron" uses Neutron, and "none"
+# uses a no-op provider. (string value)
+{%- if conductor.get('dhcp', {}).get('provider') %}
+dhcp_provider = {{ conductor.dhcp.provider }}
+{%- else %}
+#dhcp_provider = neutron
+{%- endif %}
+
+
+[disk_partitioner]
+
+#
+# From ironic_lib.disk_partitioner
+#
+
+# After Ironic has completed creating the partition table, it
+# continues to check for activity on the attached iSCSI device
+# status at this interval prior to copying the image to the
+# node, in seconds (integer value)
+#check_device_interval = 1
+
+# The maximum number of times to check that the device is not
+# accessed by another process. If the device is still busy
+# after that, the disk partitioning will be treated as having
+# failed. (integer value)
+#check_device_max_retries = 20
+
+
+[disk_utils]
+
+#
+# From ironic_lib.disk_utils
+#
+
+# Size of EFI system partition in MiB when configuring UEFI
+# systems for local boot. (integer value)
+#efi_system_partition_size = 200
+
+# Size of BIOS Boot partition in MiB when configuring GPT
+# partitioned systems for local boot in BIOS. (integer value)
+#bios_boot_partition_size = 1
+
+# Block size to use when writing to the nodes disk. (string
+# value)
+#dd_block_size = 1M
+
+# Maximum attempts to verify an iSCSI connection is active,
+# sleeping 1 second between attempts. (integer value)
+#iscsi_verify_attempts = 3
+
+
+[drac]
+
+#
+# From ironic
+#
+
+# Interval (in seconds) between periodic RAID job status
+# checks to determine whether the asynchronous RAID
+# configuration was successfully finished or not. (integer
+# value)
+#query_raid_config_job_status_interval = 120
+
+
+[glance]
+
+#
+# From ironic
+#
+
+# A list of URL schemes that can be downloaded directly via
+# the direct_url. Currently supported schemes: [file]. (list
+# value)
+#allowed_direct_url_schemes =
+
+# Authentication URL (string value)
+#auth_url = <None>
+
+# Authentication strategy to use when connecting to glance.
+# (string value)
+# Allowed values: keystone, noauth
+{%- if conductor.get('glance', {}).get('auth_strategy') %}
+auth_strategy = {{ conductor.glance.auth_strategy }}
+{%- else %}
+#auth_strategy = keystone
+{%- endif %}
+
+# Authentication type to load (string value)
+# Deprecated group/name - [glance]/auth_plugin
+{%- if conductor.get('glance', {}).get('auth_type') %}
+auth_type = {{ conductor.glance.auth_type }}
+{%- else %}
+#auth_type = <None>
+{%- endif %}
+
+# PEM encoded Certificate Authority to use when verifying
+# HTTPs connections. (string value)
+#cafile = <None>
+
+# PEM encoded client certificate cert file (string value)
+#certfile = <None>
+
+# Optional domain ID to use with v3 and v2 parameters. It will
+# be used for both the user and project domain in v3 and
+# ignored in v2 authentication. (string value)
+#default_domain_id = <None>
+
+# Optional domain name to use with v3 API and v2 parameters.
+# It will be used for both the user and project domain in v3
+# and ignored in v2 authentication. (string value)
+#default_domain_name = <None>
+
+# Domain ID to scope to (string value)
+#domain_id = <None>
+
+# Domain name to scope to (string value)
+#domain_name = <None>
+
+# Allow to perform insecure SSL (https) requests to glance.
+# (boolean value)
+#glance_api_insecure = false
+
+# A list of the glance api servers available to ironic. Prefix
+# with https:// for SSL-based glance API servers. Format is
+# [hostname|IP]:port. (list value)
+#glance_api_servers = <None>
+
+# DEPRECATED: Glance API version (1 or 2) to use. (integer
+# value)
+# Minimum value: 1
+# Maximum value: 2
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Ironic will only support using Glance API version 2
+# in the Queens release.
+#glance_api_version = 2
+
+# Optional path to a CA certificate bundle to be used to
+# validate the SSL certificate served by glance. It is used
+# when glance_api_insecure is set to False. (string value)
+#glance_cafile = <None>
+
+# Default glance hostname or IP address. (string value)
+{%- if conductor.get('glance', {}).get('host') %}
+glance_host = {{ conductor.glance.host }}
+{%- else %}
+#glance_host = $my_ip
+{%- endif %}
+
+# Number of retries when downloading an image from glance.
+# (integer value)
+#glance_num_retries = 0
+
+# Default glance port. (port value)
+# Minimum value: 0
+# Maximum value: 65535
+{%- if conductor.get('glance', {}).get('port') %}
+glance_port = {{ conductor.glance.port }}
+{%- else %}
+#glance_port = 9292
+{%- endif %}
+
+# Default protocol to use when connecting to glance. Set to
+# https for SSL. (string value)
+# Allowed values: http, https
+{%- if conductor.get('glance', {}).get('protocol') %}
+glance_protocol = {{ conductor.glance.protocol }}
+{%- else %}
+#glance_protocol = http
+{%- endif %}
+
+# Verify HTTPS connections. (boolean value)
+#insecure = false
+
+# PEM encoded client certificate key file (string value)
+#keyfile = <None>
+
+# User's password (string value)
+{%- if conductor.get('glance', {}).get('password') %}
+password = {{ conductor.glance.password }}
+{%- else %}
+#password = <None>
+{%- endif %}
+
+# Domain ID containing project (string value)
+{%- if conductor.get('glance', {}).get('project_domain_id') %}
+project_domain_id = {{ conductor.glance.project_domain_id }}
+{%- else %}
+#project_domain_id = <None>
+{%- endif %}
+
+# Domain name containing project (string value)
+{%- if conductor.get('glance', {}).get('project_domain_name') %}
+project_domain_name = {{ conductor.glance.project_domain_name }}
+{%- else %}
+#project_domain_name = <None>
+{%- endif %}
+
+# Project ID to scope to (string value)
+# Deprecated group/name - [glance]/tenant-id
+{%- if conductor.get('glance', {}).get('project_id') %}
+project_id = {{ conductor.glance.project_id }}
+{%- else %}
+#project_id = <None>
+{%- endif %}
+
+# Project name to scope to (string value)
+# Deprecated group/name - [glance]/tenant-name
+{%- if conductor.get('glance', {}).get('project_name') %}
+project_name = {{ conductor.glance.project_name }}
+{%- else %}
+#project_name = <None>
+{%- endif %}
+
+# The account that Glance uses to communicate with Swift. The
+# format is "AUTH_uuid". "uuid" is the UUID for the account
+# configured in the glance-api.conf. Required for temporary
+# URLs when Glance backend is Swift. For example:
+# "AUTH_a422b2-91f3-2f46-74b7-d7c9e8958f5d30". Swift temporary
+# URL format:
+# "endpoint_url/api_version/[account/]container/object_id"
+# (string value)
+#swift_account = <None>
+
+# The Swift API version to create a temporary URL for.
+# Defaults to "v1". Swift temporary URL format:
+# "endpoint_url/api_version/[account/]container/object_id"
+# (string value)
+#swift_api_version = v1
+
+# The Swift container Glance is configured to store its images
+# in. Defaults to "glance", which is the default in glance-
+# api.conf. Swift temporary URL format:
+# "endpoint_url/api_version/[account/]container/object_id"
+# (string value)
+#swift_container = glance
+
+# The "endpoint" (scheme, hostname, optional port) for the
+# Swift URL of the form
+# "endpoint_url/api_version/[account/]container/object_id". Do
+# not include trailing "/". For example, use
+# "https://swift.example.com". If using RADOS Gateway,
+# endpoint may also contain /swift path; if it does not, it
+# will be appended. Required for temporary URLs. (string
+# value)
+#swift_endpoint_url = <None>
+
+# This should match a config by the same name in the Glance
+# configuration file. When set to 0, a single-tenant store
+# will only use one container to store all images. When set to
+# an integer value between 1 and 32, a single-tenant store
+# will use multiple containers to store images, and this value
+# will determine how many containers are created. (integer
+# value)
+#swift_store_multiple_containers_seed = 0
+
+# Whether to cache generated Swift temporary URLs. Setting it
+# to true is only useful when an image caching proxy is used.
+# Defaults to False. (boolean value)
+#swift_temp_url_cache_enabled = false
+
+# The length of time in seconds that the temporary URL will be
+# valid for. Defaults to 20 minutes. If some deploys get a 401
+# response code when trying to download from the temporary
+# URL, try raising this duration. This value must be greater
+# than or equal to the value for
+# swift_temp_url_expected_download_start_delay (integer value)
+#swift_temp_url_duration = 1200
+
+# This is the delay (in seconds) from the time of the deploy
+# request (when the Swift temporary URL is generated) to when
+# the IPA ramdisk starts up and URL is used for the image
+# download. This value is used to check if the Swift temporary
+# URL duration is large enough to let the image download
+# begin. Also if temporary URL caching is enabled this will
+# determine if a cached entry will still be valid when the
+# download starts. swift_temp_url_duration value must be
+# greater than or equal to this option's value. Defaults to 0.
+# (integer value)
+# Minimum value: 0
+#swift_temp_url_expected_download_start_delay = 0
+
+# The secret token given to Swift to allow temporary URL
+# downloads. Required for temporary URLs. (string value)
+{%- if conductor.get('glance', {}).get('swift_temp_url_key') %}
+swift_temp_url_key = {{ conductor.glance.swift_temp_url_key }}
+{%- else %}
+#swift_temp_url_key = <None>
+{%- endif %}
+
+# Type of endpoint to use for temporary URLs. If the Glance
+# backend is Swift, use "swift"; if it is CEPH with RADOS
+# gateway, use "radosgw". (string value)
+# Allowed values: swift, radosgw
+#temp_url_endpoint_type = swift
+
+# Tenant ID (string value)
+#tenant_id = <None>
+
+# Tenant Name (string value)
+#tenant_name = <None>
+
+# Timeout value for http requests (integer value)
+#timeout = <None>
+
+# Trust ID (string value)
+#trust_id = <None>
+
+# User's domain id (string value)
+#user_domain_id = <None>
+
+# User's domain name (string value)
+#user_domain_name = <None>
+
+# User id (string value)
+#user_id = <None>
+
+# Username (string value)
+# Deprecated group/name - [glance]/user-name
+#username = <None>
+
+
+[ilo]
+
+#
+# From ironic
+#
+
+# Timeout (in seconds) for iLO operations (integer value)
+#client_timeout = 60
+
+# Port to be used for iLO operations (port value)
+# Minimum value: 0
+# Maximum value: 65535
+#client_port = 443
+
+# The Swift iLO container to store data. (string value)
+#swift_ilo_container = ironic_ilo_container
+
+# Amount of time in seconds for Swift objects to auto-expire.
+# (integer value)
+#swift_object_expiry_timeout = 900
+
+# Set this to True to use http web server to host floppy
+# images and generated boot ISO. This requires http_root and
+# http_url to be configured in the [deploy] section of the
+# config file. If this is set to False, then Ironic will use
+# Swift to host the floppy images and generated boot_iso.
+# (boolean value)
+#use_web_server_for_images = false
+
+# DEPRECATED: Priority for erase devices clean step. If unset,
+# it defaults to 10. If set to 0, the step will be disabled
+# and will not run during cleaning. (integer value)
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: This configuration option is duplicated by [deploy]
+# erase_devices_priority, please use that instead.
+#clean_priority_erase_devices = <None>
+
+# Priority for reset_ilo clean step. (integer value)
+#clean_priority_reset_ilo = 0
+
+# Priority for reset_bios_to_default clean step. (integer
+# value)
+#clean_priority_reset_bios_to_default = 10
+
+# Priority for reset_secure_boot_keys clean step. This step
+# will reset the secure boot keys to manufacturing defaults.
+# (integer value)
+#clean_priority_reset_secure_boot_keys_to_default = 20
+
+# Priority for clear_secure_boot_keys clean step. This step is
+# not enabled by default. It can be enabled to clear all
+# secure boot keys enrolled with iLO. (integer value)
+#clean_priority_clear_secure_boot_keys = 0
+
+# Priority for reset_ilo_credential clean step. This step
+# requires "ilo_change_password" parameter to be updated in
+# nodes's driver_info with the new password. (integer value)
+#clean_priority_reset_ilo_credential = 30
+
+# Number of times a power operation needs to be retried
+# (integer value)
+#power_retry = 6
+
+# Amount of time in seconds to wait in between power
+# operations (integer value)
+#power_wait = 2
+
+# CA certificate file to validate iLO. (string value)
+#ca_file = <None>
+
+# Default boot mode to be used in provisioning when
+# "boot_mode" capability is not provided in the
+# "properties/capabilities" of the node. The default is "auto"
+# for backward compatibility. When "auto" is specified,
+# default boot mode will be selected based on boot mode
+# settings on the system. (string value)
+# Allowed values: auto, bios, uefi
+#default_boot_mode = auto
+
+
+[inspector]
+
+#
+# From ironic
+#
+
+# Authentication URL (string value)
+#auth_url = <None>
+
+# Authentication type to load (string value)
+# Deprecated group/name - [inspector]/auth_plugin
+#auth_type = <None>
+
+# PEM encoded Certificate Authority to use when verifying
+# HTTPs connections. (string value)
+#cafile = <None>
+
+# PEM encoded client certificate cert file (string value)
+#certfile = <None>
+
+# Optional domain ID to use with v3 and v2 parameters. It will
+# be used for both the user and project domain in v3 and
+# ignored in v2 authentication. (string value)
+#default_domain_id = <None>
+
+# Optional domain name to use with v3 API and v2 parameters.
+# It will be used for both the user and project domain in v3
+# and ignored in v2 authentication. (string value)
+#default_domain_name = <None>
+
+# Domain ID to scope to (string value)
+#domain_id = <None>
+
+# Domain name to scope to (string value)
+#domain_name = <None>
+
+# whether to enable inspection using ironic-inspector. This
+# option does not affect new-style dynamic drivers and the
+# fake_inspector driver. (boolean value)
+#enabled = false
+
+# Verify HTTPS connections. (boolean value)
+#insecure = false
+
+# PEM encoded client certificate key file (string value)
+#keyfile = <None>
+
+# User's password (string value)
+#password = <None>
+
+# Domain ID containing project (string value)
+#project_domain_id = <None>
+
+# Domain name containing project (string value)
+#project_domain_name = <None>
+
+# Project ID to scope to (string value)
+# Deprecated group/name - [inspector]/tenant-id
+#project_id = <None>
+
+# Project name to scope to (string value)
+# Deprecated group/name - [inspector]/tenant-name
+#project_name = <None>
+
+# ironic-inspector HTTP endpoint. If this is not set, the
+# service catalog will be used. (string value)
+#service_url = <None>
+
+# period (in seconds) to check status of nodes on inspection
+# (integer value)
+#status_check_period = 60
+
+# Tenant ID (string value)
+#tenant_id = <None>
+
+# Tenant Name (string value)
+#tenant_name = <None>
+
+# Timeout value for http requests (integer value)
+#timeout = <None>
+
+# Trust ID (string value)
+#trust_id = <None>
+
+# User's domain id (string value)
+#user_domain_id = <None>
+
+# User's domain name (string value)
+#user_domain_name = <None>
+
+# User id (string value)
+#user_id = <None>
+
+# Username (string value)
+# Deprecated group/name - [inspector]/user-name
+#username = <None>
+
+
+[ipmi]
+
+#
+# From ironic
+#
+
+# Maximum time in seconds to retry IPMI operations. There is a
+# tradeoff when setting this value. Setting this too low may
+# cause older BMCs to crash and require a hard reset. However,
+# setting too high can cause the sync power state periodic
+# task to hang when there are slow or unresponsive BMCs.
+# (integer value)
+#retry_timeout = 60
+
+# Minimum time, in seconds, between IPMI operations sent to a
+# server. There is a risk with some hardware that setting this
+# too low may cause the BMC to crash. Recommended setting is 5
+# seconds. (integer value)
+#min_command_interval = 5
+
+
+[irmc]
+
+#
+# From ironic
+#
+
+# Ironic conductor node's "NFS" or "CIFS" root path (string
+# value)
+#remote_image_share_root = /remote_image_share_root
+
+# IP of remote image server (string value)
+#remote_image_server = <None>
+
+# Share type of virtual media (string value)
+# Allowed values: CIFS, NFS
+#remote_image_share_type = CIFS
+
+# share name of remote_image_server (string value)
+#remote_image_share_name = share
+
+# User name of remote_image_server (string value)
+#remote_image_user_name = <None>
+
+# Password of remote_image_user_name (string value)
+#remote_image_user_password = <None>
+
+# Domain name of remote_image_user_name (string value)
+#remote_image_user_domain =
+
+# Port to be used for iRMC operations (port value)
+# Minimum value: 0
+# Maximum value: 65535
+# Allowed values: 443, 80
+#port = 443
+
+# Authentication method to be used for iRMC operations (string
+# value)
+# Allowed values: basic, digest
+#auth_method = basic
+
+# Timeout (in seconds) for iRMC operations (integer value)
+#client_timeout = 60
+
+# Sensor data retrieval method. (string value)
+# Allowed values: ipmitool, scci
+#sensor_method = ipmitool
+
+# SNMP protocol version (string value)
+# Allowed values: v1, v2c, v3
+#snmp_version = v2c
+
+# SNMP port (port value)
+# Minimum value: 0
+# Maximum value: 65535
+#snmp_port = 161
+
+# SNMP community. Required for versions "v1" and "v2c" (string
+# value)
+#snmp_community = public
+
+# SNMP security name. Required for version "v3" (string value)
+#snmp_security = <None>
+
+# SNMP polling interval in seconds (integer value)
+#snmp_polling_interval = 10
+
+
+[ironic_lib]
+
+#
+# From ironic_lib.utils
+#
+
+# Command that is prefixed to commands that are run as root.
+# If not specified, no commands are run as root. (string
+# value)
+#root_helper = sudo ironic-rootwrap /etc/ironic/rootwrap.conf
+
+
+[iscsi]
+
+#
+# From ironic
+#
+
+# The port number on which the iSCSI portal listens for
+# incoming connections. (port value)
+# Minimum value: 0
+# Maximum value: 65535
+#portal_port = 3260
+
+
+[keystone]
+
+#
+# From ironic
+#
+
+# The region used for getting endpoints of OpenStack services.
+# (string value)
+{%- if ironic.get('identity', {}).get('region') %}
+region_name = {{ ironic.identity.region }}
+{%- else %}
+#region_name = <None>
+{%- endif %}
+
+
+[keystone_authtoken]
+
+#
+# From keystonemiddleware.auth_token
+#
+
+# Authentication URL (string value)
+{%- if ironic.get('identity', {}).get('engine') == 'keystone' %}
+auth_url = {{ ironic.identity.protocol }}://{{ ironic.identity.host }}:{{ ironic.identity.port }}/identity
+{%- else %}
+#auth_uri = <None>
+{%- endif %}
+
+# Authentication type to load (string value)
+# Deprecated group/name - [service_catalog]/auth_plugin
+{%- if ironic.get('identity', {}).get('auth_type') %}
+auth_type = {{ ironic.identity.auth_type }}
+{%- else %}
+#auth_type = <None>
+{%- endif %}
+
+# Optional domain ID to use with v3 and v2 parameters. It will
+# be used for both the user and project domain in v3 and
+# ignored in v2 authentication. (string value)
+{%- if ironic.get('identity', {}).get('default_domain_id') %}
+default_domain_id = {{ ironic.identity.default_domain_id }}
+{%- else %}
+#default_domain_id = <None>
+{%- endif %}
+
+# Optional domain name to use with v3 API and v2 parameters.
+# It will be used for both the user and project domain in v3
+# and ignored in v2 authentication. (string value)
+{%- if ironic.get('identity', {}).get('default_domain_name') %}
+default_domain_name = {{ ironic.identity.default_domain_name }}
+{%- else %}
+#default_domain_name = <None>
+{%- endif %}
+
+# Domain ID to scope to (string value)
+{%- if ironic.get('identity', {}).get('domain_id') %}
+domain_id = {{ ironic.identity.domain_id }}
+{%- else %}
+#domain_id = <None>
+{%- endif %}
+
+# Domain name to scope to (string value)
+{%- if ironic.get('identity', {}).get('domain_name') %}
+domain_name = {{ ironic.identity.domain_name }}
+{%- else %}
+#domain_name = <None>
+{%- endif %}
+
+# User's password (string value)
+{%- if ironic.get('identity', {}).get('password') %}
+password = {{ ironic.identity.password }}
+{%- else %}
+#password = <None>
+{%- endif %}
+
+# Domain ID containing project (string value)
+{%- if ironic.get('identity', {}).get('project_domain_id') %}
+project_domain_id = {{ ironic.identity.project_domain_id }}
+{%- else %}
+#project_domain_id = <None>
+{%- endif %}
+
+# Domain name containing project (string value)
+{%- if ironic.get('identity', {}).get('project_domain_name') %}
+project_domain_name = {{ ironic.identity.project_domain_name }}
+{%- else %}
+#project_domain_name = <None>
+{%- endif %}
+
+# Project ID to scope to (string value)
+# Deprecated group/name - [service_catalog]/tenant-id
+{%- if ironic.get('identity', {}).get('project_id') %}
+project_id = {{ ironic.identity.project_id }}
+{%- else %}
+#project_id = <None>
+{%- endif %}
+
+# Project name to scope to (string value)
+# Deprecated group/name - [service_catalog]/tenant-name
+{%- if ironic.get('identity', {}).get('project_name') %}
+project_name = {{ ironic.identity.project_name }}
+{%- else %}
+#project_name = <None>
+{%- endif %}
+
+# Tenant ID (string value)
+{%- if ironic.get('identity', {}).get('tenant_id') %}
+tenant_id = {{ ironic.identity.tenant_id }}
+{%- else %}
+#tenant_id = <None>
+{%- endif %}
+
+# Tenant Name (string value)
+{%- if ironic.get('identity', {}).get('tenant_name') %}
+tenant_name = {{ ironic.identity.tenant_name }}
+{%- else %}
+#tenant_name = <None>
+{%- endif %}
+
+# User's domain id (string value)
+{%- if ironic.get('identity', {}).get('user_domain_id') %}
+user_domain_id = {{ ironic.identity.user_domain_id }}
+{%- else %}
+#user_domain_id = <None>
+{%- endif %}
+
+# User's domain name (string value)
+{%- if ironic.get('identity', {}).get('user_domain_name') %}
+user_domain_name = {{ ironic.identity.user_domain_name }}
+{%- else %}
+#user_domain_name = <None>
+{%- endif %}
+
+# User id (string value)
+{%- if ironic.get('identity', {}).get('user_id')  %}
+user_id = {{ ironic.identity.user_id }}
+{%- else %}
+#user_id = <None>
+{%- endif %}
+
+# Username (string value)
+# Deprecated group/name - [service_catalog]/user-name
+{%- if ironic.get('identity', {}).get('user') %}
+username = {{ ironic.identity.user}}
+{%- else %}
+#username = <None>
+{%- endif %}
+
+# API version of the admin Identity API endpoint. (string
+# value)
+{%- if ironic.get('identity', {}).get('version') %}
+auth_version = {{ ironic.identity.version }}
+{%- else %}
+#auth_version = <None>
+{%- endif %}
+
+# Do not handle authorization requests within the middleware,
+# but delegate the authorization decision to downstream WSGI
+# components. (boolean value)
+#delay_auth_decision = false
+
+# Request timeout value for communicating with Identity API
+# server. (integer value)
+#http_connect_timeout = <None>
+
+# How many times are we trying to reconnect when communicating
+# with Identity API Server. (integer value)
+#http_request_max_retries = 3
+
+# Request environment key where the Swift cache object is
+# stored. When auth_token middleware is deployed with a Swift
+# cache, use this option to have the middleware share a
+# caching backend with swift. Otherwise, use the
+# ``memcached_servers`` option instead. (string value)
+#cache = <None>
+
+# Required if identity server requires client certificate
+# (string value)
+#certfile = <None>
+
+# Required if identity server requires client certificate
+# (string value)
+#keyfile = <None>
+
+# A PEM encoded Certificate Authority to use when verifying
+# HTTPs connections. Defaults to system CAs. (string value)
+#cafile = <None>
+
+# Verify HTTPS connections. (boolean value)
+#insecure = false
+
+# The region in which the identity server can be found.
+# (string value)
+#region_name = <None>
+
+# DEPRECATED: Directory used to cache files related to PKI
+# tokens. This option has been deprecated in the Ocata release
+# and will be removed in the P release. (string value)
+# This option is deprecated for removal since Ocata.
+# Its value may be silently ignored in the future.
+# Reason: PKI token format is no longer supported.
+#signing_dir = <None>
+
+# Optionally specify a list of memcached server(s) to use for
+# caching. If left undefined, tokens will instead be cached
+# in-process. (list value)
+# Deprecated group/name - [keystone_authtoken]/memcache_servers
+{%- if ironic.get('identity', {}).get('memcached_servers') %}
+memcached_servers = {{ ironic.identity.memcached_servers }}
+{%- else %}
+#memcached_servers = <None>
+{%- endif %}
+
+# In order to prevent excessive effort spent validating
+# tokens, the middleware caches previously-seen tokens for a
+# configurable duration (in seconds). Set to -1 to disable
+# caching completely. (integer value)
+#token_cache_time = 300
+
+# DEPRECATED: Determines the frequency at which the list of
+# revoked tokens is retrieved from the Identity service (in
+# seconds). A high number of revocation events combined with a
+# low cache duration may significantly reduce performance.
+# Only valid for PKI tokens. This option has been deprecated
+# in the Ocata release and will be removed in the P release.
+# (integer value)
+# This option is deprecated for removal since Ocata.
+# Its value may be silently ignored in the future.
+# Reason: PKI token format is no longer supported.
+#revocation_cache_time = 10
+
+# (Optional) If defined, indicate whether token data should be
+# authenticated or authenticated and encrypted. If MAC, token
+# data is authenticated (with HMAC) in the cache. If ENCRYPT,
+# token data is encrypted and authenticated in the cache. If
+# the value is not one of these options or empty, auth_token
+# will raise an exception on initialization. (string value)
+# Allowed values: None, MAC, ENCRYPT
+#memcache_security_strategy = None
+
+# (Optional, mandatory if memcache_security_strategy is
+# defined) This string is used for key derivation. (string
+# value)
+#memcache_secret_key = <None>
+
+# (Optional) Number of seconds memcached server is considered
+# dead before it is tried again. (integer value)
+#memcache_pool_dead_retry = 300
+
+# (Optional) Maximum total number of open connections to every
+# memcached server. (integer value)
+#memcache_pool_maxsize = 10
+
+# (Optional) Socket timeout in seconds for communicating with
+# a memcached server. (integer value)
+#memcache_pool_socket_timeout = 3
+
+# (Optional) Number of seconds a connection to memcached is
+# held unused in the pool before it is closed. (integer value)
+#memcache_pool_unused_timeout = 60
+
+# (Optional) Number of seconds that an operation will wait to
+# get a memcached client connection from the pool. (integer
+# value)
+#memcache_pool_conn_get_timeout = 10
+
+# (Optional) Use the advanced (eventlet safe) memcached client
+# pool. The advanced pool will only work under python 2.x.
+# (boolean value)
+#memcache_use_advanced_pool = false
+
+# (Optional) Indicate whether to set the X-Service-Catalog
+# header. If False, middleware will not ask for service
+# catalog on token validation and will not set the X-Service-
+# Catalog header. (boolean value)
+#include_service_catalog = true
+
+# Used to control the use and type of token binding. Can be
+# set to: "disabled" to not check token binding. "permissive"
+# (default) to validate binding information if the bind type
+# is of a form known to the server and ignore it if not.
+# "strict" like "permissive" but if the bind type is unknown
+# the token will be rejected. "required" any form of token
+# binding is needed to be allowed. Finally the name of a
+# binding method that must be present in tokens. (string
+# value)
+#enforce_token_bind = permissive
+
+# DEPRECATED: If true, the revocation list will be checked for
+# cached tokens. This requires that PKI tokens are configured
+# on the identity server. (boolean value)
+# This option is deprecated for removal since Ocata.
+# Its value may be silently ignored in the future.
+# Reason: PKI token format is no longer supported.
+#check_revocations_for_cached = false
+
+# DEPRECATED: Hash algorithms to use for hashing PKI tokens.
+# This may be a single algorithm or multiple. The algorithms
+# are those supported by Python standard hashlib.new(). The
+# hashes will be tried in the order given, so put the
+# preferred one first for performance. The result of the first
+# hash will be stored in the cache. This will typically be set
+# to multiple values only while migrating from a less secure
+# algorithm to a more secure one. Once all the old tokens are
+# expired this option should be set to a single value for
+# better performance. (list value)
+# This option is deprecated for removal since Ocata.
+# Its value may be silently ignored in the future.
+# Reason: PKI token format is no longer supported.
+#hash_algorithms = md5
+
+# A choice of roles that must be present in a service token.
+# Service tokens are allowed to request that an expired token
+# can be used and so this check should tightly control that
+# only actual services should be sending this token. Roles
+# here are applied as an ANY check so any role in this list
+# must be present. For backwards compatibility reasons this
+# currently only affects the allow_expired check. (list value)
+#service_token_roles = service
+
+# For backwards compatibility reasons we must let valid
+# service tokens pass that don't pass the service_token_roles
+# check as valid. Setting this true will become the default in
+# a future release and should be enabled if possible. (boolean
+# value)
+#service_token_roles_required = false
+
+# Authentication type to load (string value)
+# Deprecated group/name - [keystone_authtoken]/auth_plugin
+{%- if ironic.get('identity', {}).get('auth_type') %}
+auth_type = {{ ironic.identity.auth_type }}
+{%- else %}
+#auth_type = <None>
+{%- endif %}
+
+# Config Section from which to load plugin specific options
+# (string value)
+#auth_section = <None>
+
+
+[matchmaker_redis]
+
+#
+# From oslo.messaging
+#
+
+# DEPRECATED: Host to locate redis. (string value)
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Replaced by [DEFAULT]/transport_url
+#host = 127.0.0.1
+
+# DEPRECATED: Use this port to connect to redis host. (port
+# value)
+# Minimum value: 0
+# Maximum value: 65535
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Replaced by [DEFAULT]/transport_url
+#port = 6379
+
+# DEPRECATED: Password for Redis server (optional). (string
+# value)
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Replaced by [DEFAULT]/transport_url
+#password =
+
+# DEPRECATED: List of Redis Sentinel hosts (fault tolerance
+# mode), e.g., [host:port, host1:port ... ] (list value)
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Replaced by [DEFAULT]/transport_url
+#sentinel_hosts =
+
+# Redis replica set name. (string value)
+#sentinel_group_name = oslo-messaging-zeromq
+
+# Time in ms to wait between connection attempts. (integer
+# value)
+#wait_timeout = 2000
+
+# Time in ms to wait before the transaction is killed.
+# (integer value)
+#check_timeout = 20000
+
+# Timeout in ms on blocking socket operations. (integer value)
+#socket_timeout = 10000
+
+
+[metrics]
+
+#
+# From ironic
+#
+
+# Backend for the agent ramdisk to use for metrics. Default
+# possible backends are "noop" and "statsd". (string value)
+#agent_backend = noop
+
+# Prepend the hostname to all metric names sent by the agent
+# ramdisk. The format of metric names is
+# [global_prefix.][uuid.][host_name.]prefix.metric_name.
+# (boolean value)
+#agent_prepend_host = false
+
+# Prepend the node's Ironic uuid to all metric names sent by
+# the agent ramdisk. The format of metric names is
+# [global_prefix.][uuid.][host_name.]prefix.metric_name.
+# (boolean value)
+#agent_prepend_uuid = false
+
+# Split the prepended host value by "." and reverse it for
+# metrics sent by the agent ramdisk (to better match the
+# reverse hierarchical form of domain names). (boolean value)
+#agent_prepend_host_reverse = true
+
+# Prefix all metric names sent by the agent ramdisk with this
+# value. The format of metric names is
+# [global_prefix.][uuid.][host_name.]prefix.metric_name.
+# (string value)
+#agent_global_prefix = <None>
+
+#
+# From ironic_lib.metrics
+#
+
+# Backend to use for the metrics system. (string value)
+# Allowed values: noop, statsd
+#backend = noop
+
+# Prepend the hostname to all metric names. The format of
+# metric names is
+# [global_prefix.][host_name.]prefix.metric_name. (boolean
+# value)
+#prepend_host = false
+
+# Split the prepended host value by "." and reverse it (to
+# better match the reverse hierarchical form of domain names).
+# (boolean value)
+#prepend_host_reverse = true
+
+# Prefix all metric names with this value. By default, there
+# is no global prefix. The format of metric names is
+# [global_prefix.][host_name.]prefix.metric_name. (string
+# value)
+#global_prefix = <None>
+
+
+[metrics_statsd]
+
+#
+# From ironic
+#
+
+# Host for the agent ramdisk to use with the statsd backend.
+# This must be accessible from networks the agent is booted
+# on. (string value)
+#agent_statsd_host = localhost
+
+# Port for the agent ramdisk to use with the statsd backend.
+# (port value)
+# Minimum value: 0
+# Maximum value: 65535
+#agent_statsd_port = 8125
+
+#
+# From ironic_lib.metrics_statsd
+#
+
+# Host for use with the statsd backend. (string value)
+#statsd_host = localhost
+
+# Port to use with the statsd backend. (port value)
+# Minimum value: 0
+# Maximum value: 65535
+#statsd_port = 8125
+
+
+[neutron]
+
+#
+# From ironic
+#
+
+# Authentication URL (string value)
+{%- if conductor.get('neutron', {}).get('auth_strategy') == 'keystone' %}
+auth_url = {{ conductor.identity.protocol }}://{{ conductor.identity.host }}:{{ conductor.identity.port }}/identity
+{%- else %}
+#auth_url = <None>
+{%- endif %}
+
+# Authentication strategy to use when connecting to neutron.
+# Running neutron in noauth mode (related to but not affected
+# by this setting) is insecure and should only be used for
+# testing. (string value)
+# Allowed values: keystone, noauth
+{%- if conductor.get('neutron', {}).get('auth_strategy') %}
+auth_strategy = {{ conductor.neutron.auth_strategy }}
+{%- else %}
+#auth_strategy = keystone
+{%- endif %}
+
+# Authentication type to load (string value)
+# Deprecated group/name - [neutron]/auth_plugin
+{%- if conductor.get('neutron', {}).get('auth_type') %}
+auth_type = {{ conductor.neutron.auth_type }}
+{%- else %}
+#auth_type = <None>
+{%- endif %}
+
+# PEM encoded Certificate Authority to use when verifying
+# HTTPs connections. (string value)
+#cafile = <None>
+
+# PEM encoded client certificate cert file (string value)
+#certfile = <None>
+
+# Neutron network UUID for the ramdisk to be booted into for
+# cleaning nodes. Required for "neutron" network interface. It
+# is also required if cleaning nodes when using "flat" network
+# interface or "neutron" DHCP provider. (string value)
+#cleaning_network_uuid = <None>
+
+# Optional domain ID to use with v3 and v2 parameters. It will
+# be used for both the user and project domain in v3 and
+# ignored in v2 authentication. (string value)
+#default_domain_id = <None>
+
+# Optional domain name to use with v3 API and v2 parameters.
+# It will be used for both the user and project domain in v3
+# and ignored in v2 authentication. (string value)
+#default_domain_name = <None>
+
+# Domain ID to scope to (string value)
+#domain_id = <None>
+
+# Domain name to scope to (string value)
+#domain_name = <None>
+
+# Verify HTTPS connections. (boolean value)
+#insecure = false
+
+# PEM encoded client certificate key file (string value)
+#keyfile = <None>
+
+# User's password (string value)
+{%- if conductor.get('neutron', {}).get('password') %}
+password = {{ conductor.neutron.password }}
+{%- else %}
+#password = <None>
+{%- endif %}
+
+# Delay value to wait for Neutron agents to setup sufficient
+# DHCP configuration for port. (integer value)
+# Minimum value: 0
+{%- if conductor.get('neutron', {}).get('port_setup_delay') %}
+port_setup_delay = {{ conductor.neutron.port_setup_delay }}
+{%- else %}
+#port_setup_delay = 0
+{%- endif %}
+
+# Domain ID containing project (string value)
+{%- if conductor.get('neutron', {}).get('project_domain_id') %}
+project_domain_id = {{ conductor.neutron.project_domain_id }}
+{%- else %}
+#project_domain_id = <None>
+{%- endif %}
+
+# Domain name containing project (string value)
+{%- if conductor.get('neutron', {}).get('project_domain_name') %}
+project_domain_name = {{ conductor.neutron.project_domain_name }}
+{%- else %}
+#project_domain_name = <None>
+{%- endif %}
+
+# Project ID to scope to (string value)
+# Deprecated group/name - [neutron]/tenant-id
+{%- if conductor.get('neutron', {}).get('project_id') %}
+project_id = {{ conductor.neutron.project_id }}
+{%- else %}
+#project_id = <None>
+{%- endif %}
+
+# Project name to scope to (string value)
+# Deprecated group/name - [neutron]/tenant-name
+{%- if conductor.get('neutron', {}).get('project_name') %}
+project_name = {{ conductor.neutron.project_name }}
+{%- else %}
+#project_name = <None>
+{%- endif %}
+
+# Neutron network UUID for the ramdisk to be booted into for
+# provisioning nodes. Required for "neutron" network
+# interface. (string value)
+#provisioning_network_uuid = <None>
+
+# Client retries in the case of a failed request. (integer
+# value)
+#retries = 3
+
+# Tenant ID (string value)
+{%- if conductor.get('neutron', {}).get('tenant_id') %}
+tenant_id = {{ conductor.neutron.tenant_id }}
+{%- else %}
+#tenant_id = <None>
+{%- endif %}
+
+# Tenant Name (string value)
+#tenant_name = <None>
+
+# Timeout value for http requests (integer value)
+#timeout = <None>
+
+# Trust ID (string value)
+#trust_id = <None>
+
+# URL for connecting to neutron. Default value translates to
+# 'http://$my_ip:9696' when auth_strategy is 'noauth', and to
+# discovery from Keystone catalog when auth_strategy is
+# 'keystone'. (string value)
+#url = <None>
+
+# Timeout value for connecting to neutron in seconds. (integer
+# value)
+#url_timeout = 30
+
+# User's domain id (string value)
+{%- if conductor.get('neutron', {}).get('user_domain_id') %}
+user_domain_id = {{ conductor.neutron.user_domain_id }}
+{%- else %}
+#user_domain_id = <None>
+{%- endif %}
+
+# User's domain name (string value)
+{%- if conductor.get('neutron', {}).get('user_domain_name') %}
+user_domain_name = {{ conductor.neutron.user_domain_name }}
+{%- else %}
+#user_domain_name = <None>
+{%- endif %}
+
+# User id (string value)
+{%- if conductor.get('neutron', {}).get('user_id') %}
+user_id = {{ conductor.neutron.user_id }}
+{%- else %}
+#user_id = <None>
+{%- endif %}
+
+# Username (string value)
+# Deprecated group/name - [neutron]/user-name
+{%- if conductor.get('neutron', {}).get('username') %}
+username = {{ conductor.neutron.username }}
+{%- else %}
+#username = <None>
+{%- endif %}
+
+
+[oneview]
+
+#
+# From ironic
+#
+
+# URL where OneView is available. (string value)
+#manager_url = <None>
+
+# OneView username to be used. (string value)
+#username = <None>
+
+# OneView password to be used. (string value)
+#password = <None>
+
+# Option to allow insecure connection with OneView. (boolean
+# value)
+#allow_insecure_connections = false
+
+# Path to CA certificate. (string value)
+#tls_cacert_file = <None>
+
+# Max connection retries to check changes on OneView. (integer
+# value)
+#max_polling_attempts = 12
+
+# Whether to enable the periodic tasks for OneView driver be
+# aware when OneView hardware resources are taken and released
+# by Ironic or OneView users and proactively manage nodes in
+# clean fail state according to Dynamic Allocation model of
+# hardware resources allocation in OneView. (boolean value)
+#enable_periodic_tasks = true
+
+# Period (in seconds) for periodic tasks to be executed when
+# enable_periodic_tasks=True. (integer value)
+#periodic_check_interval = 300
+
+
+[oslo_concurrency]
+
+#
+# From oslo.concurrency
+#
+
+# Enables or disables inter-process locks. (boolean value)
+# Deprecated group/name - [DEFAULT]/disable_process_locking
+#disable_process_locking = false
+
+# Directory to use for lock files. For security, the
+# specified directory should only be writable by the user
+# running the processes that need locking. Defaults to
+# environment variable OSLO_LOCK_PATH. If external locks are
+# used, a lock path must be set. (string value)
+# Deprecated group/name - [DEFAULT]/lock_path
+#lock_path = <None>
+
+
+[oslo_messaging_amqp]
+
+#
+# From oslo.messaging
+#
+
+# Name for the AMQP container. must be globally unique.
+# Defaults to a generated UUID (string value)
+# Deprecated group/name - [amqp1]/container_name
+#container_name = <None>
+
+# Timeout for inactive connections (in seconds) (integer
+# value)
+# Deprecated group/name - [amqp1]/idle_timeout
+#idle_timeout = 0
+
+# Debug: dump AMQP frames to stdout (boolean value)
+# Deprecated group/name - [amqp1]/trace
+#trace = false
+
+# CA certificate PEM file used to verify the server's
+# certificate (string value)
+# Deprecated group/name - [amqp1]/ssl_ca_file
+#ssl_ca_file =
+
+# Self-identifying certificate PEM file for client
+# authentication (string value)
+# Deprecated group/name - [amqp1]/ssl_cert_file
+#ssl_cert_file =
+
+# Private key PEM file used to sign ssl_cert_file certificate
+# (optional) (string value)
+# Deprecated group/name - [amqp1]/ssl_key_file
+#ssl_key_file =
+
+# Password for decrypting ssl_key_file (if encrypted) (string
+# value)
+# Deprecated group/name - [amqp1]/ssl_key_password
+#ssl_key_password = <None>
+
+# DEPRECATED: Accept clients using either SSL or plain TCP
+# (boolean value)
+# Deprecated group/name - [amqp1]/allow_insecure_clients
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Not applicable - not a SSL server
+#allow_insecure_clients = false
+
+# Space separated list of acceptable SASL mechanisms (string
+# value)
+# Deprecated group/name - [amqp1]/sasl_mechanisms
+#sasl_mechanisms =
+
+# Path to directory that contains the SASL configuration
+# (string value)
+# Deprecated group/name - [amqp1]/sasl_config_dir
+#sasl_config_dir =
+
+# Name of configuration file (without .conf suffix) (string
+# value)
+# Deprecated group/name - [amqp1]/sasl_config_name
+#sasl_config_name =
+
+# User name for message broker authentication (string value)
+# Deprecated group/name - [amqp1]/username
+#username =
+
+# Password for message broker authentication (string value)
+# Deprecated group/name - [amqp1]/password
+#password =
+
+# Seconds to pause before attempting to re-connect. (integer
+# value)
+# Minimum value: 1
+#connection_retry_interval = 1
+
+# Increase the connection_retry_interval by this many seconds
+# after each unsuccessful failover attempt. (integer value)
+# Minimum value: 0
+#connection_retry_backoff = 2
+
+# Maximum limit for connection_retry_interval +
+# connection_retry_backoff (integer value)
+# Minimum value: 1
+#connection_retry_interval_max = 30
+
+# Time to pause between re-connecting an AMQP 1.0 link that
+# failed due to a recoverable error. (integer value)
+# Minimum value: 1
+#link_retry_delay = 10
+
+# The maximum number of attempts to re-send a reply message
+# which failed due to a recoverable error. (integer value)
+# Minimum value: -1
+#default_reply_retry = 0
+
+# The deadline for an rpc reply message delivery. (integer
+# value)
+# Minimum value: 5
+#default_reply_timeout = 30
+
+# The deadline for an rpc cast or call message delivery. Only
+# used when caller does not provide a timeout expiry. (integer
+# value)
+# Minimum value: 5
+#default_send_timeout = 30
+
+# The deadline for a sent notification message delivery. Only
+# used when caller does not provide a timeout expiry. (integer
+# value)
+# Minimum value: 5
+#default_notify_timeout = 30
+
+# The duration to schedule a purge of idle sender links.
+# Detach link after expiry. (integer value)
+# Minimum value: 1
+#default_sender_link_timeout = 600
+
+# Indicates the addressing mode used by the driver.
+# Permitted values:
+# 'legacy' - use legacy non-routable addressing
+# 'routable' - use routable addresses
+# 'dynamic' - use legacy addresses if the message bus does
+# not support routing otherwise use routable addressing
+# (string value)
+#addressing_mode = dynamic
+
+# address prefix used when sending to a specific server
+# (string value)
+# Deprecated group/name - [amqp1]/server_request_prefix
+#server_request_prefix = exclusive
+
+# address prefix used when broadcasting to all servers (string
+# value)
+# Deprecated group/name - [amqp1]/broadcast_prefix
+#broadcast_prefix = broadcast
+
+# address prefix when sending to any server in group (string
+# value)
+# Deprecated group/name - [amqp1]/group_request_prefix
+#group_request_prefix = unicast
+
+# Address prefix for all generated RPC addresses (string
+# value)
+#rpc_address_prefix = openstack.org/om/rpc
+
+# Address prefix for all generated Notification addresses
+# (string value)
+#notify_address_prefix = openstack.org/om/notify
+
+# Appended to the address prefix when sending a fanout
+# message. Used by the message bus to identify fanout
+# messages. (string value)
+#multicast_address = multicast
+
+# Appended to the address prefix when sending to a particular
+# RPC/Notification server. Used by the message bus to identify
+# messages sent to a single destination. (string value)
+#unicast_address = unicast
+
+# Appended to the address prefix when sending to a group of
+# consumers. Used by the message bus to identify messages that
+# should be delivered in a round-robin fashion across
+# consumers. (string value)
+#anycast_address = anycast
+
+# Exchange name used in notification addresses.
+# Exchange name resolution precedence:
+# Target.exchange if set
+# else default_notification_exchange if set
+# else control_exchange if set
+# else 'notify' (string value)
+#default_notification_exchange = <None>
+
+# Exchange name used in RPC addresses.
+# Exchange name resolution precedence:
+# Target.exchange if set
+# else default_rpc_exchange if set
+# else control_exchange if set
+# else 'rpc' (string value)
+#default_rpc_exchange = <None>
+
+# Window size for incoming RPC Reply messages. (integer value)
+# Minimum value: 1
+#reply_link_credit = 200
+
+# Window size for incoming RPC Request messages (integer
+# value)
+# Minimum value: 1
+#rpc_server_credit = 100
+
+# Window size for incoming Notification messages (integer
+# value)
+# Minimum value: 1
+#notify_server_credit = 100
+
+# Send messages of this type pre-settled.
+# Pre-settled messages will not receive acknowledgement
+# from the peer. Note well: pre-settled messages may be
+# silently discarded if the delivery fails.
+# Permitted values:
+# 'rpc-call' - send RPC Calls pre-settled
+# 'rpc-reply'- send RPC Replies pre-settled
+# 'rpc-cast' - Send RPC Casts pre-settled
+# 'notify' - Send Notifications pre-settled
+# (multi valued)
+#pre_settled = rpc-cast
+
+
+[oslo_messaging_kafka]
+
+#
+# From oslo.messaging
+#
+
+# DEPRECATED: Default Kafka broker Host (string value)
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Replaced by [DEFAULT]/transport_url
+#kafka_default_host = localhost
+
+# DEPRECATED: Default Kafka broker Port (port value)
+# Minimum value: 0
+# Maximum value: 65535
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Replaced by [DEFAULT]/transport_url
+#kafka_default_port = 9092
+
+# Max fetch bytes of Kafka consumer (integer value)
+#kafka_max_fetch_bytes = 1048576
+
+# Default timeout(s) for Kafka consumers (floating point
+# value)
+#kafka_consumer_timeout = 1.0
+
+# Pool Size for Kafka Consumers (integer value)
+#pool_size = 10
+
+# The pool size limit for connections expiration policy
+# (integer value)
+#conn_pool_min_size = 2
+
+# The time-to-live in sec of idle connections in the pool
+# (integer value)
+#conn_pool_ttl = 1200
+
+# Group id for Kafka consumer. Consumers in one group will
+# coordinate message consumption (string value)
+#consumer_group = oslo_messaging_consumer
+
+# Upper bound on the delay for KafkaProducer batching in
+# seconds (floating point value)
+#producer_batch_timeout = 0.0
+
+# Size of batch for the producer async send (integer value)
+#producer_batch_size = 16384
+
+
+[oslo_messaging_notifications]
+
+#
+# From oslo.messaging
+#
+
+# The Drivers(s) to handle sending notifications. Possible
+# values are messaging, messagingv2, routing, log, test, noop
+# (multi valued)
+# Deprecated group/name - [DEFAULT]/notification_driver
+#driver =
+
+# A URL representing the messaging driver to use for
+# notifications. If not set, we fall back to the same
+# configuration used for RPC. (string value)
+# Deprecated group/name - [DEFAULT]/notification_transport_url
+#transport_url = <None>
+
+# AMQP topic used for OpenStack notifications. (list value)
+# Deprecated group/name - [rpc_notifier2]/topics
+# Deprecated group/name - [DEFAULT]/notification_topics
+#topics = notifications
+
+
+[oslo_messaging_rabbit]
+
+#
+# From oslo.messaging
+#
+
+# Use durable queues in AMQP. (boolean value)
+# Deprecated group/name - [DEFAULT]/amqp_durable_queues
+# Deprecated group/name - [DEFAULT]/rabbit_durable_queues
+#amqp_durable_queues = false
+
+# Auto-delete queues in AMQP. (boolean value)
+# Deprecated group/name - [DEFAULT]/amqp_auto_delete
+#amqp_auto_delete = false
+
+# Enable SSL (boolean value)
+#ssl = <None>
+
+# SSL version to use (valid only if SSL enabled). Valid values
+# are TLSv1 and SSLv23. SSLv2, SSLv3, TLSv1_1, and TLSv1_2 may
+# be available on some distributions. (string value)
+# Deprecated group/name - [oslo_messaging_rabbit]/kombu_ssl_version
+#ssl_version =
+
+# SSL key file (valid only if SSL enabled). (string value)
+# Deprecated group/name - [oslo_messaging_rabbit]/kombu_ssl_keyfile
+#ssl_key_file =
+
+# SSL cert file (valid only if SSL enabled). (string value)
+# Deprecated group/name - [oslo_messaging_rabbit]/kombu_ssl_certfile
+#ssl_cert_file =
+
+# SSL certification authority file (valid only if SSL
+# enabled). (string value)
+# Deprecated group/name - [oslo_messaging_rabbit]/kombu_ssl_ca_certs
+#ssl_ca_file =
+
+# How long to wait before reconnecting in response to an AMQP
+# consumer cancel notification. (floating point value)
+# Deprecated group/name - [DEFAULT]/kombu_reconnect_delay
+#kombu_reconnect_delay = 1.0
+
+# EXPERIMENTAL: Possible values are: gzip, bz2. If not set
+# compression will not be used. This option may not be
+# available in future versions. (string value)
+#kombu_compression = <None>
+
+# How long to wait a missing client before abandoning to send
+# it its replies. This value should not be longer than
+# rpc_response_timeout. (integer value)
+# Deprecated group/name - [oslo_messaging_rabbit]/kombu_reconnect_timeout
+#kombu_missing_consumer_retry_timeout = 60
+
+# Determines how the next RabbitMQ node is chosen in case the
+# one we are currently connected to becomes unavailable. Takes
+# effect only if more than one RabbitMQ node is provided in
+# common. (string value)
+# Allowed values: round-robin, shuffle
+#kombu_failover_strategy = round-robin
+
+# DEPRECATED: The RabbitMQ broker address where a single node
+# is used. (string value)
+# Deprecated group/name - [DEFAULT]/rabbit_host
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Replaced by [DEFAULT]/transport_url
+#rabbit_host = localhost
+
+# DEPRECATED: The RabbitMQ broker port where a single node is
+# used. (port value)
+# Minimum value: 0
+# Maximum value: 65535
+# Deprecated group/name - [DEFAULT]/rabbit_port
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Replaced by [DEFAULT]/transport_url
+#rabbit_port = 5672
+
+# DEPRECATED: RabbitMQ HA cluster host:port pairs. (list
+# value)
+# Deprecated group/name - [DEFAULT]/rabbit_hosts
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Replaced by [DEFAULT]/transport_url
+#rabbit_hosts = $rabbit_host:$rabbit_port
+
+# DEPRECATED: The RabbitMQ userid. (string value)
+# Deprecated group/name - [DEFAULT]/rabbit_userid
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Replaced by [DEFAULT]/transport_url
+#rabbit_userid = guest
+
+# DEPRECATED: The RabbitMQ password. (string value)
+# Deprecated group/name - [DEFAULT]/rabbit_password
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Replaced by [DEFAULT]/transport_url
+#rabbit_password = guest
+
+# The RabbitMQ login method. (string value)
+# Allowed values: PLAIN, AMQPLAIN, RABBIT-CR-DEMO
+# Deprecated group/name - [DEFAULT]/rabbit_login_method
+#rabbit_login_method = AMQPLAIN
+
+# DEPRECATED: The RabbitMQ virtual host. (string value)
+# Deprecated group/name - [DEFAULT]/rabbit_virtual_host
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Replaced by [DEFAULT]/transport_url
+#rabbit_virtual_host = /
+
+# How frequently to retry connecting with RabbitMQ. (integer
+# value)
+#rabbit_retry_interval = 1
+
+# How long to backoff for between retries when connecting to
+# RabbitMQ. (integer value)
+# Deprecated group/name - [DEFAULT]/rabbit_retry_backoff
+#rabbit_retry_backoff = 2
+
+# Maximum interval of RabbitMQ connection retries. Default is
+# 30 seconds. (integer value)
+#rabbit_interval_max = 30
+
+# DEPRECATED: Maximum number of RabbitMQ connection retries.
+# Default is 0 (infinite retry count). (integer value)
+# Deprecated group/name - [DEFAULT]/rabbit_max_retries
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+#rabbit_max_retries = 0
+
+# Try to use HA queues in RabbitMQ (x-ha-policy: all). If you
+# change this option, you must wipe the RabbitMQ database. In
+# RabbitMQ 3.0, queue mirroring is no longer controlled by the
+# x-ha-policy argument when declaring a queue. If you just
+# want to make sure that all queues (except those with auto-
+# generated names) are mirrored across all nodes, run:
+# "rabbitmqctl set_policy HA '^(?!amq\.).*' '{"ha-mode":
+# "all"}' " (boolean value)
+# Deprecated group/name - [DEFAULT]/rabbit_ha_queues
+#rabbit_ha_queues = false
+
+# Positive integer representing duration in seconds for queue
+# TTL (x-expires). Queues which are unused for the duration of
+# the TTL are automatically deleted. The parameter affects
+# only reply and fanout queues. (integer value)
+# Minimum value: 1
+#rabbit_transient_queues_ttl = 1800
+
+# Specifies the number of messages to prefetch. Setting to
+# zero allows unlimited messages. (integer value)
+#rabbit_qos_prefetch_count = 0
+
+# Number of seconds after which the Rabbit broker is
+# considered down if heartbeat's keep-alive fails (0 disable
+# the heartbeat). EXPERIMENTAL (integer value)
+#heartbeat_timeout_threshold = 60
+
+# How often times during the heartbeat_timeout_threshold we
+# check the heartbeat. (integer value)
+#heartbeat_rate = 2
+
+# Deprecated, use rpc_backend=kombu+memory or rpc_backend=fake
+# (boolean value)
+# Deprecated group/name - [DEFAULT]/fake_rabbit
+#fake_rabbit = false
+
+# Maximum number of channels to allow (integer value)
+#channel_max = <None>
+
+# The maximum byte size for an AMQP frame (integer value)
+#frame_max = <None>
+
+# How often to send heartbeats for consumer's connections
+# (integer value)
+#heartbeat_interval = 3
+
+# Arguments passed to ssl.wrap_socket (dict value)
+#ssl_options = <None>
+
+# Set socket timeout in seconds for connection's socket
+# (floating point value)
+#socket_timeout = 0.25
+
+# Set TCP_USER_TIMEOUT in seconds for connection's socket
+# (floating point value)
+#tcp_user_timeout = 0.25
+
+# Set delay for reconnection to some host which has connection
+# error (floating point value)
+#host_connection_reconnect_delay = 0.25
+
+# Connection factory implementation (string value)
+# Allowed values: new, single, read_write
+#connection_factory = single
+
+# Maximum number of connections to keep queued. (integer
+# value)
+#pool_max_size = 30
+
+# Maximum number of connections to create above
+# `pool_max_size`. (integer value)
+#pool_max_overflow = 0
+
+# Default number of seconds to wait for a connections to
+# available (integer value)
+#pool_timeout = 30
+
+# Lifetime of a connection (since creation) in seconds or None
+# for no recycling. Expired connections are closed on acquire.
+# (integer value)
+#pool_recycle = 600
+
+# Threshold at which inactive (since release) connections are
+# considered stale in seconds or None for no staleness. Stale
+# connections are closed on acquire. (integer value)
+#pool_stale = 60
+
+# Default serialization mechanism for
+# serializing/deserializing outgoing/incoming messages (string
+# value)
+# Allowed values: json, msgpack
+#default_serializer_type = json
+
+# Persist notification messages. (boolean value)
+#notification_persistence = false
+
+# Exchange name for sending notifications (string value)
+#default_notification_exchange = ${control_exchange}_notification
+
+# Max number of not acknowledged message which RabbitMQ can
+# send to notification listener. (integer value)
+#notification_listener_prefetch_count = 100
+
+# Reconnecting retry count in case of connectivity problem
+# during sending notification, -1 means infinite retry.
+# (integer value)
+#default_notification_retry_attempts = -1
+
+# Reconnecting retry delay in case of connectivity problem
+# during sending notification message (floating point value)
+#notification_retry_delay = 0.25
+
+# Time to live for rpc queues without consumers in seconds.
+# (integer value)
+#rpc_queue_expiration = 60
+
+# Exchange name for sending RPC messages (string value)
+#default_rpc_exchange = ${control_exchange}_rpc
+
+# Exchange name for receiving RPC replies (string value)
+#rpc_reply_exchange = ${control_exchange}_rpc_reply
+
+# Max number of not acknowledged message which RabbitMQ can
+# send to rpc listener. (integer value)
+#rpc_listener_prefetch_count = 100
+
+# Max number of not acknowledged message which RabbitMQ can
+# send to rpc reply listener. (integer value)
+#rpc_reply_listener_prefetch_count = 100
+
+# Reconnecting retry count in case of connectivity problem
+# during sending reply. -1 means infinite retry during
+# rpc_timeout (integer value)
+#rpc_reply_retry_attempts = -1
+
+# Reconnecting retry delay in case of connectivity problem
+# during sending reply. (floating point value)
+#rpc_reply_retry_delay = 0.25
+
+# Reconnecting retry count in case of connectivity problem
+# during sending RPC message, -1 means infinite retry. If
+# actual retry attempts in not 0 the rpc request could be
+# processed more than one time (integer value)
+#default_rpc_retry_attempts = -1
+
+# Reconnecting retry delay in case of connectivity problem
+# during sending RPC message (floating point value)
+#rpc_retry_delay = 0.25
+
+
+[oslo_messaging_zmq]
+
+#
+# From oslo.messaging
+#
+
+# ZeroMQ bind address. Should be a wildcard (*), an ethernet
+# interface, or IP. The "host" option should point or resolve
+# to this address. (string value)
+# Deprecated group/name - [DEFAULT]/rpc_zmq_bind_address
+#rpc_zmq_bind_address = *
+
+# MatchMaker driver. (string value)
+# Allowed values: redis, sentinel, dummy
+# Deprecated group/name - [DEFAULT]/rpc_zmq_matchmaker
+#rpc_zmq_matchmaker = redis
+
+# Number of ZeroMQ contexts, defaults to 1. (integer value)
+# Deprecated group/name - [DEFAULT]/rpc_zmq_contexts
+#rpc_zmq_contexts = 1
+
+# Maximum number of ingress messages to locally buffer per
+# topic. Default is unlimited. (integer value)
+# Deprecated group/name - [DEFAULT]/rpc_zmq_topic_backlog
+#rpc_zmq_topic_backlog = <None>
+
+# Directory for holding IPC sockets. (string value)
+# Deprecated group/name - [DEFAULT]/rpc_zmq_ipc_dir
+#rpc_zmq_ipc_dir = /var/run/openstack
+
+# Name of this node. Must be a valid hostname, FQDN, or IP
+# address. Must match "host" option, if running Nova. (string
+# value)
+# Deprecated group/name - [DEFAULT]/rpc_zmq_host
+#rpc_zmq_host = localhost
+
+# Number of seconds to wait before all pending messages will
+# be sent after closing a socket. The default value of -1
+# specifies an infinite linger period. The value of 0
+# specifies no linger period. Pending messages shall be
+# discarded immediately when the socket is closed. Positive
+# values specify an upper bound for the linger period.
+# (integer value)
+# Deprecated group/name - [DEFAULT]/rpc_cast_timeout
+#zmq_linger = -1
+
+# The default number of seconds that poll should wait. Poll
+# raises timeout exception when timeout expired. (integer
+# value)
+# Deprecated group/name - [DEFAULT]/rpc_poll_timeout
+#rpc_poll_timeout = 1
+
+# Expiration timeout in seconds of a name service record about
+# existing target ( < 0 means no timeout). (integer value)
+# Deprecated group/name - [DEFAULT]/zmq_target_expire
+#zmq_target_expire = 300
+
+# Update period in seconds of a name service record about
+# existing target. (integer value)
+# Deprecated group/name - [DEFAULT]/zmq_target_update
+#zmq_target_update = 180
+
+# Use PUB/SUB pattern for fanout methods. PUB/SUB always uses
+# proxy. (boolean value)
+# Deprecated group/name - [DEFAULT]/use_pub_sub
+#use_pub_sub = false
+
+# Use ROUTER remote proxy. (boolean value)
+# Deprecated group/name - [DEFAULT]/use_router_proxy
+#use_router_proxy = false
+
+# This option makes direct connections dynamic or static. It
+# makes sense only with use_router_proxy=False which means to
+# use direct connections for direct message types (ignored
+# otherwise). (boolean value)
+#use_dynamic_connections = false
+
+# How many additional connections to a host will be made for
+# failover reasons. This option is actual only in dynamic
+# connections mode. (integer value)
+#zmq_failover_connections = 2
+
+# Minimal port number for random ports range. (port value)
+# Minimum value: 0
+# Maximum value: 65535
+# Deprecated group/name - [DEFAULT]/rpc_zmq_min_port
+#rpc_zmq_min_port = 49153
+
+# Maximal port number for random ports range. (integer value)
+# Minimum value: 1
+# Maximum value: 65536
+# Deprecated group/name - [DEFAULT]/rpc_zmq_max_port
+#rpc_zmq_max_port = 65536
+
+# Number of retries to find free port number before fail with
+# ZMQBindError. (integer value)
+# Deprecated group/name - [DEFAULT]/rpc_zmq_bind_port_retries
+#rpc_zmq_bind_port_retries = 100
+
+# Default serialization mechanism for
+# serializing/deserializing outgoing/incoming messages (string
+# value)
+# Allowed values: json, msgpack
+# Deprecated group/name - [DEFAULT]/rpc_zmq_serialization
+#rpc_zmq_serialization = json
+
+# This option configures round-robin mode in zmq socket. True
+# means not keeping a queue when server side disconnects.
+# False means to keep queue and messages even if server is
+# disconnected, when the server appears we send all
+# accumulated messages to it. (boolean value)
+#zmq_immediate = true
+
+# Enable/disable TCP keepalive (KA) mechanism. The default
+# value of -1 (or any other negative value) means to skip any
+# overrides and leave it to OS default; 0 and 1 (or any other
+# positive value) mean to disable and enable the option
+# respectively. (integer value)
+#zmq_tcp_keepalive = -1
+
+# The duration between two keepalive transmissions in idle
+# condition. The unit is platform dependent, for example,
+# seconds in Linux, milliseconds in Windows etc. The default
+# value of -1 (or any other negative value and 0) means to
+# skip any overrides and leave it to OS default. (integer
+# value)
+#zmq_tcp_keepalive_idle = -1
+
+# The number of retransmissions to be carried out before
+# declaring that remote end is not available. The default
+# value of -1 (or any other negative value and 0) means to
+# skip any overrides and leave it to OS default. (integer
+# value)
+#zmq_tcp_keepalive_cnt = -1
+
+# The duration between two successive keepalive
+# retransmissions, if acknowledgement to the previous
+# keepalive transmission is not received. The unit is platform
+# dependent, for example, seconds in Linux, milliseconds in
+# Windows etc. The default value of -1 (or any other negative
+# value and 0) means to skip any overrides and leave it to OS
+# default. (integer value)
+#zmq_tcp_keepalive_intvl = -1
+
+# Maximum number of (green) threads to work concurrently.
+# (integer value)
+#rpc_thread_pool_size = 100
+
+# Expiration timeout in seconds of a sent/received message
+# after which it is not tracked anymore by a client/server.
+# (integer value)
+#rpc_message_ttl = 300
+
+# Wait for message acknowledgements from receivers. This
+# mechanism works only via proxy without PUB/SUB. (boolean
+# value)
+#rpc_use_acks = false
+
+# Number of seconds to wait for an ack from a cast/call. After
+# each retry attempt this timeout is multiplied by some
+# specified multiplier. (integer value)
+#rpc_ack_timeout_base = 15
+
+# Number to multiply base ack timeout by after each retry
+# attempt. (integer value)
+#rpc_ack_timeout_multiplier = 2
+
+# Default number of message sending attempts in case of any
+# problems occurred: positive value N means at most N retries,
+# 0 means no retries, None or -1 (or any other negative
+# values) mean to retry forever. This option is used only if
+# acknowledgments are enabled. (integer value)
+#rpc_retry_attempts = 3
+
+# List of publisher hosts SubConsumer can subscribe on. This
+# option has higher priority then the default publishers list
+# taken from the matchmaker. (list value)
+#subscribe_on =
+
+
+[oslo_policy]
+
+#
+# From oslo.policy
+#
+
+# The file that defines policies. (string value)
+# Deprecated group/name - [DEFAULT]/policy_file
+#policy_file = policy.json
+
+# Default rule. Enforced when a requested rule is not found.
+# (string value)
+# Deprecated group/name - [DEFAULT]/policy_default_rule
+#policy_default_rule = default
+
+# Directories where policy configuration files are stored.
+# They can be relative to any directory in the search path
+# defined by the config_dir option, or absolute paths. The
+# file defined by policy_file must exist for these directories
+# to be searched. Missing or empty directories are ignored.
+# (multi valued)
+# Deprecated group/name - [DEFAULT]/policy_dirs
+#policy_dirs = policy.d
+
+
+[pxe]
+
+#
+# From ironic
+#
+
+# Additional append parameters for baremetal PXE boot. (string
+# value)
+#pxe_append_params = nofb nomodeset vga=normal
+
+# Default file system format for ephemeral partition, if one
+# is created. (string value)
+#default_ephemeral_format = ext4
+
+# On the ironic-conductor node, directory where images are
+# stored on disk. (string value)
+#images_path = /var/lib/ironic/images/
+
+# On the ironic-conductor node, directory where master
+# instance images are stored on disk. Setting to <None>
+# disables image caching. (string value)
+#instance_master_path = /var/lib/ironic/master_images
+
+# Maximum size (in MiB) of cache for master images, including
+# those in use. (integer value)
+#image_cache_size = 20480
+
+# Maximum TTL (in minutes) for old master images in cache.
+# (integer value)
+#image_cache_ttl = 10080
+
+# On ironic-conductor node, template file for PXE
+# configuration. (string value)
+{%- if conductor.get('pxe_config_template') %}
+pxe_config_template = {{ conductor.pxe_config_template }}
+{%- else %}
+#pxe_config_template = $pybasedir/drivers/modules/pxe_common.template
+{%- endif %}
+
+# On ironic-conductor node, template file for PXE
+# configuration for UEFI boot loader. (string value)
+#uefi_pxe_config_template = $pybasedir/drivers/modules/pxe_grub_common.template
+
+# On ironic-conductor node, template file for PXE
+# configuration per node architecture. For example:
+# aarch64:/opt/share/grubaa64_pxe_common.template (dict value)
+#pxe_config_template_by_arch =
+
+# IP address of ironic-conductor node's TFTP server. (string
+# value)
+#tftp_server = $my_ip
+
+# ironic-conductor node's TFTP root path. The ironic-conductor
+# must have read/write access to this path. (string value)
+{%- if conductor.get('tftp_root') %}
+tftp_root = {{ conductor.tftp_root }}
+{%- else %}
+#tftp_root = /tftpboot
+{%- endif %}
+
+# On ironic-conductor node, directory where master TFTP images
+# are stored on disk. Setting to <None> disables image
+# caching. (string value)
+{%- if conductor.get('tftp_master_path') %}
+tftp_master_path = {{ conductor.tftp_master_path }}
+{%- else %}
+#tftp_master_path = /tftpboot/master_images
+{%- endif %}
+
+# Bootfile DHCP parameter. (string value)
+{%- if conductor.get('pxe_config_template') %}
+pxe_bootfile_name = {{ conductor.pxe_bootfile_name }}
+{%- else %}
+#pxe_bootfile_name = pxelinux.0
+{%- endif %}
+
+# Bootfile DHCP parameter for UEFI boot mode. (string value)
+#uefi_pxe_bootfile_name = bootx64.efi
+
+# Bootfile DHCP parameter per node architecture. For example:
+# aarch64:grubaa64.efi (dict value)
+#pxe_bootfile_name_by_arch =
+
+# Enable iPXE boot. (boolean value)
+{%- if conductor.ipxe_enabled is defined %}
+ipxe_enabled = {{ conductor.ipxe_enabled }}
+{%- else %}
+#ipxe_enabled = false
+{%- endif %}
+
+# On ironic-conductor node, the path to the main iPXE script
+# file. (string value)
+#ipxe_boot_script = $pybasedir/drivers/modules/boot.ipxe
+
+# Timeout value (in seconds) for downloading an image via
+# iPXE. Defaults to 0 (no timeout) (integer value)
+#ipxe_timeout = 0
+
+# The IP version that will be used for PXE booting. Defaults
+# to 4. EXPERIMENTAL (string value)
+# Allowed values: 4, 6
+#ip_version = 4
+
+# Download deploy images directly from swift using temporary
+# URLs. If set to false (default), images are downloaded to
+# the ironic-conductor node and served over its local HTTP
+# server. Applicable only when 'ipxe_enabled' option is set to
+# true. (boolean value)
+#ipxe_use_swift = false
+
+
+[service_catalog]
+
+#
+# From ironic
+#
+
+# Authentication URL (string value)
+{%- if ironic.get('identity', {}).get('engine') == 'keystone' %}
+auth_url = {{ ironic.identity.protocol }}://{{ ironic.identity.host }}:{{ ironic.identity.port }}/identity
+{%- else %}
+#auth_url = <None>
+{%- endif %}
+
+# Authentication type to load (string value)
+# Deprecated group/name - [service_catalog]/auth_plugin
+{%- if ironic.get('identity', {}).get('auth_type') %}
+auth_type = {{ ironic.identity.auth_type }}
+{%- else %}
+#auth_type = <None>
+{%- endif %}
+
+# PEM encoded Certificate Authority to use when verifying
+# HTTPs connections. (string value)
+#cafile = <None>
+
+# PEM encoded client certificate cert file (string value)
+#certfile = <None>
+
+# Optional domain ID to use with v3 and v2 parameters. It will
+# be used for both the user and project domain in v3 and
+# ignored in v2 authentication. (string value)
+{%- if ironic.get('identity', {}).get('default_domain_id') %}
+default_domain_id = {{ ironic.identity.default_domain_id }}
+{%- else %}
+#default_domain_id = <None>
+{%- endif %}
+
+# Optional domain name to use with v3 API and v2 parameters.
+# It will be used for both the user and project domain in v3
+# and ignored in v2 authentication. (string value)
+{%- if ironic.get('identity', {}).get('default_domain_name') %}
+default_domain_name = {{ ironic.identity.default_domain_name }}
+{%- else %}
+#default_domain_name = <None>
+{%- endif %}
+
+# Domain ID to scope to (string value)
+{%- if ironic.get('identity', {}).get('domain_id') %}
+domain_id = {{ ironic.identity.domain_id }}
+{%- else %}
+#domain_id = <None>
+{%- endif %}
+
+# Domain name to scope to (string value)
+{%- if ironic.get('identity', {}).get('domain_name') %}
+domain_name = {{ ironic.identity.domain_name }}
+{%- else %}
+#domain_name = <None>
+{%- endif %}
+
+# Verify HTTPS connections. (boolean value)
+#insecure = false
+
+# PEM encoded client certificate key file (string value)
+#keyfile = <None>
+
+# User's password (string value)
+{%- if ironic.get('identity', {}).get('password') %}
+password = {{ ironic.identity.password }}
+{%- else %}
+#password = <None>
+{%- endif %}
+
+# Domain ID containing project (string value)
+{%- if ironic.get('identity', {}).get('project_domain_id') %}
+project_domain_id = {{ ironic.identity.project_domain_id }}
+{%- else %}
+#project_domain_id = <None>
+{%- endif %}
+
+# Domain name containing project (string value)
+{%- if ironic.get('identity', {}).get('project_domain_name') %}
+project_domain_name = {{ ironic.identity.project_domain_name }}
+{%- else %}
+#project_domain_name = <None>
+{%- endif %}
+
+# Project ID to scope to (string value)
+# Deprecated group/name - [service_catalog]/tenant-id
+{%- if ironic.get('identity', {}).get('project_id') %}
+project_id = {{ ironic.identity.project_id }}
+{%- else %}
+#project_id = <None>
+{%- endif %}
+
+# Project name to scope to (string value)
+# Deprecated group/name - [service_catalog]/tenant-name
+{%- if ironic.get('identity', {}).get('project_name') %}
+project_name = {{ ironic.identity.project_name }}
+{%- else %}
+#project_name = <None>
+{%- endif %}
+
+# Tenant ID (string value)
+{%- if ironic.get('identity', {}).get('tenant_id') %}
+tenant_id = {{ ironic.identity.tenant_id }}
+{%- else %}
+#tenant_id = <None>
+{%- endif %}
+
+# Tenant Name (string value)
+{%- if ironic.get('identity', {}).get('tenant_name') %}
+tenant_name = {{ ironic.identity.tenant_name }}
+{%- else %}
+#tenant_name = <None>
+{%- endif %}
+
+# Timeout value for http requests (integer value)
+#timeout = <None>
+
+# Trust ID (string value)
+#trust_id = <None>
+
+# User's domain id (string value)
+{%- if ironic.get('identity', {}).get('user_domain_id') %}
+user_domain_id = {{ ironic.identity.user_domain_id }}
+{%- else %}
+#user_domain_id = <None>
+{%- endif %}
+
+# User's domain name (string value)
+{%- if ironic.get('identity', {}).get('user_domain_name') %}
+user_domain_name = {{ ironic.identity.user_domain_name }}
+{%- else %}
+#user_domain_name = <None>
+{%- endif %}
+
+# User id (string value)
+{%- if ironic.get('identity', {}).get('user_id')  %}
+user_id = {{ ironic.identity.user_id }}
+{%- else %}
+#user_id = <None>
+{%- endif %}
+
+# Username (string value)
+# Deprecated group/name - [service_catalog]/user-name
+{%- if ironic.get('identity', {}).get('user') %}
+username = {{ ironic.identity.user }}
+{%- else %}
+#username = <None>
+{%- endif %}
+
+
+[snmp]
+
+#
+# From ironic
+#
+
+# Seconds to wait for power action to be completed (integer
+# value)
+#power_timeout = 10
+
+# Time (in seconds) to sleep between when rebooting (powering
+# off and on again) (integer value)
+# Minimum value: 0
+#reboot_delay = 0
+
+
+[ssh]
+
+#
+# From ironic
+#
+
+# libvirt URI. (string value)
+#libvirt_uri = qemu:///system
+
+# Number of attempts to try to get VM name used by the host
+# that corresponds to a node's MAC address. (integer value)
+#get_vm_name_attempts = 3
+
+# Number of seconds to wait between attempts to get VM name
+# used by the host that corresponds to a node's MAC address.
+# (integer value)
+#get_vm_name_retry_interval = 3
+
+
+[ssl]
+
+#
+# From oslo.service.sslutils
+#
+
+# CA certificate file to use to verify connecting clients.
+# (string value)
+# Deprecated group/name - [DEFAULT]/ssl_ca_file
+#ca_file = <None>
+
+# Certificate file to use when starting the server securely.
+# (string value)
+# Deprecated group/name - [DEFAULT]/ssl_cert_file
+#cert_file = <None>
+
+# Private key file to use when starting the server securely.
+# (string value)
+# Deprecated group/name - [DEFAULT]/ssl_key_file
+#key_file = <None>
+
+# SSL version to use (valid only if SSL enabled). Valid values
+# are TLSv1 and SSLv23. SSLv2, SSLv3, TLSv1_1, and TLSv1_2 may
+# be available on some distributions. (string value)
+#version = <None>
+
+# Sets the list of available ciphers. value should be a string
+# in the OpenSSL cipher list format. (string value)
+#ciphers = <None>
+
+
+[swift]
+
+#
+# From ironic
+#
+
+# Authentication URL (string value)
+#auth_url = <None>
+
+# Authentication type to load (string value)
+# Deprecated group/name - [swift]/auth_plugin
+#auth_type = <None>
+
+# PEM encoded Certificate Authority to use when verifying
+# HTTPs connections. (string value)
+#cafile = <None>
+
+# PEM encoded client certificate cert file (string value)
+#certfile = <None>
+
+# Optional domain ID to use with v3 and v2 parameters. It will
+# be used for both the user and project domain in v3 and
+# ignored in v2 authentication. (string value)
+#default_domain_id = <None>
+
+# Optional domain name to use with v3 API and v2 parameters.
+# It will be used for both the user and project domain in v3
+# and ignored in v2 authentication. (string value)
+#default_domain_name = <None>
+
+# Domain ID to scope to (string value)
+#domain_id = <None>
+
+# Domain name to scope to (string value)
+#domain_name = <None>
+
+# Verify HTTPS connections. (boolean value)
+#insecure = false
+
+# PEM encoded client certificate key file (string value)
+#keyfile = <None>
+
+# User's password (string value)
+#password = <None>
+
+# Domain ID containing project (string value)
+#project_domain_id = <None>
+
+# Domain name containing project (string value)
+#project_domain_name = <None>
+
+# Project ID to scope to (string value)
+# Deprecated group/name - [swift]/tenant-id
+#project_id = <None>
+
+# Project name to scope to (string value)
+# Deprecated group/name - [swift]/tenant-name
+#project_name = <None>
+
+# Maximum number of times to retry a Swift request, before
+# failing. (integer value)
+#swift_max_retries = 2
+
+# Tenant ID (string value)
+#tenant_id = <None>
+
+# Tenant Name (string value)
+#tenant_name = <None>
+
+# Timeout value for http requests (integer value)
+#timeout = <None>
+
+# Trust ID (string value)
+#trust_id = <None>
+
+# User's domain id (string value)
+#user_domain_id = <None>
+
+# User's domain name (string value)
+#user_domain_name = <None>
+
+# User id (string value)
+#user_id = <None>
+
+# Username (string value)
+# Deprecated group/name - [swift]/user-name
+#username = <None>
diff --git a/ironic/files/ocata/ironic.conf b/ironic/files/ocata/ironic.conf
new file mode 100644
index 0000000..1e2500f
--- /dev/null
+++ b/ironic/files/ocata/ironic.conf
@@ -0,0 +1,3941 @@
+{%- from "ironic/map.jinja" import api,conductor with context -%}
+{%- if api.get("enabled", False) %}
+  {%- set ironic = api %}
+{%- elif conductor.get('enabled', False) %}
+  {%- set ironic = conductor %}
+{%- endif %}
+[DEFAULT]
+
+#
+# From ironic
+#
+
+# Authentication strategy used by ironic-api. "noauth" should
+# not be used in a production environment because all
+# authentication will be disabled. (string value)
+# Allowed values: noauth, keystone
+{%- if ironic.identity is defined %}
+auth_strategy = {{ ironic.identity.engine }}
+{%- else %}
+#auth_strategy = keystone
+{%- endif %}
+
+# Specify the list of drivers to load during service
+# initialization. Missing drivers, or drivers which fail to
+# initialize, will prevent the conductor service from
+# starting. The option default is a recommended set of
+# production-oriented drivers. A complete list of drivers
+# present on your system may be found by enumerating the
+# "ironic.drivers" entrypoint. An example may be found in the
+# developer documentation online. (list value)
+{%- if conductor.get('enabled_drivers') %}
+enabled_drivers = {{ ','.join(conductor.enabled_drivers) }}
+{%- else %}
+#enabled_drivers = pxe_ipmitool
+{%- endif %}
+
+# Specify the list of hardware types to load during service
+# initialization. Missing hardware types, or hardware types
+# which fail to initialize, will prevent the conductor service
+# from starting. This option defaults to a recommended set of
+# production-oriented hardware types. A complete list of
+# hardware types present on your system may be found by
+# enumerating the "ironic.hardware.types" entrypoint. (list
+# value)
+{%- if conductor.get('enabled_hardware_types') %}
+enabled_hardware_types = {{ ','.join(conductor.enabled_hardware_types) }}
+{%- else %}
+#enabled_hardware_types = ipmi
+{%- endif %}
+
+# Specify the list of boot interfaces to load during service
+# initialization. Missing boot interfaces, or boot interfaces
+# which fail to initialize, will prevent the ironic-conductor
+# service from starting. At least one boot interface that is
+# supported by each enabled hardware type must be enabled
+# here, or the ironic-conductor service will not start. Must
+# not be an empty list. The default value is a recommended set
+# of production-oriented boot interfaces. A complete list of
+# boot interfaces present on your system may be found by
+# enumerating the "ironic.hardware.interfaces.boot"
+# entrypoint. When setting this value, please make sure that
+# every enabled hardware type will have the same set of
+# enabled boot interfaces on every ironic-conductor service.
+# (list value)
+{%- if conductor.get('enabled_boot_interfaces') %}
+enabled_boot_interfaces = {{ ','.join(conductor.enabled_boot_interfaces) }}
+{%- else %}
+#enabled_boot_interfaces = pxe
+{%- endif %}
+
+# Default boot interface to be used for nodes that do not have
+# boot_interface field set. A complete list of boot interfaces
+# present on your system may be found by enumerating the
+# "ironic.hardware.interfaces.boot" entrypoint. (string value)
+{%- if conductor.get('default_boot_interface') %}
+default_boot_interface = {{ conductor.default_boot_interface }}
+{%- else %}
+#default_boot_interface = <None>
+{%- endif %}
+
+# Specify the list of console interfaces to load during
+# service initialization. Missing console interfaces, or
+# console interfaces which fail to initialize, will prevent
+# the ironic-conductor service from starting. At least one
+# console interface that is supported by each enabled hardware
+# type must be enabled here, or the ironic-conductor service
+# will not start. Must not be an empty list. The default value
+# is a recommended set of production-oriented console
+# interfaces. A complete list of console interfaces present on
+# your system may be found by enumerating the
+# "ironic.hardware.interfaces.console" entrypoint. When
+# setting this value, please make sure that every enabled
+# hardware type will have the same set of enabled console
+# interfaces on every ironic-conductor service. (list value)
+{%- if conductor.get('enabled_console_interfaces') %}
+enabled_console_interfaces = {{ ','.join(conductor.enabled_console_interfaces) }}
+{%- else %}
+#enabled_console_interfaces = no-console
+{%- endif %}
+
+# Default console interface to be used for nodes that do not
+# have console_interface field set. A complete list of console
+# interfaces present on your system may be found by
+# enumerating the "ironic.hardware.interfaces.console"
+# entrypoint. (string value)
+{%- if conductor.get('default_console_interface') %}
+default_console_interface = {{ conductor.default_console_interface }}
+{%- else %}
+#default_console_interface = <None>
+{%- endif %}
+
+# Specify the list of deploy interfaces to load during service
+# initialization. Missing deploy interfaces, or deploy
+# interfaces which fail to initialize, will prevent the
+# ironic-conductor service from starting. At least one deploy
+# interface that is supported by each enabled hardware type
+# must be enabled here, or the ironic-conductor service will
+# not start. Must not be an empty list. The default value is a
+# recommended set of production-oriented deploy interfaces. A
+# complete list of deploy interfaces present on your system
+# may be found by enumerating the
+# "ironic.hardware.interfaces.deploy" entrypoint. When setting
+# this value, please make sure that every enabled hardware
+# type will have the same set of enabled deploy interfaces on
+# every ironic-conductor service. (list value)
+{%- if conductor.get('enabled_deploy_interfaces') %}
+enabled_deploy_interfaces = {{ ','.join(conductor.enabled_deploy_interfaces) }}
+{%- else %}
+#enabled_deploy_interfaces = iscsi,direct
+{%- endif %}
+
+# Default deploy interface to be used for nodes that do not
+# have deploy_interface field set. A complete list of deploy
+# interfaces present on your system may be found by
+# enumerating the "ironic.hardware.interfaces.deploy"
+# entrypoint. (string value)
+{%- if conductor.get('default_deploy_interface') %}
+default_deploy_interface = {{ conductor.default_deploy_interface }}
+{%- else %}
+#default_deploy_interface = <None>
+{%- endif %}
+
+# Specify the list of inspect interfaces to load during
+# service initialization. Missing inspect interfaces, or
+# inspect interfaces which fail to initialize, will prevent
+# the ironic-conductor service from starting. At least one
+# inspect interface that is supported by each enabled hardware
+# type must be enabled here, or the ironic-conductor service
+# will not start. Must not be an empty list. The default value
+# is a recommended set of production-oriented inspect
+# interfaces. A complete list of inspect interfaces present on
+# your system may be found by enumerating the
+# "ironic.hardware.interfaces.inspect" entrypoint. When
+# setting this value, please make sure that every enabled
+# hardware type will have the same set of enabled inspect
+# interfaces on every ironic-conductor service. (list value)
+{%- if conductor.get('enabled_inspect_interfaces') %}
+enabled_inspect_interfaces = {{ ','.join(conductor.enabled_inspect_interfaces) }}
+{%- else %}
+#enabled_inspect_interfaces = no-inspect
+{%- endif %}
+
+# Default inspect interface to be used for nodes that do not
+# have inspect_interface field set. A complete list of inspect
+# interfaces present on your system may be found by
+# enumerating the "ironic.hardware.interfaces.inspect"
+# entrypoint. (string value)
+{%- if conductor.get('default_inspect_interface') %}
+default_inspect_interface = {{ conductor.default_inspect_interface }}
+{%- else %}
+#default_inspect_interface = <None>
+{%- endif %}
+
+# Specify the list of management interfaces to load during
+# service initialization. Missing management interfaces, or
+# management interfaces which fail to initialize, will prevent
+# the ironic-conductor service from starting. At least one
+# management interface that is supported by each enabled
+# hardware type must be enabled here, or the ironic-conductor
+# service will not start. Must not be an empty list. The
+# default value is a recommended set of production-oriented
+# management interfaces. A complete list of management
+# interfaces present on your system may be found by
+# enumerating the "ironic.hardware.interfaces.management"
+# entrypoint. When setting this value, please make sure that
+# every enabled hardware type will have the same set of
+# enabled management interfaces on every ironic-conductor
+# service. (list value)
+{%- if conductor.get('enabled_management_interfaces') %}
+enabled_management_interfaces = {{ ','.join(conductor.enabled_management_interfaces) }}
+{%- else %}
+#enabled_management_interfaces = ipmitool
+{%- endif %}
+
+# Default management interface to be used for nodes that do
+# not have management_interface field set. A complete list of
+# management interfaces present on your system may be found by
+# enumerating the "ironic.hardware.interfaces.management"
+# entrypoint. (string value)
+{%- if conductor.get('default_management_interface') %}
+default_management_interface = {{ conductor.default_management_interface }}
+{%- else %}
+#default_management_interface = <None>
+{%- endif %}
+
+# Specify the list of network interfaces to load during
+# service initialization. Missing network interfaces, or
+# network interfaces which fail to initialize, will prevent
+# the ironic-conductor service from starting. At least one
+# network interface that is supported by each enabled hardware
+# type must be enabled here, or the ironic-conductor service
+# will not start. Must not be an empty list. The default value
+# is a recommended set of production-oriented network
+# interfaces. A complete list of network interfaces present on
+# your system may be found by enumerating the
+# "ironic.hardware.interfaces.network" entrypoint. When
+# setting this value, please make sure that every enabled
+# hardware type will have the same set of enabled network
+# interfaces on every ironic-conductor service. (list value)
+{%- if conductor.get('enabled_network_interfaces') %}
+enabled_network_interfaces = {{ ','.join(conductor.enabled_network_interfaces) }}
+{%- else %}
+#enabled_network_interfaces = flat,noop
+{%- endif %}
+
+# Default network interface to be used for nodes that do not
+# have network_interface field set. A complete list of network
+# interfaces present on your system may be found by
+# enumerating the "ironic.hardware.interfaces.network"
+# entrypoint. (string value)
+{%- if conductor.get('default_network_interface') %}
+default_network_interface = {{ conductor.default_network_interface }}
+{%- else %}
+#default_network_interface = <None>
+{%- endif %}
+
+# Specify the list of power interfaces to load during service
+# initialization. Missing power interfaces, or power
+# interfaces which fail to initialize, will prevent the
+# ironic-conductor service from starting. At least one power
+# interface that is supported by each enabled hardware type
+# must be enabled here, or the ironic-conductor service will
+# not start. Must not be an empty list. The default value is a
+# recommended set of production-oriented power interfaces. A
+# complete list of power interfaces present on your system may
+# be found by enumerating the
+# "ironic.hardware.interfaces.power" entrypoint. When setting
+# this value, please make sure that every enabled hardware
+# type will have the same set of enabled power interfaces on
+# every ironic-conductor service. (list value)
+{%- if conductor.get('enabled_power_interfaces') %}
+enabled_power_interfaces = {{ ','.join(conductor.enabled_power_interfaces) }}
+{%- else %}
+#enabled_power_interfaces = ipmitool
+{%- endif %}
+
+# Default power interface to be used for nodes that do not
+# have power_interface field set. A complete list of power
+# interfaces present on your system may be found by
+# enumerating the "ironic.hardware.interfaces.power"
+# entrypoint. (string value)
+{%- if conductor.get('default_power_interface') %}
+default_power_interface = {{ conductor.default_power_interface }}
+{%- else %}
+#default_power_interface = <None>
+{%- endif %}
+
+# Specify the list of raid interfaces to load during service
+# initialization. Missing raid interfaces, or raid interfaces
+# which fail to initialize, will prevent the ironic-conductor
+# service from starting. At least one raid interface that is
+# supported by each enabled hardware type must be enabled
+# here, or the ironic-conductor service will not start. Must
+# not be an empty list. The default value is a recommended set
+# of production-oriented raid interfaces. A complete list of
+# raid interfaces present on your system may be found by
+# enumerating the "ironic.hardware.interfaces.raid"
+# entrypoint. When setting this value, please make sure that
+# every enabled hardware type will have the same set of
+# enabled raid interfaces on every ironic-conductor service.
+# (list value)
+{%- if conductor.get('enabled_raid_interfaces') %}
+enabled_raid_interfaces = {{ ','.join(conductor.enabled_raid_interfaces) }}
+{%- else %}
+#enabled_raid_interfaces = agent,no-raid
+{%- endif %}
+
+# Default raid interface to be used for nodes that do not have
+# raid_interface field set. A complete list of raid interfaces
+# present on your system may be found by enumerating the
+# "ironic.hardware.interfaces.raid" entrypoint. (string value)
+{%- if conductor.get('default_raid_interface') %}
+default_raid_interface = {{ conductor.default_raid_interface }}
+{%- else %}
+#default_raid_interface = <None>
+{%- endif %}
+
+# Specify the list of storage interfaces to load during
+# service initialization. Missing storage interfaces, or
+# storage interfaces which fail to initialize, will prevent
+# the ironic-conductor service from starting. At least one
+# storage interface that is supported by each enabled hardware
+# type must be enabled here, or the ironic-conductor service
+# will not start. Must not be an empty list. The default value
+# is a recommended set of production-oriented storage
+# interfaces. A complete list of storage interfaces present on
+# your system may be found by enumerating the
+# "ironic.hardware.interfaces.storage" entrypoint. When
+# setting this value, please make sure that every enabled
+# hardware type will have the same set of enabled storage
+# interfaces on every ironic-conductor service. (list value)
+{%- if conductor.get('enabled_storage_interfaces') %}
+enabled_storage_interfaces = {{ ','.join(conductor.enabled_storage_interfaces) }}
+{%- else %}
+#enabled_storage_interfaces = noop
+{%- endif %}
+
+# Default storage interface to be used for nodes that do not
+# have storage_interface field set. A complete list of storage
+# interfaces present on your system may be found by
+# enumerating the "ironic.hardware.interfaces.storage"
+# entrypoint. (list value)
+{%- if conductor.get('default_storage_interface') %}
+default_storage_interface = {{ ironic.condcutor.default_storage_interface }}
+{%- else %}
+#default_storage_interface = <None>
+{%- endif %}
+
+# Specify the list of vendor interfaces to load during service
+# initialization. Missing vendor interfaces, or vendor
+# interfaces which fail to initialize, will prevent the
+# ironic-conductor service from starting. At least one vendor
+# interface that is supported by each enabled hardware type
+# must be enabled here, or the ironic-conductor service will
+# not start. Must not be an empty list. The default value is a
+# recommended set of production-oriented vendor interfaces. A
+# complete list of vendor interfaces present on your system
+# may be found by enumerating the
+# "ironic.hardware.interfaces.vendor" entrypoint. When setting
+# this value, please make sure that every enabled hardware
+# type will have the same set of enabled vendor interfaces on
+# every ironic-conductor service. (list value)
+{%- if conductor.get('enabled_vendor_interfaces') %}
+enabled_vendor_interfaces = {{ ','.join(conductor.enabled_vendor_interfaces) }}
+{%- else %}
+#enabled_vendor_interfaces = no-vendor
+{%- endif %}
+
+# Default vendor interface to be used for nodes that do not
+# have vendor_interface field set. A complete list of vendor
+# interfaces present on your system may be found by
+# enumerating the "ironic.hardware.interfaces.vendor"
+# entrypoint. (string value)
+{%- if conductor.get('default_vendor_interface') %}
+default_vendor_interface = {{ conductor.default_vendor_interface }}
+{%- else %}
+#default_vendor_interface = <None>
+{%- endif %}
+
+# Used if there is a formatting error when generating an
+# exception message (a programming error). If True, raise an
+# exception; if False, use the unformatted message. (boolean
+# value)
+#fatal_exception_format_errors = false
+
+# Exponent to determine number of hash partitions to use when
+# distributing load across conductors. Larger values will
+# result in more even distribution of load and less load when
+# rebalancing the ring, but more memory usage. Number of
+# partitions per conductor is (2^hash_partition_exponent).
+# This determines the granularity of rebalancing: given 10
+# hosts, and an exponent of the 2, there are 40 partitions in
+# the ring.A few thousand partitions should make rebalancing
+# smooth in most cases. The default is suitable for up to a
+# few hundred conductors. Configuring for too many partitions
+# has a negative impact on CPU usage. (integer value)
+#hash_partition_exponent = 5
+
+# [Experimental Feature] Number of hosts to map onto each hash
+# partition. Setting this to more than one will cause
+# additional conductor services to prepare deployment
+# environments and potentially allow the Ironic cluster to
+# recover more quickly if a conductor instance is terminated.
+# (integer value)
+#hash_distribution_replicas = 1
+
+# Interval (in seconds) between hash ring resets. (integer
+# value)
+#hash_ring_reset_interval = 180
+
+# If True, convert backing images to "raw" disk image format.
+# (boolean value)
+#force_raw_images = true
+
+# Path to isolinux binary file. (string value)
+#isolinux_bin = /usr/lib/syslinux/isolinux.bin
+
+# Template file for isolinux configuration file. (string
+# value)
+#isolinux_config_template = $pybasedir/common/isolinux_common.template
+
+# Template file for grub configuration file. (string value)
+#grub_config_template = $pybasedir/common/grub_conf.template
+
+# Run image downloads and raw format conversions in parallel.
+# (boolean value)
+#parallel_image_downloads = false
+
+# IP address of this host. If unset, will determine the IP
+# programmatically. If unable to do so, will use "127.0.0.1".
+# (string value)
+#my_ip = 127.0.0.1
+
+# Specifies the minimum level for which to send notifications.
+# If not set, no notifications will be sent. The default is
+# for this option to be unset. (string value)
+# Allowed values: debug, info, warning, error, critical
+#notification_level = <None>
+
+# Directory where the ironic python module is installed.
+# (string value)
+#pybasedir = /usr/lib/python/site-packages/ironic/ironic
+
+# Directory where ironic binaries are installed. (string
+# value)
+#bindir = $pybasedir/bin
+
+# Top-level directory for maintaining ironic's state. (string
+# value)
+#state_path = $pybasedir
+
+# Default mode for portgroups. Allowed values can be found in
+# the linux kernel documentation on bonding:
+# https://www.kernel.org/doc/Documentation/networking/bonding.txt.
+# (string value)
+#default_portgroup_mode = active-backup
+
+# Name of this node. This can be an opaque identifier. It is
+# not necessarily a hostname, FQDN, or IP address. However,
+# the node name must be valid within an AMQP key, and if using
+# ZeroMQ, a valid hostname, FQDN, or IP address. (string
+# value)
+# host = localhost
+
+# Path to the rootwrap configuration file to use for running
+# commands as root. (string value)
+#rootwrap_config = /etc/ironic/rootwrap.conf
+
+# Temporary working directory, default is Python temp dir.
+# (string value)
+#tempdir = /tmp
+
+#
+# From oslo.log
+#
+
+# If set to true, the logging level will be set to DEBUG
+# instead of the default INFO level. (boolean value)
+# Note: This option can be changed without restarting.
+{%- if ironic.logging is defined and ironic.debug is defined %}
+debug = {{ ironic.logging.debug }}
+{%- else %}
+#debug = false
+{%- endif %}
+
+# The name of a logging configuration file. This file is
+# appended to any existing logging configuration files. For
+# details about logging configuration files, see the Python
+# logging module documentation. Note that when logging
+# configuration files are used then all logging configuration
+# is set in the configuration file and other logging
+# configuration options are ignored (for example,
+# logging_context_format_string). (string value)
+# Note: This option can be changed without restarting.
+# Deprecated group/name - [DEFAULT]/log_config
+#log_config_append = <None>
+
+# Defines the format string for %%(asctime)s in log records.
+# Default: %(default)s . This option is ignored if
+# log_config_append is set. (string value)
+#log_date_format = %Y-%m-%d %H:%M:%S
+
+# (Optional) Name of log file to send logging output to. If no
+# default is set, logging will go to stderr as defined by
+# use_stderr. This option is ignored if log_config_append is
+# set. (string value)
+# Deprecated group/name - [DEFAULT]/logfile
+#log_file = <None>
+
+# (Optional) The base directory used for relative log_file
+# paths. This option is ignored if log_config_append is set.
+# (string value)
+# Deprecated group/name - [DEFAULT]/logdir
+#log_dir = <None>
+
+# Uses logging handler designed to watch file system. When log
+# file is moved or removed this handler will open a new log
+# file with specified path instantaneously. It makes sense
+# only if log_file option is specified and Linux platform is
+# used. This option is ignored if log_config_append is set.
+# (boolean value)
+#watch_log_file = false
+
+# Use syslog for logging. Existing syslog format is DEPRECATED
+# and will be changed later to honor RFC5424. This option is
+# ignored if log_config_append is set. (boolean value)
+#use_syslog = false
+
+# Syslog facility to receive log lines. This option is ignored
+# if log_config_append is set. (string value)
+#syslog_log_facility = LOG_USER
+
+# Log output to standard error. This option is ignored if
+# log_config_append is set. (boolean value)
+#use_stderr = false
+
+# Format string to use for log messages with context. (string
+# value)
+#logging_context_format_string = %(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [%(request_id)s %(user_identity)s] %(instance)s%(message)s
+
+# Format string to use for log messages when context is
+# undefined. (string value)
+#logging_default_format_string = %(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [-] %(instance)s%(message)s
+
+# Additional data to append to log message when logging level
+# for the message is DEBUG. (string value)
+#logging_debug_format_suffix = %(funcName)s %(pathname)s:%(lineno)d
+
+# Prefix each line of exception output with this format.
+# (string value)
+#logging_exception_prefix = %(asctime)s.%(msecs)03d %(process)d ERROR %(name)s %(instance)s
+
+# Defines the format string for %(user_identity)s that is used
+# in logging_context_format_string. (string value)
+#logging_user_identity_format = %(user)s %(tenant)s %(domain)s %(user_domain)s %(project_domain)s
+
+# List of package logging levels in logger=LEVEL pairs. This
+# option is ignored if log_config_append is set. (list value)
+#default_log_levels = amqp=WARN,amqplib=WARN,boto=WARN,qpid=WARN,sqlalchemy=WARN,suds=INFO,oslo.messaging=INFO,iso8601=WARN,requests.packages.urllib3.connectionpool=WARN,urllib3.connectionpool=WARN,websocket=WARN,requests.packages.urllib3.util.retry=WARN,urllib3.util.retry=WARN,keystonemiddleware=WARN,routes.middleware=WARN,stevedore=WARN,taskflow=WARN,keystoneauth=WARN,oslo.cache=INFO,dogpile.core.dogpile=INFO
+
+# Enables or disables publication of error events. (boolean
+# value)
+#publish_errors = false
+
+# The format for an instance that is passed with the log
+# message. (string value)
+#instance_format = "[instance: %(uuid)s] "
+
+# The format for an instance UUID that is passed with the log
+# message. (string value)
+#instance_uuid_format = "[instance: %(uuid)s] "
+
+# Interval, number of seconds, of log rate limiting. (integer
+# value)
+#rate_limit_interval = 0
+
+# Maximum number of logged messages per rate_limit_interval.
+# (integer value)
+#rate_limit_burst = 0
+
+# Log level name used by rate limiting: CRITICAL, ERROR, INFO,
+# WARNING, DEBUG or empty string. Logs with level greater or
+# equal to rate_limit_except_level are not filtered. An empty
+# string means that all levels are filtered. (string value)
+#rate_limit_except_level = CRITICAL
+
+# Enables or disables fatal status of deprecations. (boolean
+# value)
+#fatal_deprecations = false
+
+#
+# From oslo.messaging
+#
+
+# Size of RPC connection pool. (integer value)
+# Deprecated group/name - [DEFAULT]/rpc_conn_pool_size
+#rpc_conn_pool_size = 30
+
+# The pool size limit for connections expiration policy
+# (integer value)
+#conn_pool_min_size = 2
+
+# The time-to-live in sec of idle connections in the pool
+# (integer value)
+#conn_pool_ttl = 1200
+
+# ZeroMQ bind address. Should be a wildcard (*), an ethernet
+# interface, or IP. The "host" option should point or resolve
+# to this address. (string value)
+# Deprecated group/name - [DEFAULT]/rpc_zmq_bind_address
+#rpc_zmq_bind_address = *
+
+# MatchMaker driver. (string value)
+# Allowed values: redis, sentinel, dummy
+# Deprecated group/name - [DEFAULT]/rpc_zmq_matchmaker
+#rpc_zmq_matchmaker = redis
+
+# Number of ZeroMQ contexts, defaults to 1. (integer value)
+# Deprecated group/name - [DEFAULT]/rpc_zmq_contexts
+#rpc_zmq_contexts = 1
+
+# Maximum number of ingress messages to locally buffer per
+# topic. Default is unlimited. (integer value)
+# Deprecated group/name - [DEFAULT]/rpc_zmq_topic_backlog
+#rpc_zmq_topic_backlog = <None>
+
+# Directory for holding IPC sockets. (string value)
+# Deprecated group/name - [DEFAULT]/rpc_zmq_ipc_dir
+#rpc_zmq_ipc_dir = /var/run/openstack
+
+# Name of this node. Must be a valid hostname, FQDN, or IP
+# address. Must match "host" option, if running Nova. (string
+# value)
+# Deprecated group/name - [DEFAULT]/rpc_zmq_host
+#rpc_zmq_host = localhost
+
+# Number of seconds to wait before all pending messages will
+# be sent after closing a socket. The default value of -1
+# specifies an infinite linger period. The value of 0
+# specifies no linger period. Pending messages shall be
+# discarded immediately when the socket is closed. Positive
+# values specify an upper bound for the linger period.
+# (integer value)
+# Deprecated group/name - [DEFAULT]/rpc_cast_timeout
+#zmq_linger = -1
+
+# The default number of seconds that poll should wait. Poll
+# raises timeout exception when timeout expired. (integer
+# value)
+# Deprecated group/name - [DEFAULT]/rpc_poll_timeout
+#rpc_poll_timeout = 1
+
+# Expiration timeout in seconds of a name service record about
+# existing target ( < 0 means no timeout). (integer value)
+# Deprecated group/name - [DEFAULT]/zmq_target_expire
+#zmq_target_expire = 300
+
+# Update period in seconds of a name service record about
+# existing target. (integer value)
+# Deprecated group/name - [DEFAULT]/zmq_target_update
+#zmq_target_update = 180
+
+# Use PUB/SUB pattern for fanout methods. PUB/SUB always uses
+# proxy. (boolean value)
+# Deprecated group/name - [DEFAULT]/use_pub_sub
+#use_pub_sub = false
+
+# Use ROUTER remote proxy. (boolean value)
+# Deprecated group/name - [DEFAULT]/use_router_proxy
+#use_router_proxy = false
+
+# This option makes direct connections dynamic or static. It
+# makes sense only with use_router_proxy=False which means to
+# use direct connections for direct message types (ignored
+# otherwise). (boolean value)
+#use_dynamic_connections = false
+
+# How many additional connections to a host will be made for
+# failover reasons. This option is actual only in dynamic
+# connections mode. (integer value)
+#zmq_failover_connections = 2
+
+# Minimal port number for random ports range. (port value)
+# Minimum value: 0
+# Maximum value: 65535
+# Deprecated group/name - [DEFAULT]/rpc_zmq_min_port
+#rpc_zmq_min_port = 49153
+
+# Maximal port number for random ports range. (integer value)
+# Minimum value: 1
+# Maximum value: 65536
+# Deprecated group/name - [DEFAULT]/rpc_zmq_max_port
+#rpc_zmq_max_port = 65536
+
+# Number of retries to find free port number before fail with
+# ZMQBindError. (integer value)
+# Deprecated group/name - [DEFAULT]/rpc_zmq_bind_port_retries
+#rpc_zmq_bind_port_retries = 100
+
+# Default serialization mechanism for
+# serializing/deserializing outgoing/incoming messages (string
+# value)
+# Allowed values: json, msgpack
+# Deprecated group/name - [DEFAULT]/rpc_zmq_serialization
+#rpc_zmq_serialization = json
+
+# This option configures round-robin mode in zmq socket. True
+# means not keeping a queue when server side disconnects.
+# False means to keep queue and messages even if server is
+# disconnected, when the server appears we send all
+# accumulated messages to it. (boolean value)
+#zmq_immediate = true
+
+# Enable/disable TCP keepalive (KA) mechanism. The default
+# value of -1 (or any other negative value) means to skip any
+# overrides and leave it to OS default; 0 and 1 (or any other
+# positive value) mean to disable and enable the option
+# respectively. (integer value)
+#zmq_tcp_keepalive = -1
+
+# The duration between two keepalive transmissions in idle
+# condition. The unit is platform dependent, for example,
+# seconds in Linux, milliseconds in Windows etc. The default
+# value of -1 (or any other negative value and 0) means to
+# skip any overrides and leave it to OS default. (integer
+# value)
+#zmq_tcp_keepalive_idle = -1
+
+# The number of retransmissions to be carried out before
+# declaring that remote end is not available. The default
+# value of -1 (or any other negative value and 0) means to
+# skip any overrides and leave it to OS default. (integer
+# value)
+#zmq_tcp_keepalive_cnt = -1
+
+# The duration between two successive keepalive
+# retransmissions, if acknowledgement to the previous
+# keepalive transmission is not received. The unit is platform
+# dependent, for example, seconds in Linux, milliseconds in
+# Windows etc. The default value of -1 (or any other negative
+# value and 0) means to skip any overrides and leave it to OS
+# default. (integer value)
+#zmq_tcp_keepalive_intvl = -1
+
+# Maximum number of (green) threads to work concurrently.
+# (integer value)
+#rpc_thread_pool_size = 100
+
+# Expiration timeout in seconds of a sent/received message
+# after which it is not tracked anymore by a client/server.
+# (integer value)
+#rpc_message_ttl = 300
+
+# Wait for message acknowledgements from receivers. This
+# mechanism works only via proxy without PUB/SUB. (boolean
+# value)
+#rpc_use_acks = false
+
+# Number of seconds to wait for an ack from a cast/call. After
+# each retry attempt this timeout is multiplied by some
+# specified multiplier. (integer value)
+#rpc_ack_timeout_base = 15
+
+# Number to multiply base ack timeout by after each retry
+# attempt. (integer value)
+#rpc_ack_timeout_multiplier = 2
+
+# Default number of message sending attempts in case of any
+# problems occurred: positive value N means at most N retries,
+# 0 means no retries, None or -1 (or any other negative
+# values) mean to retry forever. This option is used only if
+# acknowledgments are enabled. (integer value)
+#rpc_retry_attempts = 3
+
+# List of publisher hosts SubConsumer can subscribe on. This
+# option has higher priority then the default publishers list
+# taken from the matchmaker. (list value)
+#subscribe_on =
+
+# Size of executor thread pool. (integer value)
+# Deprecated group/name - [DEFAULT]/rpc_thread_pool_size
+#executor_thread_pool_size = 64
+
+# Seconds to wait for a response from a call. (integer value)
+#rpc_response_timeout = 60
+
+# A URL representing the messaging driver to use and its full
+# configuration. (string value)
+{%- set mq = ironic.message_queue %}
+{%- set rmq_port = mq.get('port', 5672) %}
+{%- if mq.members is defined %}
+transport_url = rabbit://{% for member in mq.members -%}
+                         {{ mq.user }}:{{ mq.password }}@{{ member.host }}:{{ member.get('port', rmq_port) }}
+                         {%- if not loop.last -%},{%- endif -%}
+                         {%- endfor -%}/{{ mq.virtual_host }}
+{%- else %}
+transport_url = rabbit://{{ mq.user }}:{{ mq.password }}@{{ mq.host }}:{{ rmq_port }}/{{ mq.virtual_host }}
+{%- endif %}
+
+# The default exchange under which topics are scoped. May be
+# overridden by an exchange name specified in the
+# transport_url option. (string value)
+#control_exchange = openstack
+
+#
+# From oslo.service.periodic_task
+#
+
+# Some periodic tasks can be run in a separate process. Should
+# we run them here? (boolean value)
+#run_external_periodic_tasks = true
+
+#
+# From oslo.service.service
+#
+
+# Enable eventlet backdoor. Acceptable values are 0, <port>,
+# and <start>:<end>, where 0 results in listening on a random
+# tcp port number; <port> results in listening on the
+# specified port number (and not enabling backdoor if that
+# port is in use); and <start>:<end> results in listening on
+# the smallest unused port number within the specified range
+# of port numbers. The chosen port is displayed in the
+# service's log file. (string value)
+#backdoor_port = <None>
+
+# Enable eventlet backdoor, using the provided path as a unix
+# socket that can receive connections. This option is mutually
+# exclusive with 'backdoor_port' in that only one should be
+# provided. If both are provided then the existence of this
+# option overrides the usage of that option. (string value)
+#backdoor_socket = <None>
+
+# Enables or disables logging values of all registered options
+# when starting a service (at DEBUG level). (boolean value)
+#log_options = true
+
+# Specify a timeout after which a gracefully shutdown server
+# will exit. Zero value means endless wait. (integer value)
+#graceful_shutdown_timeout = 60
+
+
+[agent]
+
+#
+# From ironic
+#
+
+# Whether Ironic will manage booting of the agent ramdisk. If
+# set to False, you will need to configure your mechanism to
+# allow booting the agent ramdisk. (boolean value)
+#manage_agent_boot = true
+
+# The memory size in MiB consumed by agent when it is booted
+# on a bare metal node. This is used for checking if the image
+# can be downloaded and deployed on the bare metal node after
+# booting agent ramdisk. This may be set according to the
+# memory consumed by the agent ramdisk image. (integer value)
+#memory_consumed_by_agent = 0
+
+# Whether the agent ramdisk should stream raw images directly
+# onto the disk or not. By streaming raw images directly onto
+# the disk the agent ramdisk will not spend time copying the
+# image to a tmpfs partition (therefore consuming less memory)
+# prior to writing it to the disk. Unless the disk where the
+# image will be copied to is really slow, this option should
+# be set to True. Defaults to True. (boolean value)
+#stream_raw_images = true
+
+# Number of times to retry getting power state to check if
+# bare metal node has been powered off after a soft power off.
+# (integer value)
+#post_deploy_get_power_state_retries = 6
+
+# Amount of time (in seconds) to wait between polling power
+# state after trigger soft poweroff. (integer value)
+#post_deploy_get_power_state_retry_interval = 5
+
+# API version to use for communicating with the ramdisk agent.
+# (string value)
+#agent_api_version = v1
+
+# Whether Ironic should collect the deployment logs on
+# deployment failure (on_failure), always or never. (string
+# value)
+# Allowed values: always, on_failure, never
+#deploy_logs_collect = on_failure
+
+# The name of the storage backend where the logs will be
+# stored. (string value)
+# Allowed values: local, swift
+#deploy_logs_storage_backend = local
+
+# The path to the directory where the logs should be stored,
+# used when the deploy_logs_storage_backend is configured to
+# "local". (string value)
+#deploy_logs_local_path = /var/log/ironic/deploy
+
+# The name of the Swift container to store the logs, used when
+# the deploy_logs_storage_backend is configured to "swift".
+# (string value)
+#deploy_logs_swift_container = ironic_deploy_logs_container
+
+# Number of days before a log object is marked as expired in
+# Swift. If None, the logs will be kept forever or until
+# manually deleted. Used when the deploy_logs_storage_backend
+# is configured to "swift". (integer value)
+#deploy_logs_swift_days_to_expire = 30
+
+
+[api]
+
+#
+# From ironic
+#
+
+# The IP address on which ironic-api listens. (string value)
+{%- if api.get('bind', {}).get('address') %}
+host_ip = {{ api.bind.address }}
+{%- else %}
+#host_ip = 0.0.0.0
+{%- endif %}
+
+# The TCP port on which ironic-api listens. (port value)
+# Minimum value: 0
+# Maximum value: 65535
+{%- if api.get('bind', {}).get('port') %}
+port = {{ api.bind.port }}
+{%- else %}
+#port = 6385
+{%- endif %}
+
+# The maximum number of items returned in a single response
+# from a collection resource. (integer value)
+#max_limit = 1000
+
+# Public URL to use when building the links to the API
+# resources (for example, "https://ironic.rocks:6384"). If
+# None the links will be built using the request's host URL.
+# If the API is operating behind a proxy, you will want to
+# change this to represent the proxy's URL. Defaults to None.
+# (string value)
+#public_endpoint = <None>
+
+# Number of workers for OpenStack Ironic API service. The
+# default is equal to the number of CPUs available if that can
+# be determined, else a default worker count of 1 is returned.
+# (integer value)
+#api_workers = <None>
+
+# Enable the integrated stand-alone API to service requests
+# via HTTPS instead of HTTP. If there is a front-end service
+# performing HTTPS offloading from the service, this option
+# should be False; note, you will want to change public API
+# endpoint to represent SSL termination URL with
+# 'public_endpoint' option. (boolean value)
+#enable_ssl_api = false
+
+# Whether to restrict the lookup API to only nodes in certain
+# states. (boolean value)
+#restrict_lookup = true
+
+# Maximum interval (in seconds) for agent heartbeats. (integer
+# value)
+# Deprecated group/name - [agent]/heartbeat_timeout
+#ramdisk_heartbeat_timeout = 300
+
+
+[audit]
+
+#
+# From ironic
+#
+
+# Enable auditing of API requests (for ironic-api service).
+# (boolean value)
+#enabled = false
+
+# Path to audit map file for ironic-api service. Used only
+# when API audit is enabled. (string value)
+#audit_map_file = /etc/ironic/api_audit_map.conf
+
+# Comma separated list of Ironic REST API HTTP methods to be
+# ignored during audit logging. For example: auditing will not
+# be done on any GET or POST requests if this is set to
+# "GET,POST". It is used only when API audit is enabled.
+# (string value)
+#ignore_req_list =
+
+
+[cimc]
+
+#
+# From ironic
+#
+
+# Number of times a power operation needs to be retried
+# (integer value)
+#max_retry = 6
+
+# Amount of time in seconds to wait in between power
+# operations (integer value)
+#action_interval = 10
+
+
+[cisco_ucs]
+
+#
+# From ironic
+#
+
+# Number of times a power operation needs to be retried
+# (integer value)
+#max_retry = 6
+
+# Amount of time in seconds to wait in between power
+# operations (integer value)
+#action_interval = 5
+
+
+[conductor]
+
+#
+# From ironic
+#
+
+# The size of the workers greenthread pool. Note that 2
+# threads will be reserved by the conductor itself for
+# handling heart beats and periodic tasks. (integer value)
+# Minimum value: 3
+#workers_pool_size = 100
+
+# Seconds between conductor heart beats. (integer value)
+#heartbeat_interval = 10
+
+# URL of Ironic API service. If not set ironic can get the
+# current value from the keystone service catalog. If set, the
+# value must start with either http:// or https://. (string
+# value)
+{%- if conductor.get('api_url') %}
+api_url = {{ conductor.api_url }}
+{%- else %}
+#api_url = <None>
+{%- endif %}
+
+# Maximum time (in seconds) since the last check-in of a
+# conductor. A conductor is considered inactive when this time
+# has been exceeded. (integer value)
+#heartbeat_timeout = 60
+
+# Interval between syncing the node power state to the
+# database, in seconds. (integer value)
+#sync_power_state_interval = 60
+
+# Interval between checks of provision timeouts, in seconds.
+# (integer value)
+#check_provision_state_interval = 60
+
+# Timeout (seconds) to wait for a callback from a deploy
+# ramdisk. Set to 0 to disable timeout. (integer value)
+#deploy_callback_timeout = 1800
+
+# During sync_power_state, should the hardware power state be
+# set to the state recorded in the database (True) or should
+# the database be updated based on the hardware state (False).
+# (boolean value)
+#force_power_state_during_sync = true
+
+# During sync_power_state failures, limit the number of times
+# Ironic should try syncing the hardware node power state with
+# the node power state in DB (integer value)
+#power_state_sync_max_retries = 3
+
+# Maximum number of worker threads that can be started
+# simultaneously by a periodic task. Should be less than RPC
+# thread pool size. (integer value)
+#periodic_max_workers = 8
+
+# Number of attempts to grab a node lock. (integer value)
+#node_locked_retry_attempts = 3
+
+# Seconds to sleep between node lock attempts. (integer value)
+#node_locked_retry_interval = 1
+
+# Enable sending sensor data message via the notification bus
+# (boolean value)
+#send_sensor_data = false
+
+# Seconds between conductor sending sensor data message to
+# ceilometer via the notification bus. (integer value)
+#send_sensor_data_interval = 600
+
+# The maximum number of workers that can be started
+# simultaneously for send data from sensors periodic task.
+# (integer value)
+# Minimum value: 1
+#send_sensor_data_workers = 4
+
+# The time in seconds to wait for send sensors data periodic
+# task to be finished before allowing periodic call to happen
+# again. Should be less than send_sensor_data_interval value.
+# (integer value)
+#send_sensor_data_wait_timeout = 300
+
+# List of comma separated meter types which need to be sent to
+# Ceilometer. The default value, "ALL", is a special value
+# meaning send all the sensor data. (list value)
+#send_sensor_data_types = ALL
+
+# When conductors join or leave the cluster, existing
+# conductors may need to update any persistent local state as
+# nodes are moved around the cluster. This option controls how
+# often, in seconds, each conductor will check for nodes that
+# it should "take over". Set it to a negative value to disable
+# the check entirely. (integer value)
+#sync_local_state_interval = 180
+
+# Whether to upload the config drive to Swift. (boolean value)
+#configdrive_use_swift = false
+
+# Name of the Swift container to store config drive data. Used
+# when configdrive_use_swift is True. (string value)
+#configdrive_swift_container = ironic_configdrive_container
+
+# Timeout (seconds) for waiting for node inspection. 0 -
+# unlimited. (integer value)
+#inspect_timeout = 1800
+
+# Enables or disables automated cleaning. Automated cleaning
+# is a configurable set of steps, such as erasing disk drives,
+# that are performed on the node to ensure it is in a baseline
+# state and ready to be deployed to. This is done after
+# instance deletion as well as during the transition from a
+# "manageable" to "available" state. When enabled, the
+# particular steps performed to clean a node depend on which
+# driver that node is managed by; see the individual driver's
+# documentation for details. NOTE: The introduction of the
+# cleaning operation causes instance deletion to take
+# significantly longer. In an environment where all tenants
+# are trusted (eg, because there is only one tenant), this
+# option could be safely disabled. (boolean value)
+{%- if conductor.automated_clean is defined %}
+automated_clean = {{ conductor.automated_clean }}
+{%- else %}
+#automated_clean = true
+{%- endif %}
+
+# Timeout (seconds) to wait for a callback from the ramdisk
+# doing the cleaning. If the timeout is reached the node will
+# be put in the "clean failed" provision state. Set to 0 to
+# disable timeout. (integer value)
+#clean_callback_timeout = 1800
+
+# Timeout (in seconds) of soft reboot and soft power off
+# operation. This value always has to be positive. (integer
+# value)
+# Minimum value: 1
+#soft_power_off_timeout = 600
+
+
+[console]
+
+#
+# From ironic
+#
+
+# Path to serial console terminal program. Used only by Shell
+# In A Box console. (string value)
+#terminal = shellinaboxd
+
+# Directory containing the terminal SSL cert (PEM) for serial
+# console access. Used only by Shell In A Box console. (string
+# value)
+#terminal_cert_dir = <None>
+
+# Directory for holding terminal pid files. If not specified,
+# the temporary directory will be used. (string value)
+#terminal_pid_dir = <None>
+
+# Time interval (in seconds) for checking the status of
+# console subprocess. (integer value)
+#subprocess_checking_interval = 1
+
+# Time (in seconds) to wait for the console subprocess to
+# start. (integer value)
+#subprocess_timeout = 10
+
+
+[cors]
+
+#
+# From oslo.middleware.cors
+#
+
+# Indicate whether this resource may be shared with the domain
+# received in the requests "origin" header. Format:
+# "<protocol>://<host>[:<port>]", no trailing slash. Example:
+# https://horizon.example.com (list value)
+#allowed_origin = <None>
+
+# Indicate that the actual request can include user
+# credentials (boolean value)
+#allow_credentials = true
+
+# Indicate which headers are safe to expose to the API.
+# Defaults to HTTP Simple Headers. (list value)
+#expose_headers =
+
+# Maximum cache age of CORS preflight requests. (integer
+# value)
+#max_age = 3600
+
+# Indicate which methods can be used during the actual
+# request. (list value)
+#allow_methods = OPTIONS,GET,HEAD,POST,PUT,DELETE,TRACE,PATCH
+
+# Indicate which header field names may be used during the
+# actual request. (list value)
+#allow_headers =
+
+
+[database]
+
+#
+# From ironic
+#
+
+# MySQL engine to use. (string value)
+#mysql_engine = InnoDB
+
+#
+# From oslo.db
+#
+
+# DEPRECATED: The file name to use with SQLite. (string value)
+# Deprecated group/name - [DEFAULT]/sqlite_db
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Should use config option connection or
+# slave_connection to connect the database.
+#sqlite_db = oslo.sqlite
+
+# If True, SQLite uses synchronous mode. (boolean value)
+# Deprecated group/name - [DEFAULT]/sqlite_synchronous
+#sqlite_synchronous = true
+
+# The back end to use for the database. (string value)
+# Deprecated group/name - [DEFAULT]/db_backend
+#backend = sqlalchemy
+
+# The SQLAlchemy connection string to use to connect to the
+# database. (string value)
+# Deprecated group/name - [DEFAULT]/sql_connection
+# Deprecated group/name - [DATABASE]/sql_connection
+# Deprecated group/name - [sql]/connection
+connection = {{ ironic.database.engine }}+pymysql://{{ ironic.database.user }}:{{ ironic.database.password }}@{{ ironic.database.host }}/{{ ironic.database.name }}?charset=utf8
+
+# The SQLAlchemy connection string to use to connect to the
+# slave database. (string value)
+#slave_connection = <None>
+
+# The SQL mode to be used for MySQL sessions. This option,
+# including the default, overrides any server-set SQL mode. To
+# use whatever SQL mode is set by the server configuration,
+# set this to no value. Example: mysql_sql_mode= (string
+# value)
+#mysql_sql_mode = TRADITIONAL
+
+# Timeout before idle SQL connections are reaped. (integer
+# value)
+# Deprecated group/name - [DEFAULT]/sql_idle_timeout
+# Deprecated group/name - [DATABASE]/sql_idle_timeout
+# Deprecated group/name - [sql]/idle_timeout
+#idle_timeout = 3600
+
+# Minimum number of SQL connections to keep open in a pool.
+# (integer value)
+# Deprecated group/name - [DEFAULT]/sql_min_pool_size
+# Deprecated group/name - [DATABASE]/sql_min_pool_size
+#min_pool_size = 1
+
+# Maximum number of SQL connections to keep open in a pool.
+# Setting a value of 0 indicates no limit. (integer value)
+# Deprecated group/name - [DEFAULT]/sql_max_pool_size
+# Deprecated group/name - [DATABASE]/sql_max_pool_size
+#max_pool_size = 5
+
+# Maximum number of database connection retries during
+# startup. Set to -1 to specify an infinite retry count.
+# (integer value)
+# Deprecated group/name - [DEFAULT]/sql_max_retries
+# Deprecated group/name - [DATABASE]/sql_max_retries
+#max_retries = 10
+
+# Interval between retries of opening a SQL connection.
+# (integer value)
+# Deprecated group/name - [DEFAULT]/sql_retry_interval
+# Deprecated group/name - [DATABASE]/reconnect_interval
+#retry_interval = 10
+
+# If set, use this value for max_overflow with SQLAlchemy.
+# (integer value)
+# Deprecated group/name - [DEFAULT]/sql_max_overflow
+# Deprecated group/name - [DATABASE]/sqlalchemy_max_overflow
+#max_overflow = 50
+
+# Verbosity of SQL debugging information: 0=None,
+# 100=Everything. (integer value)
+# Minimum value: 0
+# Maximum value: 100
+# Deprecated group/name - [DEFAULT]/sql_connection_debug
+#connection_debug = 0
+
+# Add Python stack traces to SQL as comment strings. (boolean
+# value)
+# Deprecated group/name - [DEFAULT]/sql_connection_trace
+#connection_trace = false
+
+# If set, use this value for pool_timeout with SQLAlchemy.
+# (integer value)
+# Deprecated group/name - [DATABASE]/sqlalchemy_pool_timeout
+#pool_timeout = <None>
+
+# Enable the experimental use of database reconnect on
+# connection lost. (boolean value)
+#use_db_reconnect = false
+
+# Seconds between retries of a database transaction. (integer
+# value)
+#db_retry_interval = 1
+
+# If True, increases the interval between retries of a
+# database operation up to db_max_retry_interval. (boolean
+# value)
+#db_inc_retry_interval = true
+
+# If db_inc_retry_interval is set, the maximum seconds between
+# retries of a database operation. (integer value)
+#db_max_retry_interval = 10
+
+# Maximum retries in case of connection error or deadlock
+# error before error is raised. Set to -1 to specify an
+# infinite retry count. (integer value)
+#db_max_retries = 20
+
+
+[deploy]
+
+#
+# From ironic
+#
+
+# ironic-conductor node's HTTP server URL. Example:
+# http://192.1.2.3:8080 (string value)
+{%- if conductor.get('http_url') %}
+http_url = {{ conductor.http_url }}
+{%- else %}
+#http_url = <None>
+{%- endif %}
+
+# ironic-conductor node's HTTP root path. (string value)
+{%- if conductor.get('http_root') %}
+http_root = {{ conductor.http_root }}
+{%- else %}
+#http_root = /httpboot
+{%- endif %}
+
+# Priority to run in-band erase devices via the Ironic Python
+# Agent ramdisk. If unset, will use the priority set in the
+# ramdisk (defaults to 10 for the GenericHardwareManager). If
+# set to 0, will not run during cleaning. (integer value)
+#erase_devices_priority = <None>
+
+# Priority to run in-band clean step that erases metadata from
+# devices, via the Ironic Python Agent ramdisk. If unset, will
+# use the priority set in the ramdisk (defaults to 99 for the
+# GenericHardwareManager). If set to 0, will not run during
+# cleaning. (integer value)
+#erase_devices_metadata_priority = <None>
+
+# During shred, overwrite all block devices N times with
+# random data. This is only used if a device could not be ATA
+# Secure Erased. Defaults to 1. (integer value)
+# Minimum value: 0
+#shred_random_overwrite_iterations = 1
+
+# Whether to write zeros to a node's block devices after
+# writing random data. This will write zeros to the device
+# even when deploy.shred_random_overwrite_iterations is 0.
+# This option is only used if a device could not be ATA Secure
+# Erased. Defaults to True. (boolean value)
+#shred_final_overwrite_with_zeros = true
+
+# Defines what to do if an ATA secure erase operation fails
+# during cleaning in the Ironic Python Agent. If False, the
+# cleaning operation will fail and the node will be put in
+# ``clean failed`` state. If True, shred will be invoked and
+# cleaning will continue. (boolean value)
+#continue_if_disk_secure_erase_fails = false
+
+# Whether to power off a node after deploy failure. Defaults
+# to True. (boolean value)
+#power_off_after_deploy_failure = true
+
+# Default boot option to use when no boot option is requested
+# in node's driver_info. Currently the default is "netboot",
+# but it will be changed to "local" in the future. It is
+# recommended to set an explicit value for this option.
+# (string value)
+# Allowed values: netboot, local
+#default_boot_option = <None>
+
+
+[dhcp]
+
+#
+# From ironic
+#
+
+# DHCP provider to use. "neutron" uses Neutron, and "none"
+# uses a no-op provider. (string value)
+{%- if conductor.get('dhcp', {}).get('provider') %}
+dhcp_provider = {{ conductor.dhcp.provider }}
+{%- else %}
+#dhcp_provider = neutron
+{%- endif %}
+
+
+[disk_partitioner]
+
+#
+# From ironic_lib.disk_partitioner
+#
+
+# After Ironic has completed creating the partition table, it
+# continues to check for activity on the attached iSCSI device
+# status at this interval prior to copying the image to the
+# node, in seconds (integer value)
+#check_device_interval = 1
+
+# The maximum number of times to check that the device is not
+# accessed by another process. If the device is still busy
+# after that, the disk partitioning will be treated as having
+# failed. (integer value)
+#check_device_max_retries = 20
+
+
+[disk_utils]
+
+#
+# From ironic_lib.disk_utils
+#
+
+# Size of EFI system partition in MiB when configuring UEFI
+# systems for local boot. (integer value)
+#efi_system_partition_size = 200
+
+# Size of BIOS Boot partition in MiB when configuring GPT
+# partitioned systems for local boot in BIOS. (integer value)
+#bios_boot_partition_size = 1
+
+# Block size to use when writing to the nodes disk. (string
+# value)
+#dd_block_size = 1M
+
+# Maximum attempts to verify an iSCSI connection is active,
+# sleeping 1 second between attempts. (integer value)
+#iscsi_verify_attempts = 3
+
+
+[drac]
+
+#
+# From ironic
+#
+
+# Interval (in seconds) between periodic RAID job status
+# checks to determine whether the asynchronous RAID
+# configuration was successfully finished or not. (integer
+# value)
+#query_raid_config_job_status_interval = 120
+
+
+[glance]
+
+#
+# From ironic
+#
+
+# A list of URL schemes that can be downloaded directly via
+# the direct_url. Currently supported schemes: [file]. (list
+# value)
+#allowed_direct_url_schemes =
+
+# Authentication URL (string value)
+#auth_url = <None>
+
+# Authentication strategy to use when connecting to glance.
+# (string value)
+# Allowed values: keystone, noauth
+{%- if conductor.get('glance', {}).get('auth_strategy') %}
+auth_strategy = {{ conductor.glance.auth_strategy }}
+{%- else %}
+#auth_strategy = keystone
+{%- endif %}
+
+# Authentication type to load (string value)
+# Deprecated group/name - [glance]/auth_plugin
+{%- if conductor.get('glance', {}).get('auth_type') %}
+auth_type = {{ conductor.glance.auth_type }}
+{%- else %}
+#auth_type = <None>
+{%- endif %}
+
+# PEM encoded Certificate Authority to use when verifying
+# HTTPs connections. (string value)
+#cafile = <None>
+
+# PEM encoded client certificate cert file (string value)
+#certfile = <None>
+
+# Optional domain ID to use with v3 and v2 parameters. It will
+# be used for both the user and project domain in v3 and
+# ignored in v2 authentication. (string value)
+#default_domain_id = <None>
+
+# Optional domain name to use with v3 API and v2 parameters.
+# It will be used for both the user and project domain in v3
+# and ignored in v2 authentication. (string value)
+#default_domain_name = <None>
+
+# Domain ID to scope to (string value)
+#domain_id = <None>
+
+# Domain name to scope to (string value)
+#domain_name = <None>
+
+# Allow to perform insecure SSL (https) requests to glance.
+# (boolean value)
+#glance_api_insecure = false
+
+# A list of the glance api servers available to ironic. Prefix
+# with https:// for SSL-based glance API servers. Format is
+# [hostname|IP]:port. (list value)
+#glance_api_servers = <None>
+
+# DEPRECATED: Glance API version (1 or 2) to use. (integer
+# value)
+# Minimum value: 1
+# Maximum value: 2
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Ironic will only support using Glance API version 2
+# in the Queens release.
+#glance_api_version = 2
+
+# Optional path to a CA certificate bundle to be used to
+# validate the SSL certificate served by glance. It is used
+# when glance_api_insecure is set to False. (string value)
+#glance_cafile = <None>
+
+# Default glance hostname or IP address. (string value)
+{%- if conductor.get('glance', {}).get('host') %}
+glance_host = {{ conductor.glance.host }}
+{%- else %}
+#glance_host = $my_ip
+{%- endif %}
+
+# Number of retries when downloading an image from glance.
+# (integer value)
+#glance_num_retries = 0
+
+# Default glance port. (port value)
+# Minimum value: 0
+# Maximum value: 65535
+{%- if conductor.get('glance', {}).get('port') %}
+glance_port = {{ conductor.glance.port }}
+{%- else %}
+#glance_port = 9292
+{%- endif %}
+
+# Default protocol to use when connecting to glance. Set to
+# https for SSL. (string value)
+# Allowed values: http, https
+{%- if conductor.get('glance', {}).get('protocol') %}
+glance_protocol = {{ conductor.glance.protocol }}
+{%- else %}
+#glance_protocol = http
+{%- endif %}
+
+# Verify HTTPS connections. (boolean value)
+#insecure = false
+
+# PEM encoded client certificate key file (string value)
+#keyfile = <None>
+
+# User's password (string value)
+{%- if conductor.get('glance', {}).get('password') %}
+password = {{ conductor.glance.password }}
+{%- else %}
+#password = <None>
+{%- endif %}
+
+# Domain ID containing project (string value)
+{%- if conductor.get('glance', {}).get('project_domain_id') %}
+project_domain_id = {{ conductor.glance.project_domain_id }}
+{%- else %}
+#project_domain_id = <None>
+{%- endif %}
+
+# Domain name containing project (string value)
+{%- if conductor.get('glance', {}).get('project_domain_name') %}
+project_domain_name = {{ conductor.glance.project_domain_name }}
+{%- else %}
+#project_domain_name = <None>
+{%- endif %}
+
+# Project ID to scope to (string value)
+# Deprecated group/name - [glance]/tenant-id
+{%- if conductor.get('glance', {}).get('project_id') %}
+project_id = {{ conductor.glance.project_id }}
+{%- else %}
+#project_id = <None>
+{%- endif %}
+
+# Project name to scope to (string value)
+# Deprecated group/name - [glance]/tenant-name
+{%- if conductor.get('glance', {}).get('project_name') %}
+project_name = {{ conductor.glance.project_name }}
+{%- else %}
+#project_name = <None>
+{%- endif %}
+
+# The account that Glance uses to communicate with Swift. The
+# format is "AUTH_uuid". "uuid" is the UUID for the account
+# configured in the glance-api.conf. Required for temporary
+# URLs when Glance backend is Swift. For example:
+# "AUTH_a422b2-91f3-2f46-74b7-d7c9e8958f5d30". Swift temporary
+# URL format:
+# "endpoint_url/api_version/[account/]container/object_id"
+# (string value)
+#swift_account = <None>
+
+# The Swift API version to create a temporary URL for.
+# Defaults to "v1". Swift temporary URL format:
+# "endpoint_url/api_version/[account/]container/object_id"
+# (string value)
+#swift_api_version = v1
+
+# The Swift container Glance is configured to store its images
+# in. Defaults to "glance", which is the default in glance-
+# api.conf. Swift temporary URL format:
+# "endpoint_url/api_version/[account/]container/object_id"
+# (string value)
+#swift_container = glance
+
+# The "endpoint" (scheme, hostname, optional port) for the
+# Swift URL of the form
+# "endpoint_url/api_version/[account/]container/object_id". Do
+# not include trailing "/". For example, use
+# "https://swift.example.com". If using RADOS Gateway,
+# endpoint may also contain /swift path; if it does not, it
+# will be appended. Required for temporary URLs. (string
+# value)
+#swift_endpoint_url = <None>
+
+# This should match a config by the same name in the Glance
+# configuration file. When set to 0, a single-tenant store
+# will only use one container to store all images. When set to
+# an integer value between 1 and 32, a single-tenant store
+# will use multiple containers to store images, and this value
+# will determine how many containers are created. (integer
+# value)
+#swift_store_multiple_containers_seed = 0
+
+# Whether to cache generated Swift temporary URLs. Setting it
+# to true is only useful when an image caching proxy is used.
+# Defaults to False. (boolean value)
+#swift_temp_url_cache_enabled = false
+
+# The length of time in seconds that the temporary URL will be
+# valid for. Defaults to 20 minutes. If some deploys get a 401
+# response code when trying to download from the temporary
+# URL, try raising this duration. This value must be greater
+# than or equal to the value for
+# swift_temp_url_expected_download_start_delay (integer value)
+#swift_temp_url_duration = 1200
+
+# This is the delay (in seconds) from the time of the deploy
+# request (when the Swift temporary URL is generated) to when
+# the IPA ramdisk starts up and URL is used for the image
+# download. This value is used to check if the Swift temporary
+# URL duration is large enough to let the image download
+# begin. Also if temporary URL caching is enabled this will
+# determine if a cached entry will still be valid when the
+# download starts. swift_temp_url_duration value must be
+# greater than or equal to this option's value. Defaults to 0.
+# (integer value)
+# Minimum value: 0
+#swift_temp_url_expected_download_start_delay = 0
+
+# The secret token given to Swift to allow temporary URL
+# downloads. Required for temporary URLs. (string value)
+{%- if conductor.get('glance', {}).get('swift_temp_url_key') %}
+swift_temp_url_key = {{ conductor.glance.swift_temp_url_key }}
+{%- else %}
+#swift_temp_url_key = <None>
+{%- endif %}
+
+# Type of endpoint to use for temporary URLs. If the Glance
+# backend is Swift, use "swift"; if it is CEPH with RADOS
+# gateway, use "radosgw". (string value)
+# Allowed values: swift, radosgw
+#temp_url_endpoint_type = swift
+
+# Tenant ID (string value)
+#tenant_id = <None>
+
+# Tenant Name (string value)
+#tenant_name = <None>
+
+# Timeout value for http requests (integer value)
+#timeout = <None>
+
+# Trust ID (string value)
+#trust_id = <None>
+
+# User's domain id (string value)
+#user_domain_id = <None>
+
+# User's domain name (string value)
+#user_domain_name = <None>
+
+# User id (string value)
+#user_id = <None>
+
+# Username (string value)
+# Deprecated group/name - [glance]/user-name
+#username = <None>
+
+
+[ilo]
+
+#
+# From ironic
+#
+
+# Timeout (in seconds) for iLO operations (integer value)
+#client_timeout = 60
+
+# Port to be used for iLO operations (port value)
+# Minimum value: 0
+# Maximum value: 65535
+#client_port = 443
+
+# The Swift iLO container to store data. (string value)
+#swift_ilo_container = ironic_ilo_container
+
+# Amount of time in seconds for Swift objects to auto-expire.
+# (integer value)
+#swift_object_expiry_timeout = 900
+
+# Set this to True to use http web server to host floppy
+# images and generated boot ISO. This requires http_root and
+# http_url to be configured in the [deploy] section of the
+# config file. If this is set to False, then Ironic will use
+# Swift to host the floppy images and generated boot_iso.
+# (boolean value)
+#use_web_server_for_images = false
+
+# DEPRECATED: Priority for erase devices clean step. If unset,
+# it defaults to 10. If set to 0, the step will be disabled
+# and will not run during cleaning. (integer value)
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: This configuration option is duplicated by [deploy]
+# erase_devices_priority, please use that instead.
+#clean_priority_erase_devices = <None>
+
+# Priority for reset_ilo clean step. (integer value)
+#clean_priority_reset_ilo = 0
+
+# Priority for reset_bios_to_default clean step. (integer
+# value)
+#clean_priority_reset_bios_to_default = 10
+
+# Priority for reset_secure_boot_keys clean step. This step
+# will reset the secure boot keys to manufacturing defaults.
+# (integer value)
+#clean_priority_reset_secure_boot_keys_to_default = 20
+
+# Priority for clear_secure_boot_keys clean step. This step is
+# not enabled by default. It can be enabled to clear all
+# secure boot keys enrolled with iLO. (integer value)
+#clean_priority_clear_secure_boot_keys = 0
+
+# Priority for reset_ilo_credential clean step. This step
+# requires "ilo_change_password" parameter to be updated in
+# nodes's driver_info with the new password. (integer value)
+#clean_priority_reset_ilo_credential = 30
+
+# Number of times a power operation needs to be retried
+# (integer value)
+#power_retry = 6
+
+# Amount of time in seconds to wait in between power
+# operations (integer value)
+#power_wait = 2
+
+# CA certificate file to validate iLO. (string value)
+#ca_file = <None>
+
+# Default boot mode to be used in provisioning when
+# "boot_mode" capability is not provided in the
+# "properties/capabilities" of the node. The default is "auto"
+# for backward compatibility. When "auto" is specified,
+# default boot mode will be selected based on boot mode
+# settings on the system. (string value)
+# Allowed values: auto, bios, uefi
+#default_boot_mode = auto
+
+
+[inspector]
+
+#
+# From ironic
+#
+
+# Authentication URL (string value)
+#auth_url = <None>
+
+# Authentication type to load (string value)
+# Deprecated group/name - [inspector]/auth_plugin
+#auth_type = <None>
+
+# PEM encoded Certificate Authority to use when verifying
+# HTTPs connections. (string value)
+#cafile = <None>
+
+# PEM encoded client certificate cert file (string value)
+#certfile = <None>
+
+# Optional domain ID to use with v3 and v2 parameters. It will
+# be used for both the user and project domain in v3 and
+# ignored in v2 authentication. (string value)
+#default_domain_id = <None>
+
+# Optional domain name to use with v3 API and v2 parameters.
+# It will be used for both the user and project domain in v3
+# and ignored in v2 authentication. (string value)
+#default_domain_name = <None>
+
+# Domain ID to scope to (string value)
+#domain_id = <None>
+
+# Domain name to scope to (string value)
+#domain_name = <None>
+
+# whether to enable inspection using ironic-inspector. This
+# option does not affect new-style dynamic drivers and the
+# fake_inspector driver. (boolean value)
+#enabled = false
+
+# Verify HTTPS connections. (boolean value)
+#insecure = false
+
+# PEM encoded client certificate key file (string value)
+#keyfile = <None>
+
+# User's password (string value)
+#password = <None>
+
+# Domain ID containing project (string value)
+#project_domain_id = <None>
+
+# Domain name containing project (string value)
+#project_domain_name = <None>
+
+# Project ID to scope to (string value)
+# Deprecated group/name - [inspector]/tenant-id
+#project_id = <None>
+
+# Project name to scope to (string value)
+# Deprecated group/name - [inspector]/tenant-name
+#project_name = <None>
+
+# ironic-inspector HTTP endpoint. If this is not set, the
+# service catalog will be used. (string value)
+#service_url = <None>
+
+# period (in seconds) to check status of nodes on inspection
+# (integer value)
+#status_check_period = 60
+
+# Tenant ID (string value)
+#tenant_id = <None>
+
+# Tenant Name (string value)
+#tenant_name = <None>
+
+# Timeout value for http requests (integer value)
+#timeout = <None>
+
+# Trust ID (string value)
+#trust_id = <None>
+
+# User's domain id (string value)
+#user_domain_id = <None>
+
+# User's domain name (string value)
+#user_domain_name = <None>
+
+# User id (string value)
+#user_id = <None>
+
+# Username (string value)
+# Deprecated group/name - [inspector]/user-name
+#username = <None>
+
+
+[ipmi]
+
+#
+# From ironic
+#
+
+# Maximum time in seconds to retry IPMI operations. There is a
+# tradeoff when setting this value. Setting this too low may
+# cause older BMCs to crash and require a hard reset. However,
+# setting too high can cause the sync power state periodic
+# task to hang when there are slow or unresponsive BMCs.
+# (integer value)
+#retry_timeout = 60
+
+# Minimum time, in seconds, between IPMI operations sent to a
+# server. There is a risk with some hardware that setting this
+# too low may cause the BMC to crash. Recommended setting is 5
+# seconds. (integer value)
+#min_command_interval = 5
+
+
+[irmc]
+
+#
+# From ironic
+#
+
+# Ironic conductor node's "NFS" or "CIFS" root path (string
+# value)
+#remote_image_share_root = /remote_image_share_root
+
+# IP of remote image server (string value)
+#remote_image_server = <None>
+
+# Share type of virtual media (string value)
+# Allowed values: CIFS, NFS
+#remote_image_share_type = CIFS
+
+# share name of remote_image_server (string value)
+#remote_image_share_name = share
+
+# User name of remote_image_server (string value)
+#remote_image_user_name = <None>
+
+# Password of remote_image_user_name (string value)
+#remote_image_user_password = <None>
+
+# Domain name of remote_image_user_name (string value)
+#remote_image_user_domain =
+
+# Port to be used for iRMC operations (port value)
+# Minimum value: 0
+# Maximum value: 65535
+# Allowed values: 443, 80
+#port = 443
+
+# Authentication method to be used for iRMC operations (string
+# value)
+# Allowed values: basic, digest
+#auth_method = basic
+
+# Timeout (in seconds) for iRMC operations (integer value)
+#client_timeout = 60
+
+# Sensor data retrieval method. (string value)
+# Allowed values: ipmitool, scci
+#sensor_method = ipmitool
+
+# SNMP protocol version (string value)
+# Allowed values: v1, v2c, v3
+#snmp_version = v2c
+
+# SNMP port (port value)
+# Minimum value: 0
+# Maximum value: 65535
+#snmp_port = 161
+
+# SNMP community. Required for versions "v1" and "v2c" (string
+# value)
+#snmp_community = public
+
+# SNMP security name. Required for version "v3" (string value)
+#snmp_security = <None>
+
+# SNMP polling interval in seconds (integer value)
+#snmp_polling_interval = 10
+
+
+[ironic_lib]
+
+#
+# From ironic_lib.utils
+#
+
+# Command that is prefixed to commands that are run as root.
+# If not specified, no commands are run as root. (string
+# value)
+#root_helper = sudo ironic-rootwrap /etc/ironic/rootwrap.conf
+
+
+[iscsi]
+
+#
+# From ironic
+#
+
+# The port number on which the iSCSI portal listens for
+# incoming connections. (port value)
+# Minimum value: 0
+# Maximum value: 65535
+#portal_port = 3260
+
+
+[keystone]
+
+#
+# From ironic
+#
+
+# The region used for getting endpoints of OpenStack services.
+# (string value)
+{%- if ironic.get('identity', {}).get('region') %}
+region_name = {{ ironic.identity.region }}
+{%- else %}
+#region_name = <None>
+{%- endif %}
+
+
+[keystone_authtoken]
+
+#
+# From keystonemiddleware.auth_token
+#
+
+# Authentication URL (string value)
+{%- if ironic.get('identity', {}).get('engine') == 'keystone' %}
+auth_url = {{ ironic.identity.protocol }}://{{ ironic.identity.host }}:{{ ironic.identity.port }}/identity
+{%- else %}
+#auth_uri = <None>
+{%- endif %}
+
+# Authentication type to load (string value)
+# Deprecated group/name - [service_catalog]/auth_plugin
+{%- if ironic.get('identity', {}).get('auth_type') %}
+auth_type = {{ ironic.identity.auth_type }}
+{%- else %}
+#auth_type = <None>
+{%- endif %}
+
+# Optional domain ID to use with v3 and v2 parameters. It will
+# be used for both the user and project domain in v3 and
+# ignored in v2 authentication. (string value)
+{%- if ironic.get('identity', {}).get('default_domain_id') %}
+default_domain_id = {{ ironic.identity.default_domain_id }}
+{%- else %}
+#default_domain_id = <None>
+{%- endif %}
+
+# Optional domain name to use with v3 API and v2 parameters.
+# It will be used for both the user and project domain in v3
+# and ignored in v2 authentication. (string value)
+{%- if ironic.get('identity', {}).get('default_domain_name') %}
+default_domain_name = {{ ironic.identity.default_domain_name }}
+{%- else %}
+#default_domain_name = <None>
+{%- endif %}
+
+# Domain ID to scope to (string value)
+{%- if ironic.get('identity', {}).get('domain_id') %}
+domain_id = {{ ironic.identity.domain_id }}
+{%- else %}
+#domain_id = <None>
+{%- endif %}
+
+# Domain name to scope to (string value)
+{%- if ironic.get('identity', {}).get('domain_name') %}
+domain_name = {{ ironic.identity.domain_name }}
+{%- else %}
+#domain_name = <None>
+{%- endif %}
+
+# User's password (string value)
+{%- if ironic.get('identity', {}).get('password') %}
+password = {{ ironic.identity.password }}
+{%- else %}
+#password = <None>
+{%- endif %}
+
+# Domain ID containing project (string value)
+{%- if ironic.get('identity', {}).get('project_domain_id') %}
+project_domain_id = {{ ironic.identity.project_domain_id }}
+{%- else %}
+#project_domain_id = <None>
+{%- endif %}
+
+# Domain name containing project (string value)
+{%- if ironic.get('identity', {}).get('project_domain_name') %}
+project_domain_name = {{ ironic.identity.project_domain_name }}
+{%- else %}
+#project_domain_name = <None>
+{%- endif %}
+
+# Project ID to scope to (string value)
+# Deprecated group/name - [service_catalog]/tenant-id
+{%- if ironic.get('identity', {}).get('project_id') %}
+project_id = {{ ironic.identity.project_id }}
+{%- else %}
+#project_id = <None>
+{%- endif %}
+
+# Project name to scope to (string value)
+# Deprecated group/name - [service_catalog]/tenant-name
+{%- if ironic.get('identity', {}).get('project_name') %}
+project_name = {{ ironic.identity.project_name }}
+{%- else %}
+#project_name = <None>
+{%- endif %}
+
+# Tenant ID (string value)
+{%- if ironic.get('identity', {}).get('tenant_id') %}
+tenant_id = {{ ironic.identity.tenant_id }}
+{%- else %}
+#tenant_id = <None>
+{%- endif %}
+
+# Tenant Name (string value)
+{%- if ironic.get('identity', {}).get('tenant_name') %}
+tenant_name = {{ ironic.identity.tenant_name }}
+{%- else %}
+#tenant_name = <None>
+{%- endif %}
+
+# User's domain id (string value)
+{%- if ironic.get('identity', {}).get('user_domain_id') %}
+user_domain_id = {{ ironic.identity.user_domain_id }}
+{%- else %}
+#user_domain_id = <None>
+{%- endif %}
+
+# User's domain name (string value)
+{%- if ironic.get('identity', {}).get('user_domain_name') %}
+user_domain_name = {{ ironic.identity.user_domain_name }}
+{%- else %}
+#user_domain_name = <None>
+{%- endif %}
+
+# User id (string value)
+{%- if ironic.get('identity', {}).get('user_id')  %}
+user_id = {{ ironic.identity.user_id }}
+{%- else %}
+#user_id = <None>
+{%- endif %}
+
+# Username (string value)
+# Deprecated group/name - [service_catalog]/user-name
+{%- if ironic.get('identity', {}).get('user') %}
+username = {{ ironic.identity.user }}
+{%- else %}
+#username = <None>
+{%- endif %}
+
+# API version of the admin Identity API endpoint. (string
+# value)
+{%- if ironic.get('identity', {}).get('version') %}
+auth_version = {{ ironic.identity.version }}
+{%- else %}
+#auth_version = <None>
+{%- endif %}
+
+# Do not handle authorization requests within the middleware,
+# but delegate the authorization decision to downstream WSGI
+# components. (boolean value)
+#delay_auth_decision = false
+
+# Request timeout value for communicating with Identity API
+# server. (integer value)
+#http_connect_timeout = <None>
+
+# How many times are we trying to reconnect when communicating
+# with Identity API Server. (integer value)
+#http_request_max_retries = 3
+
+# Request environment key where the Swift cache object is
+# stored. When auth_token middleware is deployed with a Swift
+# cache, use this option to have the middleware share a
+# caching backend with swift. Otherwise, use the
+# ``memcached_servers`` option instead. (string value)
+#cache = <None>
+
+# Required if identity server requires client certificate
+# (string value)
+#certfile = <None>
+
+# Required if identity server requires client certificate
+# (string value)
+#keyfile = <None>
+
+# A PEM encoded Certificate Authority to use when verifying
+# HTTPs connections. Defaults to system CAs. (string value)
+#cafile = <None>
+
+# Verify HTTPS connections. (boolean value)
+#insecure = false
+
+# The region in which the identity server can be found.
+# (string value)
+#region_name = <None>
+
+# DEPRECATED: Directory used to cache files related to PKI
+# tokens. This option has been deprecated in the Ocata release
+# and will be removed in the P release. (string value)
+# This option is deprecated for removal since Ocata.
+# Its value may be silently ignored in the future.
+# Reason: PKI token format is no longer supported.
+#signing_dir = <None>
+
+# Optionally specify a list of memcached server(s) to use for
+# caching. If left undefined, tokens will instead be cached
+# in-process. (list value)
+# Deprecated group/name - [keystone_authtoken]/memcache_servers
+{%- if ironic.get('identity', {}).get('memcached_servers') %}
+memcached_servers = {{ ironic.identity.memcached_servers }}
+{%- else %}
+#memcached_servers = <None>
+{%- endif %}
+
+# In order to prevent excessive effort spent validating
+# tokens, the middleware caches previously-seen tokens for a
+# configurable duration (in seconds). Set to -1 to disable
+# caching completely. (integer value)
+#token_cache_time = 300
+
+# DEPRECATED: Determines the frequency at which the list of
+# revoked tokens is retrieved from the Identity service (in
+# seconds). A high number of revocation events combined with a
+# low cache duration may significantly reduce performance.
+# Only valid for PKI tokens. This option has been deprecated
+# in the Ocata release and will be removed in the P release.
+# (integer value)
+# This option is deprecated for removal since Ocata.
+# Its value may be silently ignored in the future.
+# Reason: PKI token format is no longer supported.
+#revocation_cache_time = 10
+
+# (Optional) If defined, indicate whether token data should be
+# authenticated or authenticated and encrypted. If MAC, token
+# data is authenticated (with HMAC) in the cache. If ENCRYPT,
+# token data is encrypted and authenticated in the cache. If
+# the value is not one of these options or empty, auth_token
+# will raise an exception on initialization. (string value)
+# Allowed values: None, MAC, ENCRYPT
+#memcache_security_strategy = None
+
+# (Optional, mandatory if memcache_security_strategy is
+# defined) This string is used for key derivation. (string
+# value)
+#memcache_secret_key = <None>
+
+# (Optional) Number of seconds memcached server is considered
+# dead before it is tried again. (integer value)
+#memcache_pool_dead_retry = 300
+
+# (Optional) Maximum total number of open connections to every
+# memcached server. (integer value)
+#memcache_pool_maxsize = 10
+
+# (Optional) Socket timeout in seconds for communicating with
+# a memcached server. (integer value)
+#memcache_pool_socket_timeout = 3
+
+# (Optional) Number of seconds a connection to memcached is
+# held unused in the pool before it is closed. (integer value)
+#memcache_pool_unused_timeout = 60
+
+# (Optional) Number of seconds that an operation will wait to
+# get a memcached client connection from the pool. (integer
+# value)
+#memcache_pool_conn_get_timeout = 10
+
+# (Optional) Use the advanced (eventlet safe) memcached client
+# pool. The advanced pool will only work under python 2.x.
+# (boolean value)
+#memcache_use_advanced_pool = false
+
+# (Optional) Indicate whether to set the X-Service-Catalog
+# header. If False, middleware will not ask for service
+# catalog on token validation and will not set the X-Service-
+# Catalog header. (boolean value)
+#include_service_catalog = true
+
+# Used to control the use and type of token binding. Can be
+# set to: "disabled" to not check token binding. "permissive"
+# (default) to validate binding information if the bind type
+# is of a form known to the server and ignore it if not.
+# "strict" like "permissive" but if the bind type is unknown
+# the token will be rejected. "required" any form of token
+# binding is needed to be allowed. Finally the name of a
+# binding method that must be present in tokens. (string
+# value)
+#enforce_token_bind = permissive
+
+# DEPRECATED: If true, the revocation list will be checked for
+# cached tokens. This requires that PKI tokens are configured
+# on the identity server. (boolean value)
+# This option is deprecated for removal since Ocata.
+# Its value may be silently ignored in the future.
+# Reason: PKI token format is no longer supported.
+#check_revocations_for_cached = false
+
+# DEPRECATED: Hash algorithms to use for hashing PKI tokens.
+# This may be a single algorithm or multiple. The algorithms
+# are those supported by Python standard hashlib.new(). The
+# hashes will be tried in the order given, so put the
+# preferred one first for performance. The result of the first
+# hash will be stored in the cache. This will typically be set
+# to multiple values only while migrating from a less secure
+# algorithm to a more secure one. Once all the old tokens are
+# expired this option should be set to a single value for
+# better performance. (list value)
+# This option is deprecated for removal since Ocata.
+# Its value may be silently ignored in the future.
+# Reason: PKI token format is no longer supported.
+#hash_algorithms = md5
+
+# A choice of roles that must be present in a service token.
+# Service tokens are allowed to request that an expired token
+# can be used and so this check should tightly control that
+# only actual services should be sending this token. Roles
+# here are applied as an ANY check so any role in this list
+# must be present. For backwards compatibility reasons this
+# currently only affects the allow_expired check. (list value)
+#service_token_roles = service
+
+# For backwards compatibility reasons we must let valid
+# service tokens pass that don't pass the service_token_roles
+# check as valid. Setting this true will become the default in
+# a future release and should be enabled if possible. (boolean
+# value)
+#service_token_roles_required = false
+
+# Authentication type to load (string value)
+# Deprecated group/name - [keystone_authtoken]/auth_plugin
+{%- if ironic.get('identity', {}).get('auth_type') %}
+auth_type = {{ ironic.identity.auth_type }}
+{%- else %}
+#auth_type = <None>
+{%- endif %}
+
+# Config Section from which to load plugin specific options
+# (string value)
+#auth_section = <None>
+
+
+[matchmaker_redis]
+
+#
+# From oslo.messaging
+#
+
+# DEPRECATED: Host to locate redis. (string value)
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Replaced by [DEFAULT]/transport_url
+#host = 127.0.0.1
+
+# DEPRECATED: Use this port to connect to redis host. (port
+# value)
+# Minimum value: 0
+# Maximum value: 65535
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Replaced by [DEFAULT]/transport_url
+#port = 6379
+
+# DEPRECATED: Password for Redis server (optional). (string
+# value)
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Replaced by [DEFAULT]/transport_url
+#password =
+
+# DEPRECATED: List of Redis Sentinel hosts (fault tolerance
+# mode), e.g., [host:port, host1:port ... ] (list value)
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Replaced by [DEFAULT]/transport_url
+#sentinel_hosts =
+
+# Redis replica set name. (string value)
+#sentinel_group_name = oslo-messaging-zeromq
+
+# Time in ms to wait between connection attempts. (integer
+# value)
+#wait_timeout = 2000
+
+# Time in ms to wait before the transaction is killed.
+# (integer value)
+#check_timeout = 20000
+
+# Timeout in ms on blocking socket operations. (integer value)
+#socket_timeout = 10000
+
+
+[metrics]
+
+#
+# From ironic
+#
+
+# Backend for the agent ramdisk to use for metrics. Default
+# possible backends are "noop" and "statsd". (string value)
+#agent_backend = noop
+
+# Prepend the hostname to all metric names sent by the agent
+# ramdisk. The format of metric names is
+# [global_prefix.][uuid.][host_name.]prefix.metric_name.
+# (boolean value)
+#agent_prepend_host = false
+
+# Prepend the node's Ironic uuid to all metric names sent by
+# the agent ramdisk. The format of metric names is
+# [global_prefix.][uuid.][host_name.]prefix.metric_name.
+# (boolean value)
+#agent_prepend_uuid = false
+
+# Split the prepended host value by "." and reverse it for
+# metrics sent by the agent ramdisk (to better match the
+# reverse hierarchical form of domain names). (boolean value)
+#agent_prepend_host_reverse = true
+
+# Prefix all metric names sent by the agent ramdisk with this
+# value. The format of metric names is
+# [global_prefix.][uuid.][host_name.]prefix.metric_name.
+# (string value)
+#agent_global_prefix = <None>
+
+#
+# From ironic_lib.metrics
+#
+
+# Backend to use for the metrics system. (string value)
+# Allowed values: noop, statsd
+#backend = noop
+
+# Prepend the hostname to all metric names. The format of
+# metric names is
+# [global_prefix.][host_name.]prefix.metric_name. (boolean
+# value)
+#prepend_host = false
+
+# Split the prepended host value by "." and reverse it (to
+# better match the reverse hierarchical form of domain names).
+# (boolean value)
+#prepend_host_reverse = true
+
+# Prefix all metric names with this value. By default, there
+# is no global prefix. The format of metric names is
+# [global_prefix.][host_name.]prefix.metric_name. (string
+# value)
+#global_prefix = <None>
+
+
+[metrics_statsd]
+
+#
+# From ironic
+#
+
+# Host for the agent ramdisk to use with the statsd backend.
+# This must be accessible from networks the agent is booted
+# on. (string value)
+#agent_statsd_host = localhost
+
+# Port for the agent ramdisk to use with the statsd backend.
+# (port value)
+# Minimum value: 0
+# Maximum value: 65535
+#agent_statsd_port = 8125
+
+#
+# From ironic_lib.metrics_statsd
+#
+
+# Host for use with the statsd backend. (string value)
+#statsd_host = localhost
+
+# Port to use with the statsd backend. (port value)
+# Minimum value: 0
+# Maximum value: 65535
+#statsd_port = 8125
+
+
+[neutron]
+
+#
+# From ironic
+#
+
+# Authentication URL (string value)
+{%- if conductor.get('neutron', {}).get('auth_strategy') == 'keystone' %}
+auth_url = {{ conductor.identity.protocol }}://{{ conductor.identity.host }}:{{ conductor.identity.port }}/identity
+{%- else %}
+#auth_url = <None>
+{%- endif %}
+
+# Authentication strategy to use when connecting to neutron.
+# Running neutron in noauth mode (related to but not affected
+# by this setting) is insecure and should only be used for
+# testing. (string value)
+# Allowed values: keystone, noauth
+{%- if conductor.get('neutron', {}).get('auth_strategy') %}
+auth_strategy = {{ conductor.neutron.auth_strategy }}
+{%- else %}
+#auth_strategy = keystone
+{%- endif %}
+
+# Authentication type to load (string value)
+# Deprecated group/name - [neutron]/auth_plugin
+{%- if conductor.get('neutron', {}).get('auth_type') %}
+auth_type = {{ conductor.neutron.auth_type }}
+{%- else %}
+#auth_type = <None>
+{%- endif %}
+
+# PEM encoded Certificate Authority to use when verifying
+# HTTPs connections. (string value)
+#cafile = <None>
+
+# PEM encoded client certificate cert file (string value)
+#certfile = <None>
+
+# Neutron network UUID or name for the ramdisk to be booted
+# into for cleaning nodes. Required for "neutron" network
+# interface. It is also required if cleaning nodes when using
+# "flat" network interface or "neutron" DHCP provider. If a
+# name is provided, it must be unique among all networks or
+# cleaning will fail. (string value)
+# Deprecated group/name - [neutron]/cleaning_network_uuid
+{%- if conductor.get('neutron', {}).get('cleaning_network') %}
+cleaning_network = {{ conductor.neutron.cleaning_network }}
+{%- else %}
+#cleaning_network = <None>
+{%- endif %}
+
+# List of Neutron Security Group UUIDs to be applied during
+# cleaning of the nodes. Optional for the "neutron" network
+# interface and not used for the "flat" or "noop" network
+# interfaces. If not specified, default security group is
+# used. (list value)
+#cleaning_network_security_groups =
+
+# Optional domain ID to use with v3 and v2 parameters. It will
+# be used for both the user and project domain in v3 and
+# ignored in v2 authentication. (string value)
+#default_domain_id = <None>
+
+# Optional domain name to use with v3 API and v2 parameters.
+# It will be used for both the user and project domain in v3
+# and ignored in v2 authentication. (string value)
+#default_domain_name = <None>
+
+# Domain ID to scope to (string value)
+#domain_id = <None>
+
+# Domain name to scope to (string value)
+#domain_name = <None>
+
+# Verify HTTPS connections. (boolean value)
+#insecure = false
+
+# PEM encoded client certificate key file (string value)
+#keyfile = <None>
+
+# User's password (string value)
+{%- if conductor.get('neutron', {}).get('password') %}
+password = {{ conductor.neutron.password }}
+{%- else %}
+#password = <None>
+{%- endif %}
+
+# Delay value to wait for Neutron agents to setup sufficient
+# DHCP configuration for port. (integer value)
+# Minimum value: 0
+{%- if conductor.get('neutron', {}).get('port_setup_delay') %}
+port_setup_delay = {{ conductor.neutron.port_setup_delay }}
+{%- else %}
+#port_setup_delay = 0
+{%- endif %}
+
+# Domain ID containing project (string value)
+{%- if conductor.get('neutron', {}).get('project_domain_id') %}
+project_domain_id = {{ conductor.neutron.project_domain_id }}
+{%- else %}
+#project_domain_id = <None>
+{%- endif %}
+
+# Domain name containing project (string value)
+{%- if conductor.get('neutron', {}).get('project_domain_name') %}
+project_domain_name = {{ conductor.neutron.project_domain_name }}
+{%- else %}
+#project_domain_name = <None>
+{%- endif %}
+
+# Project ID to scope to (string value)
+# Deprecated group/name - [neutron]/tenant-id
+{%- if conductor.get('neutron', {}).get('project_id') %}
+project_id = {{ conductor.neutron.project_id }}
+{%- else %}
+#project_id = <None>
+{%- endif %}
+
+# Project name to scope to (string value)
+# Deprecated group/name - [neutron]/tenant-name
+{%- if conductor.get('neutron', {}).get('project_name') %}
+project_name = {{ conductor.neutron.project_name }}
+{%- else %}
+#project_name = <None>
+{%- endif %}
+
+# Neutron network UUID or name for the ramdisk to be booted
+# into for provisioning nodes. Required for "neutron" network
+# interface. If a name is provided, it must be unique among
+# all networks or deploy will fail. (string value)
+# Deprecated group/name - [neutron]/provisioning_network_uuid
+{%- if conductor.get('neutron', {}).get('provisioning_network') %}
+provisioning_network = {{ conductor.neutron.provisioning_network }}
+{%- else %}
+#provisioning_network = <None>
+{%- endif %}
+
+# List of Neutron Security Group UUIDs to be applied during
+# provisioning of the nodes. Optional for the "neutron"
+# network interface and not used for the "flat" or "noop"
+# network interfaces. If not specified, default security group
+# is used. (list value)
+#provisioning_network_security_groups =
+
+# Client retries in the case of a failed request. (integer
+# value)
+#retries = 3
+
+# Tenant ID (string value)
+{%- if conductor.get('neutron', {}).get('tenant_id') %}
+tenant_id = {{ conductor.neutron.tenant_id }}
+{%- else %}
+#tenant_id = <None>
+{%- endif %}
+
+# Tenant Name (string value)
+#tenant_name = <None>
+
+# Timeout value for http requests (integer value)
+#timeout = <None>
+
+# Trust ID (string value)
+#trust_id = <None>
+
+# URL for connecting to neutron. Default value translates to
+# 'http://$my_ip:9696' when auth_strategy is 'noauth', and to
+# discovery from Keystone catalog when auth_strategy is
+# 'keystone'. (string value)
+#url = <None>
+
+# Timeout value for connecting to neutron in seconds. (integer
+# value)
+#url_timeout = 30
+
+# User's domain id (string value)
+{%- if conductor.get('neutron', {}).get('user_domain_id') %}
+user_domain_id = {{ conductor.neutron.user_domain_id }}
+{%- else %}
+#user_domain_id = <None>
+{%- endif %}
+
+# User's domain name (string value)
+{%- if conductor.get('neutron', {}).get('user_domain_name') %}
+user_domain_name = {{ conductor.neutron.user_domain_name }}
+{%- else %}
+#user_domain_name = <None>
+{%- endif %}
+
+# User id (string value)
+{%- if conductor.get('neutron', {}).get('user_id') %}
+user_id = {{ conductor.neutron.user_id }}
+{%- else %}
+#user_id = <None>
+{%- endif %}
+
+# Username (string value)
+# Deprecated group/name - [neutron]/user-name
+{%- if conductor.get('neutron', {}).get('username') %}
+username = {{ conductor.neutron.username }}
+{%- else %}
+#username = <None>
+{%- endif %}
+
+
+[oneview]
+
+#
+# From ironic
+#
+
+# URL where OneView is available. (string value)
+#manager_url = <None>
+
+# OneView username to be used. (string value)
+#username = <None>
+
+# OneView password to be used. (string value)
+#password = <None>
+
+# Option to allow insecure connection with OneView. (boolean
+# value)
+#allow_insecure_connections = false
+
+# Path to CA certificate. (string value)
+#tls_cacert_file = <None>
+
+# Max connection retries to check changes on OneView. (integer
+# value)
+#max_polling_attempts = 12
+
+# Whether to enable the periodic tasks for OneView driver be
+# aware when OneView hardware resources are taken and released
+# by Ironic or OneView users and proactively manage nodes in
+# clean fail state according to Dynamic Allocation model of
+# hardware resources allocation in OneView. (boolean value)
+#enable_periodic_tasks = true
+
+# Period (in seconds) for periodic tasks to be executed when
+# enable_periodic_tasks=True. (integer value)
+#periodic_check_interval = 300
+
+
+[oslo_concurrency]
+
+#
+# From oslo.concurrency
+#
+
+# Enables or disables inter-process locks. (boolean value)
+# Deprecated group/name - [DEFAULT]/disable_process_locking
+#disable_process_locking = false
+
+# Directory to use for lock files. For security, the
+# specified directory should only be writable by the user
+# running the processes that need locking. Defaults to
+# environment variable OSLO_LOCK_PATH. If external locks are
+# used, a lock path must be set. (string value)
+# Deprecated group/name - [DEFAULT]/lock_path
+#lock_path = <None>
+
+
+[oslo_messaging_amqp]
+
+#
+# From oslo.messaging
+#
+
+# Name for the AMQP container. must be globally unique.
+# Defaults to a generated UUID (string value)
+# Deprecated group/name - [amqp1]/container_name
+#container_name = <None>
+
+# Timeout for inactive connections (in seconds) (integer
+# value)
+# Deprecated group/name - [amqp1]/idle_timeout
+#idle_timeout = 0
+
+# Debug: dump AMQP frames to stdout (boolean value)
+# Deprecated group/name - [amqp1]/trace
+#trace = false
+
+# CA certificate PEM file used to verify the server's
+# certificate (string value)
+# Deprecated group/name - [amqp1]/ssl_ca_file
+#ssl_ca_file =
+
+# Self-identifying certificate PEM file for client
+# authentication (string value)
+# Deprecated group/name - [amqp1]/ssl_cert_file
+#ssl_cert_file =
+
+# Private key PEM file used to sign ssl_cert_file certificate
+# (optional) (string value)
+# Deprecated group/name - [amqp1]/ssl_key_file
+#ssl_key_file =
+
+# Password for decrypting ssl_key_file (if encrypted) (string
+# value)
+# Deprecated group/name - [amqp1]/ssl_key_password
+#ssl_key_password = <None>
+
+# DEPRECATED: Accept clients using either SSL or plain TCP
+# (boolean value)
+# Deprecated group/name - [amqp1]/allow_insecure_clients
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Not applicable - not a SSL server
+#allow_insecure_clients = false
+
+# Space separated list of acceptable SASL mechanisms (string
+# value)
+# Deprecated group/name - [amqp1]/sasl_mechanisms
+#sasl_mechanisms =
+
+# Path to directory that contains the SASL configuration
+# (string value)
+# Deprecated group/name - [amqp1]/sasl_config_dir
+#sasl_config_dir =
+
+# Name of configuration file (without .conf suffix) (string
+# value)
+# Deprecated group/name - [amqp1]/sasl_config_name
+#sasl_config_name =
+
+# User name for message broker authentication (string value)
+# Deprecated group/name - [amqp1]/username
+#username =
+
+# Password for message broker authentication (string value)
+# Deprecated group/name - [amqp1]/password
+#password =
+
+# Seconds to pause before attempting to re-connect. (integer
+# value)
+# Minimum value: 1
+#connection_retry_interval = 1
+
+# Increase the connection_retry_interval by this many seconds
+# after each unsuccessful failover attempt. (integer value)
+# Minimum value: 0
+#connection_retry_backoff = 2
+
+# Maximum limit for connection_retry_interval +
+# connection_retry_backoff (integer value)
+# Minimum value: 1
+#connection_retry_interval_max = 30
+
+# Time to pause between re-connecting an AMQP 1.0 link that
+# failed due to a recoverable error. (integer value)
+# Minimum value: 1
+#link_retry_delay = 10
+
+# The maximum number of attempts to re-send a reply message
+# which failed due to a recoverable error. (integer value)
+# Minimum value: -1
+#default_reply_retry = 0
+
+# The deadline for an rpc reply message delivery. (integer
+# value)
+# Minimum value: 5
+#default_reply_timeout = 30
+
+# The deadline for an rpc cast or call message delivery. Only
+# used when caller does not provide a timeout expiry. (integer
+# value)
+# Minimum value: 5
+#default_send_timeout = 30
+
+# The deadline for a sent notification message delivery. Only
+# used when caller does not provide a timeout expiry. (integer
+# value)
+# Minimum value: 5
+#default_notify_timeout = 30
+
+# The duration to schedule a purge of idle sender links.
+# Detach link after expiry. (integer value)
+# Minimum value: 1
+#default_sender_link_timeout = 600
+
+# Indicates the addressing mode used by the driver.
+# Permitted values:
+# 'legacy' - use legacy non-routable addressing
+# 'routable' - use routable addresses
+# 'dynamic' - use legacy addresses if the message bus does
+# not support routing otherwise use routable addressing
+# (string value)
+#addressing_mode = dynamic
+
+# address prefix used when sending to a specific server
+# (string value)
+# Deprecated group/name - [amqp1]/server_request_prefix
+#server_request_prefix = exclusive
+
+# address prefix used when broadcasting to all servers (string
+# value)
+# Deprecated group/name - [amqp1]/broadcast_prefix
+#broadcast_prefix = broadcast
+
+# address prefix when sending to any server in group (string
+# value)
+# Deprecated group/name - [amqp1]/group_request_prefix
+#group_request_prefix = unicast
+
+# Address prefix for all generated RPC addresses (string
+# value)
+#rpc_address_prefix = openstack.org/om/rpc
+
+# Address prefix for all generated Notification addresses
+# (string value)
+#notify_address_prefix = openstack.org/om/notify
+
+# Appended to the address prefix when sending a fanout
+# message. Used by the message bus to identify fanout
+# messages. (string value)
+#multicast_address = multicast
+
+# Appended to the address prefix when sending to a particular
+# RPC/Notification server. Used by the message bus to identify
+# messages sent to a single destination. (string value)
+#unicast_address = unicast
+
+# Appended to the address prefix when sending to a group of
+# consumers. Used by the message bus to identify messages that
+# should be delivered in a round-robin fashion across
+# consumers. (string value)
+#anycast_address = anycast
+
+# Exchange name used in notification addresses.
+# Exchange name resolution precedence:
+# Target.exchange if set
+# else default_notification_exchange if set
+# else control_exchange if set
+# else 'notify' (string value)
+#default_notification_exchange = <None>
+
+# Exchange name used in RPC addresses.
+# Exchange name resolution precedence:
+# Target.exchange if set
+# else default_rpc_exchange if set
+# else control_exchange if set
+# else 'rpc' (string value)
+#default_rpc_exchange = <None>
+
+# Window size for incoming RPC Reply messages. (integer value)
+# Minimum value: 1
+#reply_link_credit = 200
+
+# Window size for incoming RPC Request messages (integer
+# value)
+# Minimum value: 1
+#rpc_server_credit = 100
+
+# Window size for incoming Notification messages (integer
+# value)
+# Minimum value: 1
+#notify_server_credit = 100
+
+# Send messages of this type pre-settled.
+# Pre-settled messages will not receive acknowledgement
+# from the peer. Note well: pre-settled messages may be
+# silently discarded if the delivery fails.
+# Permitted values:
+# 'rpc-call' - send RPC Calls pre-settled
+# 'rpc-reply'- send RPC Replies pre-settled
+# 'rpc-cast' - Send RPC Casts pre-settled
+# 'notify' - Send Notifications pre-settled
+# (multi valued)
+#pre_settled = rpc-cast
+
+
+[oslo_messaging_kafka]
+
+#
+# From oslo.messaging
+#
+
+# DEPRECATED: Default Kafka broker Host (string value)
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Replaced by [DEFAULT]/transport_url
+#kafka_default_host = localhost
+
+# DEPRECATED: Default Kafka broker Port (port value)
+# Minimum value: 0
+# Maximum value: 65535
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Replaced by [DEFAULT]/transport_url
+#kafka_default_port = 9092
+
+# Max fetch bytes of Kafka consumer (integer value)
+#kafka_max_fetch_bytes = 1048576
+
+# Default timeout(s) for Kafka consumers (floating point
+# value)
+#kafka_consumer_timeout = 1.0
+
+# Pool Size for Kafka Consumers (integer value)
+#pool_size = 10
+
+# The pool size limit for connections expiration policy
+# (integer value)
+#conn_pool_min_size = 2
+
+# The time-to-live in sec of idle connections in the pool
+# (integer value)
+#conn_pool_ttl = 1200
+
+# Group id for Kafka consumer. Consumers in one group will
+# coordinate message consumption (string value)
+#consumer_group = oslo_messaging_consumer
+
+# Upper bound on the delay for KafkaProducer batching in
+# seconds (floating point value)
+#producer_batch_timeout = 0.0
+
+# Size of batch for the producer async send (integer value)
+#producer_batch_size = 16384
+
+
+[oslo_messaging_notifications]
+
+#
+# From oslo.messaging
+#
+
+# The Drivers(s) to handle sending notifications. Possible
+# values are messaging, messagingv2, routing, log, test, noop
+# (multi valued)
+# Deprecated group/name - [DEFAULT]/notification_driver
+#driver =
+
+# A URL representing the messaging driver to use for
+# notifications. If not set, we fall back to the same
+# configuration used for RPC. (string value)
+# Deprecated group/name - [DEFAULT]/notification_transport_url
+#transport_url = <None>
+
+# AMQP topic used for OpenStack notifications. (list value)
+# Deprecated group/name - [rpc_notifier2]/topics
+# Deprecated group/name - [DEFAULT]/notification_topics
+#topics = notifications
+
+
+[oslo_messaging_rabbit]
+
+#
+# From oslo.messaging
+#
+
+# Use durable queues in AMQP. (boolean value)
+# Deprecated group/name - [DEFAULT]/amqp_durable_queues
+# Deprecated group/name - [DEFAULT]/rabbit_durable_queues
+#amqp_durable_queues = false
+
+# Auto-delete queues in AMQP. (boolean value)
+# Deprecated group/name - [DEFAULT]/amqp_auto_delete
+#amqp_auto_delete = false
+
+# Enable SSL (boolean value)
+#ssl = <None>
+
+# SSL version to use (valid only if SSL enabled). Valid values
+# are TLSv1 and SSLv23. SSLv2, SSLv3, TLSv1_1, and TLSv1_2 may
+# be available on some distributions. (string value)
+# Deprecated group/name - [oslo_messaging_rabbit]/kombu_ssl_version
+#ssl_version =
+
+# SSL key file (valid only if SSL enabled). (string value)
+# Deprecated group/name - [oslo_messaging_rabbit]/kombu_ssl_keyfile
+#ssl_key_file =
+
+# SSL cert file (valid only if SSL enabled). (string value)
+# Deprecated group/name - [oslo_messaging_rabbit]/kombu_ssl_certfile
+#ssl_cert_file =
+
+# SSL certification authority file (valid only if SSL
+# enabled). (string value)
+# Deprecated group/name - [oslo_messaging_rabbit]/kombu_ssl_ca_certs
+#ssl_ca_file =
+
+# How long to wait before reconnecting in response to an AMQP
+# consumer cancel notification. (floating point value)
+# Deprecated group/name - [DEFAULT]/kombu_reconnect_delay
+#kombu_reconnect_delay = 1.0
+
+# EXPERIMENTAL: Possible values are: gzip, bz2. If not set
+# compression will not be used. This option may not be
+# available in future versions. (string value)
+#kombu_compression = <None>
+
+# How long to wait a missing client before abandoning to send
+# it its replies. This value should not be longer than
+# rpc_response_timeout. (integer value)
+# Deprecated group/name - [oslo_messaging_rabbit]/kombu_reconnect_timeout
+#kombu_missing_consumer_retry_timeout = 60
+
+# Determines how the next RabbitMQ node is chosen in case the
+# one we are currently connected to becomes unavailable. Takes
+# effect only if more than one RabbitMQ node is provided in
+# common. (string value)
+# Allowed values: round-robin, shuffle
+#kombu_failover_strategy = round-robin
+
+# DEPRECATED: The RabbitMQ broker address where a single node
+# is used. (string value)
+# Deprecated group/name - [DEFAULT]/rabbit_host
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Replaced by [DEFAULT]/transport_url
+#rabbit_host = localhost
+
+# DEPRECATED: The RabbitMQ broker port where a single node is
+# used. (port value)
+# Minimum value: 0
+# Maximum value: 65535
+# Deprecated group/name - [DEFAULT]/rabbit_port
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Replaced by [DEFAULT]/transport_url
+#rabbit_port = 5672
+
+# DEPRECATED: RabbitMQ HA cluster host:port pairs. (list
+# value)
+# Deprecated group/name - [DEFAULT]/rabbit_hosts
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Replaced by [DEFAULT]/transport_url
+#rabbit_hosts = $rabbit_host:$rabbit_port
+
+# DEPRECATED: The RabbitMQ userid. (string value)
+# Deprecated group/name - [DEFAULT]/rabbit_userid
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Replaced by [DEFAULT]/transport_url
+#rabbit_userid = guest
+
+# DEPRECATED: The RabbitMQ password. (string value)
+# Deprecated group/name - [DEFAULT]/rabbit_password
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Replaced by [DEFAULT]/transport_url
+#rabbit_password = guest
+
+# The RabbitMQ login method. (string value)
+# Allowed values: PLAIN, AMQPLAIN, RABBIT-CR-DEMO
+# Deprecated group/name - [DEFAULT]/rabbit_login_method
+#rabbit_login_method = AMQPLAIN
+
+# DEPRECATED: The RabbitMQ virtual host. (string value)
+# Deprecated group/name - [DEFAULT]/rabbit_virtual_host
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+# Reason: Replaced by [DEFAULT]/transport_url
+#rabbit_virtual_host = /
+
+# How frequently to retry connecting with RabbitMQ. (integer
+# value)
+#rabbit_retry_interval = 1
+
+# How long to backoff for between retries when connecting to
+# RabbitMQ. (integer value)
+# Deprecated group/name - [DEFAULT]/rabbit_retry_backoff
+#rabbit_retry_backoff = 2
+
+# Maximum interval of RabbitMQ connection retries. Default is
+# 30 seconds. (integer value)
+#rabbit_interval_max = 30
+
+# DEPRECATED: Maximum number of RabbitMQ connection retries.
+# Default is 0 (infinite retry count). (integer value)
+# Deprecated group/name - [DEFAULT]/rabbit_max_retries
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+#rabbit_max_retries = 0
+
+# Try to use HA queues in RabbitMQ (x-ha-policy: all). If you
+# change this option, you must wipe the RabbitMQ database. In
+# RabbitMQ 3.0, queue mirroring is no longer controlled by the
+# x-ha-policy argument when declaring a queue. If you just
+# want to make sure that all queues (except those with auto-
+# generated names) are mirrored across all nodes, run:
+# "rabbitmqctl set_policy HA '^(?!amq\.).*' '{"ha-mode":
+# "all"}' " (boolean value)
+# Deprecated group/name - [DEFAULT]/rabbit_ha_queues
+#rabbit_ha_queues = false
+
+# Positive integer representing duration in seconds for queue
+# TTL (x-expires). Queues which are unused for the duration of
+# the TTL are automatically deleted. The parameter affects
+# only reply and fanout queues. (integer value)
+# Minimum value: 1
+#rabbit_transient_queues_ttl = 1800
+
+# Specifies the number of messages to prefetch. Setting to
+# zero allows unlimited messages. (integer value)
+#rabbit_qos_prefetch_count = 0
+
+# Number of seconds after which the Rabbit broker is
+# considered down if heartbeat's keep-alive fails (0 disable
+# the heartbeat). EXPERIMENTAL (integer value)
+#heartbeat_timeout_threshold = 60
+
+# How often times during the heartbeat_timeout_threshold we
+# check the heartbeat. (integer value)
+#heartbeat_rate = 2
+
+# Deprecated, use rpc_backend=kombu+memory or rpc_backend=fake
+# (boolean value)
+# Deprecated group/name - [DEFAULT]/fake_rabbit
+#fake_rabbit = false
+
+# Maximum number of channels to allow (integer value)
+#channel_max = <None>
+
+# The maximum byte size for an AMQP frame (integer value)
+#frame_max = <None>
+
+# How often to send heartbeats for consumer's connections
+# (integer value)
+#heartbeat_interval = 3
+
+# Arguments passed to ssl.wrap_socket (dict value)
+#ssl_options = <None>
+
+# Set socket timeout in seconds for connection's socket
+# (floating point value)
+#socket_timeout = 0.25
+
+# Set TCP_USER_TIMEOUT in seconds for connection's socket
+# (floating point value)
+#tcp_user_timeout = 0.25
+
+# Set delay for reconnection to some host which has connection
+# error (floating point value)
+#host_connection_reconnect_delay = 0.25
+
+# Connection factory implementation (string value)
+# Allowed values: new, single, read_write
+#connection_factory = single
+
+# Maximum number of connections to keep queued. (integer
+# value)
+#pool_max_size = 30
+
+# Maximum number of connections to create above
+# `pool_max_size`. (integer value)
+#pool_max_overflow = 0
+
+# Default number of seconds to wait for a connections to
+# available (integer value)
+#pool_timeout = 30
+
+# Lifetime of a connection (since creation) in seconds or None
+# for no recycling. Expired connections are closed on acquire.
+# (integer value)
+#pool_recycle = 600
+
+# Threshold at which inactive (since release) connections are
+# considered stale in seconds or None for no staleness. Stale
+# connections are closed on acquire. (integer value)
+#pool_stale = 60
+
+# Default serialization mechanism for
+# serializing/deserializing outgoing/incoming messages (string
+# value)
+# Allowed values: json, msgpack
+#default_serializer_type = json
+
+# Persist notification messages. (boolean value)
+#notification_persistence = false
+
+# Exchange name for sending notifications (string value)
+#default_notification_exchange = ${control_exchange}_notification
+
+# Max number of not acknowledged message which RabbitMQ can
+# send to notification listener. (integer value)
+#notification_listener_prefetch_count = 100
+
+# Reconnecting retry count in case of connectivity problem
+# during sending notification, -1 means infinite retry.
+# (integer value)
+#default_notification_retry_attempts = -1
+
+# Reconnecting retry delay in case of connectivity problem
+# during sending notification message (floating point value)
+#notification_retry_delay = 0.25
+
+# Time to live for rpc queues without consumers in seconds.
+# (integer value)
+#rpc_queue_expiration = 60
+
+# Exchange name for sending RPC messages (string value)
+#default_rpc_exchange = ${control_exchange}_rpc
+
+# Exchange name for receiving RPC replies (string value)
+#rpc_reply_exchange = ${control_exchange}_rpc_reply
+
+# Max number of not acknowledged message which RabbitMQ can
+# send to rpc listener. (integer value)
+#rpc_listener_prefetch_count = 100
+
+# Max number of not acknowledged message which RabbitMQ can
+# send to rpc reply listener. (integer value)
+#rpc_reply_listener_prefetch_count = 100
+
+# Reconnecting retry count in case of connectivity problem
+# during sending reply. -1 means infinite retry during
+# rpc_timeout (integer value)
+#rpc_reply_retry_attempts = -1
+
+# Reconnecting retry delay in case of connectivity problem
+# during sending reply. (floating point value)
+#rpc_reply_retry_delay = 0.25
+
+# Reconnecting retry count in case of connectivity problem
+# during sending RPC message, -1 means infinite retry. If
+# actual retry attempts in not 0 the rpc request could be
+# processed more than one time (integer value)
+#default_rpc_retry_attempts = -1
+
+# Reconnecting retry delay in case of connectivity problem
+# during sending RPC message (floating point value)
+#rpc_retry_delay = 0.25
+
+
+[oslo_messaging_zmq]
+
+#
+# From oslo.messaging
+#
+
+# ZeroMQ bind address. Should be a wildcard (*), an ethernet
+# interface, or IP. The "host" option should point or resolve
+# to this address. (string value)
+# Deprecated group/name - [DEFAULT]/rpc_zmq_bind_address
+#rpc_zmq_bind_address = *
+
+# MatchMaker driver. (string value)
+# Allowed values: redis, sentinel, dummy
+# Deprecated group/name - [DEFAULT]/rpc_zmq_matchmaker
+#rpc_zmq_matchmaker = redis
+
+# Number of ZeroMQ contexts, defaults to 1. (integer value)
+# Deprecated group/name - [DEFAULT]/rpc_zmq_contexts
+#rpc_zmq_contexts = 1
+
+# Maximum number of ingress messages to locally buffer per
+# topic. Default is unlimited. (integer value)
+# Deprecated group/name - [DEFAULT]/rpc_zmq_topic_backlog
+#rpc_zmq_topic_backlog = <None>
+
+# Directory for holding IPC sockets. (string value)
+# Deprecated group/name - [DEFAULT]/rpc_zmq_ipc_dir
+#rpc_zmq_ipc_dir = /var/run/openstack
+
+# Name of this node. Must be a valid hostname, FQDN, or IP
+# address. Must match "host" option, if running Nova. (string
+# value)
+# Deprecated group/name - [DEFAULT]/rpc_zmq_host
+#rpc_zmq_host = localhost
+
+# Number of seconds to wait before all pending messages will
+# be sent after closing a socket. The default value of -1
+# specifies an infinite linger period. The value of 0
+# specifies no linger period. Pending messages shall be
+# discarded immediately when the socket is closed. Positive
+# values specify an upper bound for the linger period.
+# (integer value)
+# Deprecated group/name - [DEFAULT]/rpc_cast_timeout
+#zmq_linger = -1
+
+# The default number of seconds that poll should wait. Poll
+# raises timeout exception when timeout expired. (integer
+# value)
+# Deprecated group/name - [DEFAULT]/rpc_poll_timeout
+#rpc_poll_timeout = 1
+
+# Expiration timeout in seconds of a name service record about
+# existing target ( < 0 means no timeout). (integer value)
+# Deprecated group/name - [DEFAULT]/zmq_target_expire
+#zmq_target_expire = 300
+
+# Update period in seconds of a name service record about
+# existing target. (integer value)
+# Deprecated group/name - [DEFAULT]/zmq_target_update
+#zmq_target_update = 180
+
+# Use PUB/SUB pattern for fanout methods. PUB/SUB always uses
+# proxy. (boolean value)
+# Deprecated group/name - [DEFAULT]/use_pub_sub
+#use_pub_sub = false
+
+# Use ROUTER remote proxy. (boolean value)
+# Deprecated group/name - [DEFAULT]/use_router_proxy
+#use_router_proxy = false
+
+# This option makes direct connections dynamic or static. It
+# makes sense only with use_router_proxy=False which means to
+# use direct connections for direct message types (ignored
+# otherwise). (boolean value)
+#use_dynamic_connections = false
+
+# How many additional connections to a host will be made for
+# failover reasons. This option is actual only in dynamic
+# connections mode. (integer value)
+#zmq_failover_connections = 2
+
+# Minimal port number for random ports range. (port value)
+# Minimum value: 0
+# Maximum value: 65535
+# Deprecated group/name - [DEFAULT]/rpc_zmq_min_port
+#rpc_zmq_min_port = 49153
+
+# Maximal port number for random ports range. (integer value)
+# Minimum value: 1
+# Maximum value: 65536
+# Deprecated group/name - [DEFAULT]/rpc_zmq_max_port
+#rpc_zmq_max_port = 65536
+
+# Number of retries to find free port number before fail with
+# ZMQBindError. (integer value)
+# Deprecated group/name - [DEFAULT]/rpc_zmq_bind_port_retries
+#rpc_zmq_bind_port_retries = 100
+
+# Default serialization mechanism for
+# serializing/deserializing outgoing/incoming messages (string
+# value)
+# Allowed values: json, msgpack
+# Deprecated group/name - [DEFAULT]/rpc_zmq_serialization
+#rpc_zmq_serialization = json
+
+# This option configures round-robin mode in zmq socket. True
+# means not keeping a queue when server side disconnects.
+# False means to keep queue and messages even if server is
+# disconnected, when the server appears we send all
+# accumulated messages to it. (boolean value)
+#zmq_immediate = true
+
+# Enable/disable TCP keepalive (KA) mechanism. The default
+# value of -1 (or any other negative value) means to skip any
+# overrides and leave it to OS default; 0 and 1 (or any other
+# positive value) mean to disable and enable the option
+# respectively. (integer value)
+#zmq_tcp_keepalive = -1
+
+# The duration between two keepalive transmissions in idle
+# condition. The unit is platform dependent, for example,
+# seconds in Linux, milliseconds in Windows etc. The default
+# value of -1 (or any other negative value and 0) means to
+# skip any overrides and leave it to OS default. (integer
+# value)
+#zmq_tcp_keepalive_idle = -1
+
+# The number of retransmissions to be carried out before
+# declaring that remote end is not available. The default
+# value of -1 (or any other negative value and 0) means to
+# skip any overrides and leave it to OS default. (integer
+# value)
+#zmq_tcp_keepalive_cnt = -1
+
+# The duration between two successive keepalive
+# retransmissions, if acknowledgement to the previous
+# keepalive transmission is not received. The unit is platform
+# dependent, for example, seconds in Linux, milliseconds in
+# Windows etc. The default value of -1 (or any other negative
+# value and 0) means to skip any overrides and leave it to OS
+# default. (integer value)
+#zmq_tcp_keepalive_intvl = -1
+
+# Maximum number of (green) threads to work concurrently.
+# (integer value)
+#rpc_thread_pool_size = 100
+
+# Expiration timeout in seconds of a sent/received message
+# after which it is not tracked anymore by a client/server.
+# (integer value)
+#rpc_message_ttl = 300
+
+# Wait for message acknowledgements from receivers. This
+# mechanism works only via proxy without PUB/SUB. (boolean
+# value)
+#rpc_use_acks = false
+
+# Number of seconds to wait for an ack from a cast/call. After
+# each retry attempt this timeout is multiplied by some
+# specified multiplier. (integer value)
+#rpc_ack_timeout_base = 15
+
+# Number to multiply base ack timeout by after each retry
+# attempt. (integer value)
+#rpc_ack_timeout_multiplier = 2
+
+# Default number of message sending attempts in case of any
+# problems occurred: positive value N means at most N retries,
+# 0 means no retries, None or -1 (or any other negative
+# values) mean to retry forever. This option is used only if
+# acknowledgments are enabled. (integer value)
+#rpc_retry_attempts = 3
+
+# List of publisher hosts SubConsumer can subscribe on. This
+# option has higher priority then the default publishers list
+# taken from the matchmaker. (list value)
+#subscribe_on =
+
+
+[oslo_policy]
+
+#
+# From oslo.policy
+#
+
+# The file that defines policies. (string value)
+# Deprecated group/name - [DEFAULT]/policy_file
+#policy_file = policy.json
+
+# Default rule. Enforced when a requested rule is not found.
+# (string value)
+# Deprecated group/name - [DEFAULT]/policy_default_rule
+#policy_default_rule = default
+
+# Directories where policy configuration files are stored.
+# They can be relative to any directory in the search path
+# defined by the config_dir option, or absolute paths. The
+# file defined by policy_file must exist for these directories
+# to be searched. Missing or empty directories are ignored.
+# (multi valued)
+# Deprecated group/name - [DEFAULT]/policy_dirs
+#policy_dirs = policy.d
+
+
+[pxe]
+
+#
+# From ironic
+#
+
+# Additional append parameters for baremetal PXE boot. (string
+# value)
+#pxe_append_params = nofb nomodeset vga=normal
+
+# Default file system format for ephemeral partition, if one
+# is created. (string value)
+#default_ephemeral_format = ext4
+
+# On the ironic-conductor node, directory where images are
+# stored on disk. (string value)
+#images_path = /var/lib/ironic/images/
+
+# On the ironic-conductor node, directory where master
+# instance images are stored on disk. Setting to <None>
+# disables image caching. (string value)
+#instance_master_path = /var/lib/ironic/master_images
+
+# Maximum size (in MiB) of cache for master images, including
+# those in use. (integer value)
+#image_cache_size = 20480
+
+# Maximum TTL (in minutes) for old master images in cache.
+# (integer value)
+#image_cache_ttl = 10080
+
+# On ironic-conductor node, template file for PXE
+# configuration. (string value)
+{%- if conductor.get('pxe_config_template') %}
+pxe_config_template = {{ conductor.pxe_config_template }}
+{%- else %}
+#pxe_config_template = $pybasedir/drivers/modules/pxe_common.template
+{%- endif %}
+
+# On ironic-conductor node, template file for PXE
+# configuration for UEFI boot loader. (string value)
+#uefi_pxe_config_template = $pybasedir/drivers/modules/pxe_grub_common.template
+
+# On ironic-conductor node, template file for PXE
+# configuration per node architecture. For example:
+# aarch64:/opt/share/grubaa64_pxe_common.template (dict value)
+#pxe_config_template_by_arch =
+
+# IP address of ironic-conductor node's TFTP server. (string
+# value)
+#tftp_server = $my_ip
+
+# ironic-conductor node's TFTP root path. The ironic-conductor
+# must have read/write access to this path. (string value)
+{%- if conductor.get('tftp_root') %}
+tftp_root = {{ conductor.tftp_root }}
+{%- else %}
+#tftp_root = /tftpboot
+{%- endif %}
+
+# On ironic-conductor node, directory where master TFTP images
+# are stored on disk. Setting to <None> disables image
+# caching. (string value)
+{%- if conductor.get('tftp_master_path') %}
+tftp_master_path = {{ conductor.tftp_master_path }}
+{%- else %}
+#tftp_master_path = /tftpboot/master_images
+{%- endif %}
+
+# Bootfile DHCP parameter. (string value)
+{%- if conductor.get('pxe_bootfile_name') %}
+pxe_bootfile_name = {{ conductor.pxe_bootfile_name }}
+{%- else %}
+#pxe_bootfile_name = pxelinux.0
+{%- endif %}
+
+# Bootfile DHCP parameter for UEFI boot mode. (string value)
+#uefi_pxe_bootfile_name = bootx64.efi
+
+# Bootfile DHCP parameter per node architecture. For example:
+# aarch64:grubaa64.efi (dict value)
+#pxe_bootfile_name_by_arch =
+
+# Enable iPXE boot. (boolean value)
+{%- if conductor.ipxe_enabled is defined %}
+ipxe_enabled = {{ conductor.ipxe_enabled }}
+{%- else %}
+#ipxe_enabled = false
+{%- endif %}
+
+# On ironic-conductor node, the path to the main iPXE script
+# file. (string value)
+#ipxe_boot_script = $pybasedir/drivers/modules/boot.ipxe
+
+# Timeout value (in seconds) for downloading an image via
+# iPXE. Defaults to 0 (no timeout) (integer value)
+#ipxe_timeout = 0
+
+# The IP version that will be used for PXE booting. Defaults
+# to 4. EXPERIMENTAL (string value)
+# Allowed values: 4, 6
+#ip_version = 4
+
+# Download deploy images directly from swift using temporary
+# URLs. If set to false (default), images are downloaded to
+# the ironic-conductor node and served over its local HTTP
+# server. Applicable only when 'ipxe_enabled' option is set to
+# true. (boolean value)
+#ipxe_use_swift = false
+
+
+[service_catalog]
+
+#
+# From ironic
+#
+
+# Authentication URL (string value)
+{%- if ironic.get('identity', {}).get('engine') == 'keystone' %}
+auth_url = {{ ironic.identity.protocol }}://{{ ironic.identity.host }}:{{ ironic.identity.port }}/identity
+{%- else %}
+#auth_url = <None>
+{%- endif %}
+
+# Authentication type to load (string value)
+# Deprecated group/name - [service_catalog]/auth_plugin
+{%- if ironic.get('identity', {}).get('auth_type') %}
+auth_type = {{ ironic.identity.auth_type }}
+{%- else %}
+#auth_type = <None>
+{%- endif %}
+
+# PEM encoded Certificate Authority to use when verifying
+# HTTPs connections. (string value)
+#cafile = <None>
+
+# PEM encoded client certificate cert file (string value)
+#certfile = <None>
+
+# Optional domain ID to use with v3 and v2 parameters. It will
+# be used for both the user and project domain in v3 and
+# ignored in v2 authentication. (string value)
+{%- if ironic.get('identity', {}).get('default_domain_id') %}
+default_domain_id = {{ ironic.identity.default_domain_id }}
+{%- else %}
+#default_domain_id = <None>
+{%- endif %}
+
+# Optional domain name to use with v3 API and v2 parameters.
+# It will be used for both the user and project domain in v3
+# and ignored in v2 authentication. (string value)
+{%- if ironic.get('identity', {}).get('default_domain_name') %}
+default_domain_name = {{ ironic.identity.default_domain_name }}
+{%- else %}
+#default_domain_name = <None>
+{%- endif %}
+
+# Domain ID to scope to (string value)
+{%- if ironic.get('identity', {}).get('domain_id') %}
+domain_id = {{ ironic.identity.domain_id }}
+{%- else %}
+#domain_id = <None>
+{%- endif %}
+
+# Domain name to scope to (string value)
+{%- if ironic.get('identity', {}).get('domain_name') %}
+domain_name = {{ ironic.identity.domain_name }}
+{%- else %}
+#domain_name = <None>
+{%- endif %}
+
+# Verify HTTPS connections. (boolean value)
+#insecure = false
+
+# PEM encoded client certificate key file (string value)
+#keyfile = <None>
+
+# User's password (string value)
+{%- if ironic.get('identity', {}).get('password') %}
+password = {{ ironic.identity.password }}
+{%- else %}
+#password = <None>
+{%- endif %}
+
+# Domain ID containing project (string value)
+{%- if ironic.get('identity', {}).get('project_domain_id') %}
+project_domain_id = {{ ironic.identity.project_domain_id }}
+{%- else %}
+#project_domain_id = <None>
+{%- endif %}
+
+# Domain name containing project (string value)
+{%- if ironic.get('identity', {}).get('project_domain_name') %}
+project_domain_name = {{ ironic.identity.project_domain_name }}
+{%- else %}
+#project_domain_name = <None>
+{%- endif %}
+
+# Project ID to scope to (string value)
+# Deprecated group/name - [service_catalog]/tenant-id
+{%- if ironic.get('identity', {}).get('project_id') %}
+project_id = {{ ironic.identity.project_id }}
+{%- else %}
+#project_id = <None>
+{%- endif %}
+
+# Project name to scope to (string value)
+# Deprecated group/name - [service_catalog]/tenant-name
+{%- if ironic.get('identity', {}).get('project_name') %}
+project_name = {{ ironic.identity.project_name }}
+{%- else %}
+#project_name = <None>
+{%- endif %}
+
+# Tenant ID (string value)
+{%- if ironic.get('identity', {}).get('tenant_id') %}
+tenant_id = {{ ironic.identity.tenant_id }}
+{%- else %}
+#tenant_id = <None>
+{%- endif %}
+
+# Tenant Name (string value)
+{%- if ironic.get('identity', {}).get('tenant_name') %}
+tenant_name = {{ ironic.identity.tenant_name }}
+{%- else %}
+#tenant_name = <None>
+{%- endif %}
+
+# Timeout value for http requests (integer value)
+#timeout = <None>
+
+# Trust ID (string value)
+#trust_id = <None>
+
+# User's domain id (string value)
+{%- if ironic.get('identity', {}).get('user_domain_id') %}
+user_domain_id = {{ ironic.identity.user_domain_id }}
+{%- else %}
+#user_domain_id = <None>
+{%- endif %}
+
+# User's domain name (string value)
+{%- if ironic.get('identity', {}).get('user_domain_name') %}
+user_domain_name = {{ ironic.identity.user_domain_name }}
+{%- else %}
+#user_domain_name = <None>
+{%- endif %}
+
+# User id (string value)
+{%- if ironic.get('identity', {}).get('user_id')  %}
+user_id = {{ ironic.identity.user_id }}
+{%- else %}
+#user_id = <None>
+{%- endif %}
+
+# Username (string value)
+# Deprecated group/name - [service_catalog]/user-name
+{%- if ironic.get('identity', {}).get('user') %}
+username = {{ ironic.identity.user }}
+{%- else %}
+#username = <None>
+{%- endif %}
+
+
+[snmp]
+
+#
+# From ironic
+#
+
+# Seconds to wait for power action to be completed (integer
+# value)
+#power_timeout = 10
+
+# Time (in seconds) to sleep between when rebooting (powering
+# off and on again) (integer value)
+# Minimum value: 0
+#reboot_delay = 0
+
+
+[ssh]
+
+#
+# From ironic
+#
+
+# libvirt URI. (string value)
+#libvirt_uri = qemu:///system
+
+# Number of attempts to try to get VM name used by the host
+# that corresponds to a node's MAC address. (integer value)
+#get_vm_name_attempts = 3
+
+# Number of seconds to wait between attempts to get VM name
+# used by the host that corresponds to a node's MAC address.
+# (integer value)
+#get_vm_name_retry_interval = 3
+
+
+[ssl]
+
+#
+# From oslo.service.sslutils
+#
+
+# CA certificate file to use to verify connecting clients.
+# (string value)
+# Deprecated group/name - [DEFAULT]/ssl_ca_file
+#ca_file = <None>
+
+# Certificate file to use when starting the server securely.
+# (string value)
+# Deprecated group/name - [DEFAULT]/ssl_cert_file
+#cert_file = <None>
+
+# Private key file to use when starting the server securely.
+# (string value)
+# Deprecated group/name - [DEFAULT]/ssl_key_file
+#key_file = <None>
+
+# SSL version to use (valid only if SSL enabled). Valid values
+# are TLSv1 and SSLv23. SSLv2, SSLv3, TLSv1_1, and TLSv1_2 may
+# be available on some distributions. (string value)
+#version = <None>
+
+# Sets the list of available ciphers. value should be a string
+# in the OpenSSL cipher list format. (string value)
+#ciphers = <None>
+
+
+[swift]
+
+#
+# From ironic
+#
+
+# Authentication URL (string value)
+#auth_url = <None>
+
+# Authentication type to load (string value)
+# Deprecated group/name - [swift]/auth_plugin
+#auth_type = <None>
+
+# PEM encoded Certificate Authority to use when verifying
+# HTTPs connections. (string value)
+#cafile = <None>
+
+# PEM encoded client certificate cert file (string value)
+#certfile = <None>
+
+# Optional domain ID to use with v3 and v2 parameters. It will
+# be used for both the user and project domain in v3 and
+# ignored in v2 authentication. (string value)
+#default_domain_id = <None>
+
+# Optional domain name to use with v3 API and v2 parameters.
+# It will be used for both the user and project domain in v3
+# and ignored in v2 authentication. (string value)
+#default_domain_name = <None>
+
+# Domain ID to scope to (string value)
+#domain_id = <None>
+
+# Domain name to scope to (string value)
+#domain_name = <None>
+
+# Verify HTTPS connections. (boolean value)
+#insecure = false
+
+# PEM encoded client certificate key file (string value)
+#keyfile = <None>
+
+# User's password (string value)
+#password = <None>
+
+# Domain ID containing project (string value)
+#project_domain_id = <None>
+
+# Domain name containing project (string value)
+#project_domain_name = <None>
+
+# Project ID to scope to (string value)
+# Deprecated group/name - [swift]/tenant-id
+#project_id = <None>
+
+# Project name to scope to (string value)
+# Deprecated group/name - [swift]/tenant-name
+#project_name = <None>
+
+# Maximum number of times to retry a Swift request, before
+# failing. (integer value)
+#swift_max_retries = 2
+
+# Tenant ID (string value)
+#tenant_id = <None>
+
+# Tenant Name (string value)
+#tenant_name = <None>
+
+# Timeout value for http requests (integer value)
+#timeout = <None>
+
+# Trust ID (string value)
+#trust_id = <None>
+
+# User's domain id (string value)
+#user_domain_id = <None>
+
+# User's domain name (string value)
+#user_domain_name = <None>
+
+# User id (string value)
+#user_id = <None>
+
+# Username (string value)
+# Deprecated group/name - [swift]/user-name
+#username = <None>
diff --git a/ironic/init.sls b/ironic/init.sls
new file mode 100644
index 0000000..ccf1fbc
--- /dev/null
+++ b/ironic/init.sls
@@ -0,0 +1,12 @@
+{%- if pillar.ironic is defined %}
+include:
+{%- if pillar.ironic.api is defined %}
+- ironic.api
+{% endif %}
+{%- if pillar.ironic.conductor is defined %}
+- ironic.conductor
+{%- endif %}
+{%- if pillar.ironic.client is defined %}
+- ironic.client
+{%- endif %}
+{%- endif %}
diff --git a/ironic/map.jinja b/ironic/map.jinja
new file mode 100644
index 0000000..5e17c9b
--- /dev/null
+++ b/ironic/map.jinja
@@ -0,0 +1,35 @@
+{% set api = salt['grains.filter_by']({
+    'Common': {
+        'pkgs': ['ironic-api'],
+        'service': 'ironic-api',
+    }
+}, base='Common', merge=pillar.ironic.get('api', {})) %}
+
+{% set conductor = salt['grains.filter_by']({
+    'Common': {
+        'service': 'ironic-conductor',
+        'ipxe_rom_files': ['undionly.kpxe', 'ipxe.efi'],
+    },
+    'Debian': {
+        'pkgs': ['ipmitool', 'ironic-conductor', 'tftpd-hpa', 'syslinux-common', 'pxelinux', 'ipxe'],
+        'pxelinux_path': '/usr/lib/PXELINUX',
+        'syslinux_files': ['chain.c32', 'libcom32.c32', 'libutil.c32'],
+        'syslinux_path': '/usr/lib/syslinux/modules/bios',
+        'ipxe_rom_path': '/usr/lib/ipxe',
+    },
+    'RedHat': {
+        'pkgs': ['ipmitool', 'ironic-conductor', 'tftp-server', 'syslinux-extlinux', 'ipxe-bootimgs'],
+        'pxelinux_path': '/usr/share/syslinux',
+        'syslinux_files': ['chain.c32'],
+        'syslinux_path': '/usr/share/syslinux',
+        'ipxe_rom_path': '/usr/share/ipxe',
+    },
+}, base='Common', merge=pillar.ironic.get('conductor', {})) %}
+
+{% set client = salt['grains.filter_by']({
+    'Common': {
+      'pkgs': ['python-ironicclient'],
+    },
+}, base='Common', merge=pillar.ironic.get('client', {})) %}
+
+{% set ironic = pillar.get('ironic', {}) %}
diff --git a/ironic/meta/sensu.yml b/ironic/meta/sensu.yml
new file mode 100644
index 0000000..2722e6a
--- /dev/null
+++ b/ironic/meta/sensu.yml
@@ -0,0 +1,8 @@
+# Sample check
+check:
+  local_ironic_proc:
+    command: "PATH=$PATH:/usr/lib64/nagios/plugins:/usr/lib/nagios/plugins check_procs -C ironic -u ironic -c 1:1"
+    interval: 60
+    occurrences: 1
+    subscribers:
+    - local-ironic-server
diff --git a/ironic/meta/sphinx.yml b/ironic/meta/sphinx.yml
new file mode 100644
index 0000000..07e1c68
--- /dev/null
+++ b/ironic/meta/sphinx.yml
@@ -0,0 +1,12 @@
+{%- from "ironic/map.jinja" import server with context %}
+# Fill in documentation details
+doc:
+  name: ironic
+  description: Some service info
+  role:
+    server:
+      name: server
+      param:
+        some_param:
+          name: "Some name"
+          value: "some value"
diff --git a/metadata.yml b/metadata.yml
new file mode 100644
index 0000000..1a9ccd6
--- /dev/null
+++ b/metadata.yml
@@ -0,0 +1,3 @@
+name: "ironic"
+version: "0.1"
+source: "https://github.com/salt-formulas/salt-formula-ironic"
diff --git a/metadata/service/api/cluster.yml b/metadata/service/api/cluster.yml
new file mode 100644
index 0000000..c6a5002
--- /dev/null
+++ b/metadata/service/api/cluster.yml
@@ -0,0 +1,37 @@
+applications:
+  - ironic
+parameters:
+  ironic:
+    api:
+      enabled: true
+      version: ${_param:ironic_version}
+      bind:
+        address: ${_param:cluster_local_address}
+        port: 6385
+        protocol: 'http'
+      message_queue:
+        engine: rabbitmq
+        port: 5672
+        user: openstack
+        password: ${_param:rabbitmq_openstack_password}
+        virtual_host: '/openstack'
+        host: ${_param:cluster_vip_address}
+      database:
+        engine: mysql
+        host: ${_param:cluster_vip_address}
+        port: 3306
+        name: ironic
+        user: ironic
+        password: ${_param:mysql_ironic_password}
+      identity:
+        engine: keystone
+        region: RegionOne
+        host: ${_param:cluster_vip_address}
+        port: 35357
+        user: ironic
+        password: ${_param:keystone_ironic_password}
+        tenant: service
+        auth_type: password
+        user_domain_id: default
+        project_domain_id: default
+        protocol: 'http'
diff --git a/metadata/service/api/single.yml b/metadata/service/api/single.yml
new file mode 100644
index 0000000..936f250
--- /dev/null
+++ b/metadata/service/api/single.yml
@@ -0,0 +1,37 @@
+applications:
+  - ironic
+parameters:
+  ironic:
+    api:
+      enabled: true
+      version: ${_param:ironic_version}
+      bind:
+        address: ${_param:single_address}
+        port: 6385
+        protocol: 'http'
+      message_queue:
+        engine: rabbitmq
+        port: 5672
+        user: openstack
+        password: ${_param:rabbitmq_openstack_password}
+        virtual_host: '/openstack'
+        host: ${_param:single_address}
+      database:
+        engine: mysql
+        host: ${_param:single_address}
+        port: 3306
+        name: ironic
+        user: ironic
+        password: ${_param:mysql_ironic_password}
+      identity:
+        engine: keystone
+        region: RegionOne
+        host: ${_param:single_address}
+        port: 35357
+        user: ironic
+        password: ${_param:keystone_ironic_password}
+        tenant: service
+        auth_type: password
+        user_domain_id: default
+        project_domain_id: default
+        protocol: 'http'
diff --git a/metadata/service/conductor/cluster.yml b/metadata/service/conductor/cluster.yml
new file mode 100644
index 0000000..49360f7
--- /dev/null
+++ b/metadata/service/conductor/cluster.yml
@@ -0,0 +1,52 @@
+applications:
+  - ironic
+parameters:
+  ironic:
+    conductor:
+      enabled: true
+      version: ${_param:ironic_version}
+      message_queue:
+        engine: rabbitmq
+        port: 5672
+        user: openstack
+        password: ${_param:rabbitmq_openstack_password}
+        virtual_host: '/openstack'
+        host: ${_param:cluster_vip_address}
+      database:
+        engine: mysql
+        host: ${_param:cluster_vip_address}
+        port: 3306
+        name: ironic
+        user: ironic
+        password: ${_param:mysql_ironic_password}
+      identity:
+        engine: keystone
+        region: RegionOne
+        host: ${_param:cluster_vip_address}
+        port: 35357
+        user: ironic
+        password: ${_param:keystone_ironic_password}
+        tenant: service
+        auth_type: password
+        user_domain_id: default
+        project_domain_id: default
+        protocol: 'http'
+      neutron:
+        cleaning_network: baremetal
+        provisioning_network: baremetal
+        project_domain_id: ${ironic:conductor:identity:project_domain_id}
+        user_domain_id: ${ironic:conductor:identity:user_domain_id}
+        password: ${ironic:conductor:identity:password}
+        username: ${ironic:conductor:identity:user}
+      enabled_drivers:
+        - agent_ipmitool
+        - fake
+      automated_clean: false
+      http_url: 'http://${_param:cluster_vip_address}'
+      api_url: 'http://${_param:cluster_vip_address}:6385'
+      pxe_config_template: '$pybasedir/drivers/modules/ipxe_config.template'
+      pxe_bootfile_name: '/undionly.kpxe'
+      ipxe_enabled: true
+      http_root: '/var/www/httproot'
+      tftp_root: '/var/lib/tftpboot'
+      tftp_master_path: '/var/lib/tftpboot/master_images'
diff --git a/metadata/service/conductor/single.yml b/metadata/service/conductor/single.yml
new file mode 100644
index 0000000..d88ff77
--- /dev/null
+++ b/metadata/service/conductor/single.yml
@@ -0,0 +1,53 @@
+applications:
+  - ironic
+parameters:
+  ironic:
+    conductor:
+      enabled: true
+      version: ${_param:ironic_version}
+      message_queue:
+        engine: rabbitmq
+        port: 5672
+        user: openstack
+        password: ${_param:rabbitmq_openstack_password}
+        virtual_host: '/openstack'
+        host: ${_param:single_address}
+      database:
+        engine: mysql
+        host: ${_param:single_address}
+        port: 3306
+        name: ironic
+        user: ironic
+        password: ${_param:mysql_ironic_password}
+      identity:
+        engine: keystone
+        region: RegionOne
+        host: ${_param:single_address}
+        port: 35357
+        user: ironic
+        password: ${_param:keystone_ironic_password}
+        tenant: service
+        auth_type: password
+        user_domain_id: default
+        project_domain_id: default
+        protocol: 'http'
+      neutron:
+        cleaning_network: baremetal
+        provisioning_network: baremetal
+        project_domain_id: ${ironic:conductor:identity:project_domain_id}
+        user_domain_id: ${ironic:conductor:identity:user_domain_id}
+        password: ${ironic:conductor:identity:password}
+        username: ${ironic:conductor:identity:user}
+
+      enabled_drivers:
+        - agent_ipmitool
+        - fake
+      automated_clean: false
+      http_url: 'http://${_param:single_address}'
+      api_url: 'http://${_param:single_address}:6385'
+      pxe_config_template: '$pybasedir/drivers/modules/ipxe_config.template'
+      pxe_bootfile_name: '/undionly.kpxe'
+      ipxe_enabled: true
+      http_root: '/var/www/httproot'
+      tftp_root: '/var/lib/tftpboot'
+      tftp_master_path: '/var/lib/tftpboot/master_images'
diff --git a/metadata/service/support.yml b/metadata/service/support.yml
new file mode 100644
index 0000000..f6446d5
--- /dev/null
+++ b/metadata/service/support.yml
@@ -0,0 +1,11 @@
+parameters:
+  ironic:
+    _support:
+      collectd:
+        enabled: false
+      heka:
+        enabled: false
+      sensu:
+        enabled: true
+      sphinx:
+        enabled: true
diff --git a/tests/pillar/api_single.sls b/tests/pillar/api_single.sls
new file mode 100644
index 0000000..741d92b
--- /dev/null
+++ b/tests/pillar/api_single.sls
@@ -0,0 +1,23 @@
+ironic:
+  api:
+    enabled: true
+    version: mitaka
+    bind:
+      address: '0.0.0.0'
+      port: 6385
+    message_queue:
+      engine: rabbitmq
+      host: '127.0.0.1'
+      port: 5672
+      user: openstack
+      password: workshop
+      virtual_host: '/openstack'
+    database:
+      engine: mysql
+      host: '127.0.0.1'
+      port: 3306
+      name: ironic
+      user: ironic
+      password: workshop
+    identity:
+      engine: 'noauth'
diff --git a/tests/pillar/conductor_single.sls b/tests/pillar/conductor_single.sls
new file mode 100644
index 0000000..616e456
--- /dev/null
+++ b/tests/pillar/conductor_single.sls
@@ -0,0 +1,32 @@
+ironic:
+  conductor:
+    version: ocata
+    enabled: true
+    tftp_root: '/var/lib/tftpboot'
+    message_queue:
+      engine: rabbitmq
+      host: '127.0.0.1'
+      port: 5672
+      user: openstack
+      password: workshop
+      virtual_host: '/openstack'
+    database:
+      engine: mysql
+      host: '127.0.0.1'
+      port: 3306
+      name: ironic
+      user: ironic
+      password: workshop
+    identity:
+      engine: 'noauth'
+    http_root: '/var/www/httproot'
+  tftpd_hpa:
+    server:
+      bind:
+        address: '0.0.0.0'
+        port: 69
+      username: 'ironic'
+      path: ${ironic:conductor:tftp_root}
+      options:
+        - secure
+        - map-file: '${ironic:conductor:tftp_root}/map-file'
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
new file mode 100755
index 0000000..3f42101
--- /dev/null
+++ b/tests/run_tests.sh
@@ -0,0 +1,162 @@
+#!/usr/bin/env bash
+
+set -e
+[ -n "$DEBUG" ] && set -x
+
+CURDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+METADATA=${CURDIR}/../metadata.yml
+FORMULA_NAME=$(cat $METADATA | python -c "import sys,yaml; print yaml.load(sys.stdin)['name']")
+
+## Overrideable parameters
+PILLARDIR=${PILLARDIR:-${CURDIR}/pillar}
+BUILDDIR=${BUILDDIR:-${CURDIR}/build}
+VENV_DIR=${VENV_DIR:-${BUILDDIR}/virtualenv}
+DEPSDIR=${BUILDDIR}/deps
+
+SALT_FILE_DIR=${SALT_FILE_DIR:-${BUILDDIR}/file_root}
+SALT_PILLAR_DIR=${SALT_PILLAR_DIR:-${BUILDDIR}/pillar_root}
+SALT_CONFIG_DIR=${SALT_CONFIG_DIR:-${BUILDDIR}/salt}
+SALT_CACHE_DIR=${SALT_CACHE_DIR:-${SALT_CONFIG_DIR}/cache}
+
+SALT_OPTS="${SALT_OPTS} --retcode-passthrough --local -c ${SALT_CONFIG_DIR}"
+
+if [ "x${SALT_VERSION}" != "x" ]; then
+    PIP_SALT_VERSION="==${SALT_VERSION}"
+fi
+
+## Functions
+log_info() {
+    echo "[INFO] $*"
+}
+
+log_err() {
+    echo "[ERROR] $*" >&2
+}
+
+setup_virtualenv() {
+    log_info "Setting up Python virtualenv"
+    virtualenv $VENV_DIR
+    source ${VENV_DIR}/bin/activate
+    pip install salt${PIP_SALT_VERSION}
+}
+
+setup_pillar() {
+    [ ! -d ${SALT_PILLAR_DIR} ] && mkdir -p ${SALT_PILLAR_DIR}
+    echo "base:" > ${SALT_PILLAR_DIR}/top.sls
+    for pillar in ${PILLARDIR}/*; do
+        state_name=$(basename ${pillar%.sls})
+        echo -e "  ${state_name}:\n    - ${state_name}" >> ${SALT_PILLAR_DIR}/top.sls
+    done
+}
+
+setup_salt() {
+    [ ! -d ${SALT_FILE_DIR} ] && mkdir -p ${SALT_FILE_DIR}
+    [ ! -d ${SALT_CONFIG_DIR} ] && mkdir -p ${SALT_CONFIG_DIR}
+    [ ! -d ${SALT_CACHE_DIR} ] && mkdir -p ${SALT_CACHE_DIR}
+
+    echo "base:" > ${SALT_FILE_DIR}/top.sls
+    for pillar in ${PILLARDIR}/*.sls; do
+        state_name=$(basename ${pillar%.sls})
+        echo -e "  ${state_name}:\n    - ${FORMULA_NAME}" >> ${SALT_FILE_DIR}/top.sls
+    done
+
+    cat << EOF > ${SALT_CONFIG_DIR}/minion
+file_client: local
+cachedir: ${SALT_CACHE_DIR}
+verify_env: False
+
+file_roots:
+  base:
+  - ${SALT_FILE_DIR}
+  - ${CURDIR}/..
+  - /usr/share/salt-formulas/env
+
+pillar_roots:
+  base:
+  - ${SALT_PILLAR_DIR}
+  - ${PILLARDIR}
+EOF
+}
+
+fetch_dependency() {
+    dep_name="$(echo $1|cut -d : -f 1)"
+    dep_source="$(echo $1|cut -d : -f 2-)"
+    dep_root="${DEPSDIR}/$(basename $dep_source .git)"
+    dep_metadata="${dep_root}/metadata.yml"
+
+    [ -d /usr/share/salt-formulas/env/${dep_name} ] && log_info "Dependency $dep_name already present in system-wide salt env" && return 0
+    [ -d $dep_root ] && log_info "Dependency $dep_name already fetched" && return 0
+
+    log_info "Fetching dependency $dep_name"
+    [ ! -d ${DEPSDIR} ] && mkdir -p ${DEPSDIR}
+    git clone $dep_source ${DEPSDIR}/$(basename $dep_source .git)
+    ln -s ${dep_root}/${dep_name} ${SALT_FILE_DIR}/${dep_name}
+
+    METADATA="${dep_metadata}" install_dependencies
+}
+
+install_dependencies() {
+    grep -E "^dependencies:" ${METADATA} >/dev/null || return 0
+    (python - | while read dep; do fetch_dependency "$dep"; done) << EOF
+import sys,yaml
+for dep in yaml.load(open('${METADATA}', 'ro'))['dependencies']:
+    print '%s:%s' % (dep["name"], dep["source"])
+EOF
+}
+
+clean() {
+    log_info "Cleaning up ${BUILDDIR}"
+    [ -d ${BUILDDIR} ] && rm -rf ${BUILDDIR} || exit 0
+}
+
+salt_run() {
+    [ -e ${VEN_DIR}/bin/activate ] && source ${VENV_DIR}/bin/activate
+    salt-call ${SALT_OPTS} $*
+}
+
+prepare() {
+    [ -d ${BUILDDIR} ] && mkdir -p ${BUILDDIR}
+
+    which salt-call || setup_virtualenv
+    setup_pillar
+    setup_salt
+    install_dependencies
+}
+
+run() {
+    for pillar in ${PILLARDIR}/*.sls; do
+        state_name=$(basename ${pillar%.sls})
+        salt_run --id=${state_name} state.show_sls ${FORMULA_NAME} || (log_err "Execution of ${FORMULA_NAME}.${state_name} failed"; exit 1)
+    done
+}
+
+_atexit() {
+    RETVAL=$?
+    trap true INT TERM EXIT
+
+    if [ $RETVAL -ne 0 ]; then
+        log_err "Execution failed"
+    else
+        log_info "Execution successful"
+    fi
+    return $RETVAL
+}
+
+## Main
+trap _atexit INT TERM EXIT
+
+case $1 in
+    clean)
+        clean
+        ;;
+    prepare)
+        prepare
+        ;;
+    run)
+        run
+        ;;
+    *)
+        prepare
+        run
+        ;;
+esac