diff --git a/etc/ironic_python_agent/ironic_python_agent.conf.sample b/etc/ironic_python_agent/ironic_python_agent.conf.sample
index 2d34eac65..037965ca4 100644
--- a/etc/ironic_python_agent/ironic_python_agent.conf.sample
+++ b/etc/ironic_python_agent/ironic_python_agent.conf.sample
@@ -1,83 +1,244 @@
 [DEFAULT]
 
 #
-# Options defined in ironic_python_agent.openstack.common.log
+# From ironic-python-agent
 #
 
-# Print debugging output (set logging level to DEBUG instead
-# of default WARNING level). (boolean value)
-#debug=false
+# URL of the Ironic API. Can be supplied as "ipa-api-url"
+# kernel parameter. (string value)
+# Deprecated group/name - [DEFAULT]/api_url
+#api_url = http://127.0.0.1:6385
 
-# Print more verbose output (set logging level to INFO instead
-# of default WARNING level). (boolean value)
-#verbose=false
+# The IP address to listen on. Can be supplied as "ipa-listen-
+# host" kernel parameter. (string value)
+# Deprecated group/name - [DEFAULT]/listen_host
+#listen_host = 0.0.0.0
 
-# Log output to standard error (boolean value)
-#use_stderr=true
+# The port to listen on. Can be supplied as "ipa-listen-port"
+# kernel parameter. (integer value)
+# Deprecated group/name - [DEFAULT]/listen_port
+#listen_port = 9999
 
-# format string to use for log messages with context (string
+# The host to tell Ironic to reply and send commands to. Can
+# be supplied as "ipa-advertise-host" kernel parameter.
+# (string value)
+# Deprecated group/name - [DEFAULT]/advertise_host
+#advertise_host = <None>
+
+# The port to tell Ironic to reply and send commands to. Can
+# be supplied as "ipa-advertise-port" kernel parameter.
+# (integer value)
+# Deprecated group/name - [DEFAULT]/advertise_port
+#advertise_port = 9999
+
+# The number of times to try and automatically determine the
+# agent IPv4 address. Can be supplied as "ipa-ip-lookup-
+# attempts" kernel parameter. (integer value)
+# Deprecated group/name - [DEFAULT]/ip_lookup_attempts
+#ip_lookup_attempts = 3
+
+# The amount of time to sleep between attempts to determine IP
+# address. Can be supplied as "ipa-ip-lookup-timeout" kernel
+# parameter. (integer value)
+# Deprecated group/name - [DEFAULT]/ip_lookup_sleep
+#ip_lookup_sleep = 10
+
+# The interface to use when looking for an IPaddress. Can be
+# supplied as "ipa-network-interface" kernel parameter.
+# (string value)
+# Deprecated group/name - [DEFAULT]/network_interface
+#network_interface = <None>
+
+# The amount of time to retry the initial lookup call to
+# Ironic. After the timeout, the agent will exit with a non-
+# zero exit code. Can be supplied as "ipa-lookup-timeout"
+# kernel parameter. (integer value)
+# Deprecated group/name - [DEFAULT]/lookup_timeout
+#lookup_timeout = 300
+
+# The initial interval for retries on the initial lookup call
+# to Ironic. The interval will be doubled after each failure
+# until timeout is exceeded. Can be supplied as "ipa-lookup-
+# interval" kernel parameter. (integer value)
+# Deprecated group/name - [DEFAULT]/lookup_interval
+#lookup_interval = 1
+
+# The amount of seconds to wait for LLDP packets. Can be
+# supplied as "ipa-lldp-timeout" kernel parameter. (floating
+# point value)
+#lldp_timeout = 30.0
+
+# Whether IPA should attempt to receive LLDP packets for each
+# network interface it discovers in the inventory. Can be
+# supplied as "ipa-collect-lldp" kernel parameter. (boolean
 # value)
-#logging_context_format_string=%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [%(request_id)s %(user)s %(tenant)s] %(instance)s%(message)s
+#collect_lldp = false
 
-# format string to use for log messages without context
-# (string value)
-#logging_default_format_string=%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [-] %(instance)s%(message)s
+# Note: for debugging only. Start the Agent but suppress any
+# calls to Ironic API. Can be supplied as "ipa-standalone"
+# kernel parameter. (boolean value)
+#standalone = false
 
-# data to append to log format when level is DEBUG (string
+# Endpoint of ironic-inspector. If set, hardware inventory
+# will be collected and sent to ironic-inspector on start up.
+# Can be supplied as "ipa-inspection-callback-url" kernel
+# parameter. (string value)
+#inspection_callback_url = <None>
+
+# Comma-separated list of plugins providing additional
+# hardware data for inspection, empty value gives a minimum
+# required set of plugins. Can be supplied as "ipa-inspection-
+# collectors" kernel parameter. (string value)
+#inspection_collectors = default
+
+# Maximum time (in seconds) to wait for the PXE NIC (or all
+# NICs if inspection_dhcp_all_interfaces is True) to get its
+# IP address via DHCP before inspection. Set to 0 to disable
+# waiting completely. Can be supplied as "ipa-inspection-dhcp-
+# wait-timeout" kernel parameter. (integer value)
+#inspection_dhcp_wait_timeout = 60
+
+# Whether to wait for all interfaces to get their IP addresses
+# before inspection. If set to false (the default), only waits
+# for the PXE interface. Can be supplied as "ipa-inspection-
+# dhcp-all-interfaces" kernel parameter. (boolean value)
+#inspection_dhcp_all_interfaces = false
+
+# How much time (in seconds) to wait for hardware to
+# initialize before proceeding with any actions. Can be
+# supplied as "ipa-hardware-initialization-delay" kernel
+# parameter. (integer value)
+#hardware_initialization_delay = 0
+
+# The number of times to try and check to see if at least one
+# suitable disk has appeared in inventory before proceeding
+# with any actions. Can be supplied as "ipa-disk-wait-
+# attempts" kernel parameter. (integer value)
+#disk_wait_attempts = 10
+
+# How much time (in seconds) to wait between attempts to check
+# if at least one suitable disk has appeared in inventory. Can
+# be supplied as "ipa-disk-wait-delay" kernel parameter.
+# (integer value)
+#disk_wait_delay = 3
+
+#
+# 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.
+#debug = false
+
+# DEPRECATED: If set to false, the logging level will be set
+# to WARNING instead of the default INFO level. (boolean
 # value)
-#logging_debug_format_suffix=%(funcName)s %(pathname)s:%(lineno)d
+# This option is deprecated for removal.
+# Its value may be silently ignored in the future.
+#verbose = true
 
-# prefix each line of exception output with this format
+# 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)
-#logging_exception_prefix=%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s
+# Deprecated group/name - [DEFAULT]/logdir
+#log_dir = <None>
 
-# list of logger=LEVEL pairs (list value)
-#default_log_levels=amqplib=WARN,sqlalchemy=WARN,boto=WARN,suds=INFO,keystone=INFO,eventlet.wsgi.server=WARN
+# 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
 
-# publish error events (boolean value)
-#publish_errors=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
 
-# make deprecations fatal (boolean value)
-#fatal_deprecations=false
+# Syslog facility to receive log lines. This option is ignored
+# if log_config_append is set. (string value)
+#syslog_log_facility = LOG_USER
 
-# If an instance is passed with the log message, format it
-# like this (string value)
-#instance_format="[instance: %(uuid)s] "
+# Log output to standard error. This option is ignored if
+# log_config_append is set. (boolean value)
+#use_stderr = false
 
-# If an instance UUID is passed with the log message, format
-# it like this (string value)
-#instance_uuid_format="[instance: %(uuid)s] "
+# 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
 
-# If this option is specified, the logging configuration file
-# specified is used and overrides any other logging options
-# specified. Please see the Python logging module
-# documentation for details on logging configuration files.
+# 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)
-#log_config=<None>
+#logging_exception_prefix = %(asctime)s.%(msecs)03d %(process)d ERROR %(name)s %(instance)s
 
-# DEPRECATED. A logging.Formatter log message format string
-# which may use any of the available logging.LogRecord
-# attributes. This option is deprecated.  Please use
-# logging_context_format_string and
-# logging_default_format_string instead. (string value)
-#log_format=<None>
+# 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
 
-# Format string for %%(asctime)s in log records. Default:
-# %(default)s (string value)
-#log_date_format=%Y-%m-%d %H:%M:%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
 
-# (Optional) Name of log file to output to. If no default is
-# set, logging will go to stdout. (string value)
-#log_file=<None>
+# Enables or disables publication of error events. (boolean
+# value)
+#publish_errors = false
 
-# (Optional) The base directory used for relative --log-file
-# paths (string value)
-#log_dir=<None>
+# The format for an instance that is passed with the log
+# message. (string value)
+#instance_format = "[instance: %(uuid)s] "
 
-# Use syslog for logging. (boolean value)
-#use_syslog=false
+# The format for an instance UUID that is passed with the log
+# message. (string value)
+#instance_uuid_format = "[instance: %(uuid)s] "
 
-# syslog facility to receive log lines (string value)
-#syslog_log_facility=LOG_USER
+# 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
diff --git a/ironic_python_agent/config.py b/ironic_python_agent/config.py
index 39839010c..6c5ca9639 100644
--- a/ironic_python_agent/config.py
+++ b/ironic_python_agent/config.py
@@ -25,90 +25,116 @@ cli_opts = [
     cfg.StrOpt('api_url',
                default=APARAMS.get('ipa-api-url'),
                deprecated_name='api-url',
-               help='URL of the Ironic API'),
+               help='URL of the Ironic API. '
+                    'Can be supplied as "ipa-api-url" kernel parameter.'),
 
     cfg.StrOpt('listen_host',
                default=APARAMS.get('ipa-listen-host', '0.0.0.0'),
                deprecated_name='listen-host',
-               help='The IP address to listen on.'),
+               help='The IP address to listen on. '
+                    'Can be supplied as "ipa-listen-host" kernel parameter.'),
 
     cfg.IntOpt('listen_port',
                default=int(APARAMS.get('ipa-listen-port', 9999)),
                deprecated_name='listen-port',
-               help='The port to listen on'),
+               help='The port to listen on. '
+                    'Can be supplied as "ipa-listen-port" kernel parameter.'),
 
     cfg.StrOpt('advertise_host',
                default=APARAMS.get('ipa-advertise-host', None),
                deprecated_name='advertise_host',
                help='The host to tell Ironic to reply and send '
-                    'commands to.'),
+                    'commands to. '
+                    'Can be supplied as "ipa-advertise-host" '
+                    'kernel parameter.'),
 
     cfg.IntOpt('advertise_port',
                default=int(APARAMS.get('ipa-advertise-port', 9999)),
                deprecated_name='advertise-port',
                help='The port to tell Ironic to reply and send '
-                    'commands to.'),
+                    'commands to. '
+                    'Can be supplied as "ipa-advertise-port" '
+                    'kernel parameter.'),
 
     cfg.IntOpt('ip_lookup_attempts',
                default=int(APARAMS.get('ipa-ip-lookup-attempts', 3)),
                deprecated_name='ip-lookup-attempts',
-               help='The number of times to try and automatically'
-                    'determine the agent IPv4 address.'),
+               help='The number of times to try and automatically '
+                    'determine the agent IPv4 address. '
+                    'Can be supplied as "ipa-ip-lookup-attempts" '
+                    'kernel parameter.'),
 
     cfg.IntOpt('ip_lookup_sleep',
                default=int(APARAMS.get('ipa-ip-lookup-timeout', 10)),
                deprecated_name='ip-lookup-sleep',
-               help='The amount of time to sleep between attempts'
-                    'to determine IP address.'),
+               help='The amount of time to sleep between attempts '
+                    'to determine IP address. '
+                    'Can be supplied as "ipa-ip-lookup-timeout" '
+                    'kernel parameter.'),
 
     cfg.StrOpt('network_interface',
                default=APARAMS.get('ipa-network-interface', None),
                deprecated_name='network-interface',
-               help='The interface to use when looking for an IP'
-               'address.'),
+               help='The interface to use when looking for an IP address. '
+                    'Can be supplied as "ipa-network-interface" '
+                    'kernel parameter.'),
 
     cfg.IntOpt('lookup_timeout',
                default=int(APARAMS.get('ipa-lookup-timeout', 300)),
                deprecated_name='lookup-timeout',
                help='The amount of time to retry the initial lookup '
                     'call to Ironic. After the timeout, the agent '
-                    'will exit with a non-zero exit code.'),
+                    'will exit with a non-zero exit code. '
+                    'Can be supplied as "ipa-lookup-timeout" '
+                    'kernel parameter.'),
 
     cfg.IntOpt('lookup_interval',
-               default=int(APARAMS.get('ipa-lookup-timeout', 1)),
+               default=int(APARAMS.get('ipa-lookup-interval', 1)),
                deprecated_name='lookup-interval',
                help='The initial interval for retries on the initial '
                     'lookup call to Ironic. The interval will be '
                     'doubled after each failure until timeout is '
-                    'exceeded.'),
+                    'exceeded. '
+                    'Can be supplied as "ipa-lookup-interval" '
+                    'kernel parameter.'),
 
     cfg.FloatOpt('lldp_timeout',
                  default=APARAMS.get('ipa-lldp-timeout',
                                      APARAMS.get('lldp-timeout', 30.0)),
-                 help='The amount of seconds to wait for LLDP packets.'),
+                 help='The amount of seconds to wait for LLDP packets. '
+                      'Can be supplied as "ipa-lldp-timeout" '
+                      'kernel parameter.'),
 
     cfg.BoolOpt('collect_lldp',
                 default=APARAMS.get('ipa-collect-lldp', False),
                 help='Whether IPA should attempt to receive LLDP packets for '
-                     'each network interface it discovers in the inventory.'),
+                     'each network interface it discovers in the inventory. '
+                     'Can be supplied as "ipa-collect-lldp" '
+                     'kernel parameter.'),
 
     cfg.BoolOpt('standalone',
                 default=APARAMS.get('ipa-standalone', False),
                 help='Note: for debugging only. Start the Agent but suppress '
-                     'any calls to Ironic API.'),
+                     'any calls to Ironic API. '
+                     'Can be supplied as "ipa-standalone" '
+                     'kernel parameter.'),
 
     cfg.StrOpt('inspection_callback_url',
                default=APARAMS.get('ipa-inspection-callback-url'),
                help='Endpoint of ironic-inspector. If set, hardware inventory '
                     'will be collected and sent to ironic-inspector '
-                    'on start up.'),
+                    'on start up. '
+                    'Can be supplied as "ipa-inspection-callback-url" '
+                    'kernel parameter.'),
 
     cfg.StrOpt('inspection_collectors',
                default=APARAMS.get('ipa-inspection-collectors',
                                    inspector.DEFAULT_COLLECTOR),
                help='Comma-separated list of plugins providing additional '
                     'hardware data for inspection, empty value gives '
-                    'a minimum required set of plugins.'),
+                    'a minimum required set of plugins. '
+                    'Can be supplied as "ipa-inspection-collectors" '
+                    'kernel parameter.'),
 
     cfg.IntOpt('inspection_dhcp_wait_timeout',
                default=APARAMS.get('ipa-inspection-dhcp-wait-timeout',
@@ -116,31 +142,46 @@ cli_opts = [
                help='Maximum time (in seconds) to wait for the PXE NIC '
                     '(or all NICs if inspection_dhcp_all_interfaces is True) '
                     'to get its IP address via DHCP before inspection. '
-                    'Set to 0 to disable waiting completely.'),
+                    'Set to 0 to disable waiting completely. '
+                    'Can be supplied as "ipa-inspection-dhcp-wait-timeout" '
+                    'kernel parameter.'),
 
     cfg.BoolOpt('inspection_dhcp_all_interfaces',
                 default=APARAMS.get('ipa-inspection-dhcp-all-interfaces',
                                     False),
                 help='Whether to wait for all interfaces to get their IP '
                      'addresses before inspection. If set to false '
-                     '(the default), only waits for the PXE interface.'),
+                     '(the default), only waits for the PXE interface. '
+                     'Can be supplied as '
+                     '"ipa-inspection-dhcp-all-interfaces" '
+                     'kernel parameter.'),
 
     cfg.IntOpt('hardware_initialization_delay',
                default=APARAMS.get('ipa-hardware-initialization-delay', 0),
                help='How much time (in seconds) to wait for hardware to '
-                    'initialize before proceeding with any actions.'),
+                    'initialize before proceeding with any actions. '
+                    'Can be supplied as "ipa-hardware-initialization-delay" '
+                    'kernel parameter.'),
 
     cfg.IntOpt('disk_wait_attempts',
                default=APARAMS.get('ipa-disk-wait-attempts', 10),
                help='The number of times to try and check to see if '
                     'at least one suitable disk has appeared in inventory '
-                    'before proceeding with any actions.'),
+                    'before proceeding with any actions. '
+                    'Can be supplied as "ipa-disk-wait-attempts" '
+                    'kernel parameter.'),
 
     cfg.IntOpt('disk_wait_delay',
                default=APARAMS.get('ipa-disk-wait-delay', 3),
                help='How much time (in seconds) to wait between attempts '
                     'to check if at least one suitable disk has appeared '
-                    'in inventory.'),
+                    'in inventory. '
+                    'Can be supplied as "ipa-disk-wait-delay" '
+                    'kernel parameter.'),
 ]
 
 CONF.register_cli_opts(cli_opts)
+
+
+def list_opts():
+    return [('DEFAULT', cli_opts)]
diff --git a/releasenotes/notes/oslo-config-generator-b0f70b9fb7e23997.yaml b/releasenotes/notes/oslo-config-generator-b0f70b9fb7e23997.yaml
new file mode 100644
index 000000000..e168b474f
--- /dev/null
+++ b/releasenotes/notes/oslo-config-generator-b0f70b9fb7e23997.yaml
@@ -0,0 +1,4 @@
+---
+other:
+  - Ironic Python Agent now uses ``oslo-config-generator`` to create the
+    sample of configuration file.
diff --git a/setup.cfg b/setup.cfg
index c4326c550..0fa3d8e7a 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -16,6 +16,9 @@ packages =
     ironic_python_agent
 
 [entry_points]
+oslo.config.opts =
+    ironic-python-agent = ironic_python_agent.config:list_opts
+
 console_scripts =
     ironic-python-agent = ironic_python_agent.cmd.agent:run
 
diff --git a/tools/config/check_uptodate.sh b/tools/config/check_uptodate.sh
index 49e49f0a3..d1a5cc290 100755
--- a/tools/config/check_uptodate.sh
+++ b/tools/config/check_uptodate.sh
@@ -2,6 +2,7 @@
 
 PROJECT_NAME=${PROJECT_NAME:-ironic_python_agent}
 CFGFILE_NAME=${PROJECT_NAME}.conf.sample
+OSLO_CFGFILE_OPTION=${OSLO_CFGFILE_OPTION:-tools/config/ipa-config-generator.conf}
 
 if [ -e etc/${PROJECT_NAME}/${CFGFILE_NAME} ]; then
     CFGFILE=etc/${PROJECT_NAME}/${CFGFILE_NAME}
@@ -15,10 +16,14 @@ fi
 TEMPDIR=`mktemp -d /tmp/${PROJECT_NAME}.XXXXXX`
 trap "rm -rf $TEMPDIR" EXIT
 
-tools/config/generate_sample.sh -b ./ -p ${PROJECT_NAME} -o ${TEMPDIR}
-
-if ! diff -u ${TEMPDIR}/${CFGFILE_NAME} ${CFGFILE} ; then
-    echo "${0##*/}: ${PROJECT_NAME}.conf.sample is not up to date."
-    echo "${0##*/}: Please run ${0%%${0##*/}}generate_sample.sh."
+oslo-config-generator --config-file=${OSLO_CFGFILE_OPTION} --output-file ${TEMPDIR}/${CFGFILE_NAME}
+if [ $? != 0 ]; then
+    echo "oslo-config-generator failed to create a sample config file ${TEMPDIR}/${CFGFILE_NAME} with --config-file ${OSLO_CFGFILE_OPTION}"
+    exit 1
+fi
+
+if ! diff -u ${TEMPDIR}/${CFGFILE_NAME} ${CFGFILE}; then
+    echo "${0##*/}: ${PROJECT_NAME}.conf.sample is not up to date."
+    echo "${0##*/}: Please run oslo-config-generator --config-file=${OSLO_CFGFILE_OPTION}"
     exit 1
 fi
diff --git a/tools/config/generate_sample.sh b/tools/config/generate_sample.sh
deleted file mode 100755
index 7058a1299..000000000
--- a/tools/config/generate_sample.sh
+++ /dev/null
@@ -1,117 +0,0 @@
-#!/usr/bin/env bash
-
-print_hint() {
-    echo "Try \`${0##*/} --help' for more information." >&2
-}
-
-PARSED_OPTIONS=$(getopt -n "${0##*/}" -o hb:p:m:l:o: \
-                --long help,base-dir:,package-name:,output-dir:,module:,library: -- "$@")
-
-if [ $? != 0 ] ; then
-    print_hint ;
-    exit 1
-fi
-
-eval set -- "$PARSED_OPTIONS"
-
-while true; do
-    case "$1" in
-        -h|--help)
-            echo "${0##*/} [options]"
-            echo ""
-            echo "options:"
-            echo "-h, --help                show brief help"
-            echo "-b, --base-dir=DIR        project base directory"
-            echo "-p, --package-name=NAME   project package name"
-            echo "-o, --output-dir=DIR      file output directory"
-            echo "-m, --module=MOD          extra python module to interrogate for options"
-            echo "-l, --library=LIB         extra library that registers options for discovery"
-            exit 0
-            ;;
-        -b|--base-dir)
-            shift
-            BASEDIR=`echo $1 | sed -e 's/\/*$//g'`
-            shift
-            ;;
-        -p|--package-name)
-            shift
-            PACKAGENAME=`echo $1`
-            shift
-            ;;
-        -o|--output-dir)
-            shift
-            OUTPUTDIR=`echo $1 | sed -e 's/\/*$//g'`
-            shift
-            ;;
-        -m|--module)
-            shift
-            MODULES="$MODULES -m $1"
-            shift
-            ;;
-        -l|--library)
-            shift
-            LIBRARIES="$LIBRARIES -l $1"
-            shift
-            ;;
-        --)
-            break
-            ;;
-    esac
-done
-
-BASEDIR=${BASEDIR:-`pwd`}
-if ! [ -d $BASEDIR ] ; then
-    echo "${0##*/}: missing project base directory" >&2 ; print_hint ; exit 1
-elif [[ $BASEDIR != /* ]] ; then
-    BASEDIR=$(cd "$BASEDIR" && pwd)
-fi
-
-PACKAGENAME=${PACKAGENAME:-${BASEDIR##*/}}
-PACKAGENAME=`echo $PACKAGENAME | tr - _`
-TARGETDIR=$BASEDIR/$PACKAGENAME
-if ! [ -d $TARGETDIR ] ; then
-    echo "${0##*/}: invalid project package name" >&2 ; print_hint ; exit 1
-fi
-
-OUTPUTDIR=${OUTPUTDIR:-$BASEDIR/etc}
-# NOTE(bnemec): Some projects put their sample config in etc/,
-#               some in etc/$PACKAGENAME/
-if [ -d $OUTPUTDIR/$PACKAGENAME ] ; then
-    OUTPUTDIR=$OUTPUTDIR/$PACKAGENAME
-elif ! [ -d $OUTPUTDIR ] ; then
-    echo "${0##*/}: cannot access \`$OUTPUTDIR': No such file or directory" >&2
-    exit 1
-fi
-
-BASEDIRESC=`echo $BASEDIR | sed -e 's/\//\\\\\//g'`
-find $TARGETDIR -type f -name "*.pyc" -delete
-FILES=$(find $TARGETDIR -type f -name "*.py" ! -path "*/tests/*" ! -path "*/nova/*" \
-        -exec grep -l "Opt(" {} + | sed -e "s/^$BASEDIRESC\///g" | sort -u)
-
-RC_FILE="`dirname $0`/oslo.config.generator.rc"
-if test -r "$RC_FILE" ; then
-    source "$RC_FILE"
-fi
-
-for mod in ${IRONIC_PYTHON_AGENT_CONFIG_GENERATOR_EXTRA_MODULES}; do
-    MODULES="$MODULES -m $mod"
-done
-
-for lib in ${IRONIC_PYTHON_AGENT_CONFIG_GENERATOR_EXTRA_LIBRARIES}; do
-    LIBRARIES="$LIBRARIES -l $lib"
-done
-
-export EVENTLET_NO_GREENDNS=yes
-
-OS_VARS=$(set | sed -n '/^OS_/s/=[^=]*$//gp' | xargs)
-[ "$OS_VARS" ] && eval "unset \$OS_VARS"
-DEFAULT_MODULEPATH=ironic_python_agent.openstack.common.config.generator
-MODULEPATH=${MODULEPATH:-$DEFAULT_MODULEPATH}
-OUTPUTFILE=$OUTPUTDIR/$PACKAGENAME.conf.sample
-python -m $MODULEPATH $MODULES $LIBRARIES $FILES > $OUTPUTFILE
-
-# Hook to allow projects to append custom config file snippets
-CONCAT_FILES=$(ls $BASEDIR/tools/config/*.conf.sample 2>/dev/null)
-for CONCAT_FILE in $CONCAT_FILES; do
-    cat $CONCAT_FILE >> $OUTPUTFILE
-done
diff --git a/tools/config/ipa-config-generator.conf b/tools/config/ipa-config-generator.conf
new file mode 100644
index 000000000..424cbb285
--- /dev/null
+++ b/tools/config/ipa-config-generator.conf
@@ -0,0 +1,5 @@
+[DEFAULT]
+output_file = etc/ironic_python_agent/ironic_python_agent.conf.sample
+wrap_width = 62
+namespace = ironic-python-agent
+namespace = oslo.log
diff --git a/tools/config/oslo.config.generator.rc b/tools/config/oslo.config.generator.rc
deleted file mode 100644
index e69de29bb..000000000
diff --git a/tox.ini b/tox.ini
index 074e4dfc8..915e2cc5b 100644
--- a/tox.ini
+++ b/tox.ini
@@ -68,3 +68,16 @@ enable-extensions=H106,H203,H904
 
 [hacking]
 import_exceptions = ironic.openstack.common.gettextutils._,testtools.matchers
+
+[testenv:checkconfig]
+sitepackages = False
+envdir = {toxworkdir}/venv
+commands =
+  {toxinidir}/tools/config/check_uptodate.sh
+
+[testenv:genconfig]
+sitepackages = False
+envdir = {toxworkdir}/venv
+commands =
+  oslo-config-generator --config-file=tools/config/ipa-config-generator.conf
+