# Buggy code
def register_opts(ignore_errors=False):
    rbac_opts = [
        cfg.BoolOpt("enable", default=False, help="Enable RBAC."),
        cfg.StrOpt("backend", default="noop", help="RBAC backend to use."),
        cfg.BoolOpt(
            "sync_remote_groups",
            default=False,
            help="True to synchronize remote groups returned by the auth backed for each "
            "StackStorm user with local StackStorm roles based on the group to role "
            "mapping definition files.",
        ),
        cfg.BoolOpt(
            "permission_isolation",
            default=False,
            help="Isolate resources by user. For now, these resources only include rules and "
            "executions. All resources can only be viewed or executed by the owning user "
            "except the admin and system_user who can view or run everything.",
        ),
    ]

    do_register_opts(rbac_opts, "rbac", ignore_errors)

    system_user_opts = [
        cfg.StrOpt("user", default="stanley", help="Default system user."),
        cfg.StrOpt(
            "ssh_key_file",
            default="/home/stanley/.ssh/stanley_rsa",
            help="SSH private key for the system user.",
        ),
    ]

    do_register_opts(system_user_opts, "system_user", ignore_errors)

    schema_opts = [
        cfg.IntOpt("version", default=4, help="Version of JSON schema to use."),
        cfg.StrOpt(
            "draft",
            default="http://json-schema.org/draft-04/schema#",
            help="URL to the JSON schema draft.",
        ),
    ]

    do_register_opts(schema_opts, "schema", ignore_errors)

    system_opts = [
        cfg.BoolOpt("debug", default=False, help="Enable debug mode."),
        cfg.StrOpt(
            "base_path",
            default="/opt/stackstorm",
            help="Base path to all st2 artifacts.",
        ),
        cfg.BoolOpt(
            "validate_trigger_parameters",
            default=True,
            help="True to validate parameters for non-system trigger types when creating"
            "a rule. By default, only parameters for system triggers are validated.",
        ),
        cfg.BoolOpt(
            "validate_trigger_payload",
            default=True,
            help="True to validate payload for non-system trigger types when dispatching a trigger "
            "inside the sensor. By default, only payload for system triggers is validated.",
        ),
        cfg.BoolOpt(
            "validate_output_schema",
            default=False,
            help="True to validate action and runner output against schema.",
        ),
    ]

    do_register_opts(system_opts, "system", ignore_errors)

    system_packs_base_path = os.path.join(cfg.CONF.system.base_path, "packs")
    system_runners_base_path = os.path.join(cfg.CONF.system.base_path, "runners")

    content_opts = [
        cfg.StrOpt(
            "pack_group",
            default="st2packs",
            help="User group that can write to packs directory.",
        ),
        cfg.StrOpt(
            "system_packs_base_path",
            default=system_packs_base_path,
            help="Path to the directory which contains system packs.",
        ),
        cfg.StrOpt(
            "system_runners_base_path",
            default=system_runners_base_path,
            help="Path to the directory which contains system runners. "
            "NOTE: This option has been deprecated and it's unused since StackStorm v3.0.0",
        ),
        cfg.StrOpt(
            "packs_base_paths",
            default=None,
            help="Paths which will be searched for integration packs.",
        ),
        cfg.StrOpt(
            "runners_base_paths",
            default=None,
            help="Paths which will be searched for runners. "
            "NOTE: This option has been deprecated and it's unused since StackStorm v3.0.0",
        ),
        cfg.ListOpt(
            "index_url",
            default=["https://index.stackstorm.org/v1/index.json"],
            help="A URL pointing to the pack index. StackStorm Exchange is used by "
            "default. Use a comma-separated list for multiple indexes if you "
            'want to get other packs discovered with "st2 pack search".',
        ),
    ]

    do_register_opts(content_opts, "content", ignore_errors)

    webui_opts = [
        cfg.StrOpt(
            "webui_base_url",
            default="https://%s" % socket.getfqdn(),
            help="Base https URL to access st2 Web UI. This is used to construct history URLs "
            "that are sent out when chatops is used to kick off executions.",
        )
    ]

    do_register_opts(webui_opts, "webui", ignore_errors)

    db_opts = [
        cfg.StrOpt("host", default="127.0.0.1", help="host of db server"),
        cfg.IntOpt("port", default=27017, help="port of db server"),
        cfg.StrOpt("db_name", default="st2", help="name of database"),
        cfg.StrOpt("username", help="username for db login"),
        cfg.StrOpt("password", help="password for db login"),
        cfg.IntOpt(
            "connection_retry_max_delay_m",
            default=3,
            help="Connection retry total time (minutes).",
        ),
        cfg.IntOpt(
            "connection_retry_backoff_max_s",
            default=10,
            help="Connection retry backoff max (seconds).",
        ),
        cfg.IntOpt(
            "connection_retry_backoff_mul",
            default=1,
            help="Backoff multiplier (seconds).",
        ),
        cfg.BoolOpt(
            "ssl", default=False, help="Create the connection to mongodb using SSL"
        ),
        cfg.StrOpt(
            "ssl_keyfile",
            default=None,
            help="Private keyfile used to identify the local connection against MongoDB.",
        ),
        cfg.StrOpt(
            "ssl_certfile",
            default=None,
            help="Certificate file used to identify the localconnection",
        ),
        cfg.StrOpt(
            "ssl_cert_reqs",
            default=None,
            choices="none, optional, required",
            help="Specifies whether a certificate is required from the other side of the "
            "connection, and whether it will be validated if provided",
        ),
        cfg.StrOpt(
            "ssl_ca_certs",
            default=None,
            help="ca_certs file contains a set of concatenated CA certificates, which are "
            "used to validate certificates passed from MongoDB.",
        ),
        cfg.BoolOpt(
            "ssl_match_hostname",
            default=True,
            help="If True and `ssl_cert_reqs` is not None, enables hostname verification",
        ),
        cfg.StrOpt(
            "authentication_mechanism",
            default=None,
            help="Specifies database authentication mechanisms. "
            "By default, it use SCRAM-SHA-1 with MongoDB 3.0 and later, "
            "MONGODB-CR (MongoDB Challenge Response protocol) for older servers.",
        ),
    ]

    do_register_opts(db_opts, "database", ignore_errors)

    messaging_opts = [
        # It would be nice to be able to deprecate url and completely switch to using
        # url. However, this will be a breaking change and will have impact so allowing both.
        cfg.StrOpt(
            "url",
            default="amqp://guest:guest@127.0.0.1:5672//",
            help="URL of the messaging server.",
        ),
        cfg.ListOpt(
            "cluster_urls",
            default=[],
            help="URL of all the nodes in a messaging service cluster.",
        ),
        cfg.IntOpt(
            "connection_retries",
            default=10,
            help="How many times should we retry connection before failing.",
        ),
        cfg.IntOpt(
            "connection_retry_wait",
            default=10000,
            help="How long should we wait between connection retries.",
        ),
        cfg.BoolOpt(
            "ssl",
            default=False,
            help="Use SSL / TLS to connect to the messaging server. Same as "
            'appending "?ssl=true" at the end of the connection URL string.',
        ),
        cfg.StrOpt(
            "ssl_keyfile",
            default=None,
            help="Private keyfile used to identify the local connection against RabbitMQ.",
        ),
        cfg.StrOpt(
            "ssl_certfile",
            default=None,
            help="Certificate file used to identify the local connection (client).",
        ),
        cfg.StrOpt(
            "ssl_cert_reqs",
            default=None,
            choices="none, optional, required",
            help="Specifies whether a certificate is required from the other side of the "
            "connection, and whether it will be validated if provided.",
        ),
        cfg.StrOpt(
            "ssl_ca_certs",
            default=None,
            help="ca_certs file contains a set of concatenated CA certificates, which are "
            "used to validate certificates passed from RabbitMQ.",
        ),
        cfg.StrOpt(
            "login_method",
            default=None,
            help="Login method to use (AMQPLAIN, PLAIN, EXTERNAL, etc.).",
        ),
    ]

    do_register_opts(messaging_opts, "messaging", ignore_errors)

    syslog_opts = [
        cfg.StrOpt("host", default="127.0.0.1", help="Host for the syslog server."),
        cfg.IntOpt("port", default=514, help="Port for the syslog server."),
        cfg.StrOpt("facility", default="local7", help="Syslog facility level."),
        cfg.StrOpt(
            "protocol", default="udp", help="Transport protocol to use (udp / tcp)."
        ),
    ]

    do_register_opts(syslog_opts, "syslog", ignore_errors)

    log_opts = [
        cfg.ListOpt("excludes", default="", help="Exclusion list of loggers to omit."),
        cfg.BoolOpt(
            "redirect_stderr",
            default=False,
            help="Controls if stderr should be redirected to the logs.",
        ),
        cfg.BoolOpt(
            "mask_secrets", default=True, help="True to mask secrets in the log files."
        ),
        cfg.ListOpt(
            "mask_secrets_blacklist",
            default=[],
            help="Blacklist of additional attribute names to mask in the log messages.",
        ),
    ]

    do_register_opts(log_opts, "log", ignore_errors)

    # Common API options
    api_opts = [
        cfg.StrOpt("host", default="127.0.0.1", help="StackStorm API server host"),
        cfg.IntOpt("port", default=9101, help="StackStorm API server port"),
        cfg.ListOpt(
            "allow_origin",
            default=["http://127.0.0.1:3000"],
            help="List of origins allowed for api, auth and stream",
        ),
        cfg.BoolOpt(
            "mask_secrets",
            default=True,
            help="True to mask secrets in the API responses",
        ),
    ]

    do_register_opts(api_opts, "api", ignore_errors)

    # Key Value store options
    keyvalue_opts = [
        cfg.BoolOpt(
            "enable_encryption",
            default=True,
            help='Allow encryption of values in key value stored qualified as "secret".',
        ),
        cfg.StrOpt(
            "encryption_key_path",
            default="",
            help="Location of the symmetric encryption key for encrypting values in kvstore. "
            "This key should be in JSON and should've been generated using "
            "st2-generate-symmetric-crypto-key tool.",
        ),
    ]

    do_register_opts(keyvalue_opts, group="keyvalue")

    # Common auth options
    auth_opts = [
        cfg.StrOpt(
            "api_url",
            default=None,
            help="Base URL to the API endpoint excluding the version",
        ),
        cfg.BoolOpt("enable", default=True, help="Enable authentication middleware."),
        cfg.IntOpt(
            "token_ttl", default=(24 * 60 * 60), help="Access token ttl in seconds."
        ),
        # This TTL is used for tokens which belong to StackStorm services
        cfg.IntOpt(
            "service_token_ttl",
            default=(24 * 60 * 60),
            help="Service token ttl in seconds.",
        ),
    ]

    do_register_opts(auth_opts, "auth", ignore_errors)

    # Runner options
    default_python_bin_path = sys.executable
    default_python3_bin_path = find_executable("python3")
    base_dir = os.path.dirname(os.path.realpath(default_python_bin_path))
    default_virtualenv_bin_path = os.path.join(base_dir, "virtualenv")

    action_runner_opts = [
        # Common runner options
        cfg.StrOpt(
            "logging",
            default="/etc/st2/logging.actionrunner.conf",
            help="location of the logging.conf file",
        ),
        # Python runner options
        cfg.StrOpt(
            "python_binary",
            default=default_python_bin_path,
            help="Python binary which will be used by Python actions.",
        ),
        cfg.StrOpt(
            "python3_binary",
            default=default_python3_bin_path,
            help="Python 3 binary which will be used by Python actions for packs which "
            "use Python 3 virtual environment.",
        ),
        cfg.StrOpt(
            "python3_prefix",
            default=None,
            help="Prefix for Python 3 installation (e.g. /opt/python3.6). If not specified, it "
            "tries to find Python 3 libraries in /usr/lib and /usr/local/lib.",
        ),
        cfg.StrOpt(
            "virtualenv_binary",
            default=default_virtualenv_bin_path,
            help="Virtualenv binary which should be used to create pack virtualenvs.",
        ),
        cfg.StrOpt(
            "python_runner_log_level",
            default=PYTHON_RUNNER_DEFAULT_LOG_LEVEL,
            help="Default log level to use for Python runner actions. Can be overriden on "
            'invocation basis using "log_level" runner parameter.',
        ),
        cfg.ListOpt(
            "virtualenv_opts",
            default=["--system-site-packages"],
            help='List of virtualenv options to be passsed to "virtualenv" command that '
            "creates pack virtualenv.",
        ),
        cfg.BoolOpt(
            "stream_output",
            default=True,
            help="True to store and stream action output (stdout and stderr) in real-time.",
        ),
    ]

    do_register_opts(action_runner_opts, group="actionrunner")

    dispatcher_pool_opts = [
        cfg.IntOpt(
            "workflows_pool_size",
            default=40,
            help="Internal pool size for dispatcher used by workflow actions.",
        ),
        cfg.IntOpt(
            "actions_pool_size",
            default=60,
            help="Internal pool size for dispatcher used by regular actions.",
        ),
    ]

    do_register_opts(dispatcher_pool_opts, group="actionrunner")

    ssh_runner_opts = [
        cfg.StrOpt(
            "remote_dir",
            default="/tmp",
            help="Location of the script on the remote filesystem.",
        ),
        cfg.BoolOpt(
            "allow_partial_failure",
            default=False,
            help="How partial success of actions run on multiple nodes should be treated.",
        ),
        cfg.IntOpt(
            "max_parallel_actions",
            default=50,
            help="Max number of parallel remote SSH actions that should be run. "
            "Works only with Paramiko SSH runner.",
        ),
        cfg.BoolOpt(
            "use_ssh_config",
            default=False,
            help="Use the .ssh/config file. Useful to override ports etc.",
        ),
        cfg.StrOpt(
            "ssh_config_file_path",
            default="~/.ssh/config",
            help="Path to the ssh config file.",
        ),
    ]

    do_register_opts(ssh_runner_opts, group="ssh_runner")

    # Common options (used by action runner and sensor container)
    action_sensor_opts = [
        cfg.BoolOpt(
            "enable",
            default=True,
            help="Whether to enable or disable the ability to post a trigger on action.",
        ),
        cfg.ListOpt(
            "emit_when",
            default=LIVEACTION_COMPLETED_STATES,
            help="List of execution statuses for which a trigger will be emitted. ",
        ),
    ]

    do_register_opts(action_sensor_opts, group="action_sensor")

    # Common options for content
    pack_lib_opts = [
        cfg.BoolOpt(
            "enable_common_libs",
            default=False,
            help="Enable/Disable support for pack common libs. "
            "Setting this config to ``True`` would allow you to "
            "place common library code for sensors and actions in lib/ folder "
            "in packs and use them in python sensors and actions. "
            "See https://docs.stackstorm.com/reference/"
            "sharing_code_sensors_actions.html "
            "for details.",
        )
    ]

    do_register_opts(pack_lib_opts, group="packs")

    # Coordination options
    coord_opts = [
        cfg.StrOpt("url", default=None, help="Endpoint for the coordination server."),
        cfg.IntOpt(
            "lock_timeout", default=60, help="TTL for the lock if backend suports it."
        ),
        cfg.BoolOpt(
            "service_registry",
            default=False,
            help="True to register StackStorm services in a service registry.",
        ),
    ]

    do_register_opts(coord_opts, "coordination", ignore_errors)

    # Mistral options
    mistral_opts = [
        cfg.StrOpt(
            "v2_base_url",
            default="http://127.0.0.1:8989/v2",
            help="v2 API root endpoint.",
        ),
        cfg.IntOpt(
            "retry_exp_msec",
            default=1000,
            help="Multiplier for the exponential backoff.",
        ),
        cfg.IntOpt(
            "retry_exp_max_msec",
            default=300000,
            help="Max time for each set of backoff.",
        ),
        cfg.IntOpt(
            "retry_stop_max_msec", default=600000, help="Max time to stop retrying."
        ),
        cfg.StrOpt(
            "keystone_username", default=None, help="Username for authentication."
        ),
        cfg.StrOpt(
            "keystone_password", default=None, help="Password for authentication."
        ),
        cfg.StrOpt(
            "keystone_project_name", default=None, help="OpenStack project scope."
        ),
        cfg.StrOpt(
            "keystone_auth_url", default=None, help="Auth endpoint for Keystone."
        ),
        cfg.StrOpt(
            "cacert", default=None, help="Optional certificate to validate endpoint."
        ),
        cfg.BoolOpt(
            "insecure", default=False, help="Allow insecure communication with Mistral."
        ),
        cfg.BoolOpt(
            "enable_polling",
            default=False,
            help="Enable results tracking and disable callbacks.",
        ),
        cfg.FloatOpt(
            "jitter_interval",
            default=0.1,
            help="Jitter interval to smooth out HTTP requests "
            "to mistral tasks and executions API.",
        ),
        cfg.StrOpt(
            "api_url",
            default=None,
            help="URL Mistral uses to talk back to the API."
            "If not provided it defaults to public API URL. "
            "Note: This needs to be a base URL without API "
            "version (e.g. http://127.0.0.1:9101)",
        ),
    ]

    do_register_opts(mistral_opts, group="mistral", ignore_errors=ignore_errors)

    # Results Tracker query module options
    # Note that these are currently used only by mistral query module.
    query_opts = [
        cfg.IntOpt(
            "thread_pool_size",
            default=10,
            help="Number of threads to use to query external workflow systems.",
        ),
        cfg.FloatOpt(
            "query_interval",
            default=5,
            help="Time interval between queries to external workflow system.",
        ),
        cfg.FloatOpt(
            "empty_q_sleep_time",
            default=1,
            help="Sleep delay in between queries when query queue is empty.",
        ),
        cfg.FloatOpt(
            "no_workers_sleep_time",
            default=1,
            help="Sleep delay for query when there is no more worker in pool.",
        ),
    ]

    do_register_opts(query_opts, group="resultstracker", ignore_errors=ignore_errors)

    # XXX: This is required for us to support deprecated config group results_tracker
    query_opts = [
        cfg.IntOpt(
            "thread_pool_size",
            help="Number of threads to use to query external workflow systems.",
        ),
        cfg.FloatOpt(
            "query_interval",
            help="Time interval between subsequent queries for a context "
            "to external workflow system.",
        ),
    ]

    do_register_opts(query_opts, group="results_tracker", ignore_errors=ignore_errors)

    # Common stream options
    stream_opts = [
        cfg.IntOpt(
            "heartbeat",
            default=25,
            help="Send empty message every N seconds to keep connection open",
        )
    ]

    do_register_opts(stream_opts, group="stream", ignore_errors=ignore_errors)

    # Common CLI options
    cli_opts = [
        cfg.BoolOpt(
            "debug",
            default=False,
            help="Enable debug mode. By default this will set all log levels to DEBUG.",
        ),
        cfg.BoolOpt(
            "profile",
            default=False,
            help="Enable profile mode. In the profile mode all the MongoDB queries and "
            "related profile data are logged.",
        ),
        cfg.BoolOpt(
            "use-debugger",
            default=True,
            help="Enables debugger. Note that using this option changes how the "
            "eventlet library is used to support async IO. This could result in "
            "failures that do not occur under normal operation.",
        ),
    ]

    do_register_cli_opts(cli_opts, ignore_errors=ignore_errors)

    # Metrics Options stream options
    metrics_opts = [
        cfg.StrOpt(
            "driver", default="noop", help="Driver type for metrics collection."
        ),
        cfg.StrOpt(
            "host",
            default="127.0.0.1",
            help="Destination server to connect to if driver requires connection.",
        ),
        cfg.IntOpt(
            "port",
            default=8125,
            help="Destination port to connect to if driver requires connection.",
        ),
        cfg.StrOpt(
            "prefix",
            default=None,
            help="Optional prefix which is prepended to all the metric names. Comes handy when "
            "you want to submit metrics from various environment to the same metric "
            "backend instance.",
        ),
        cfg.FloatOpt(
            "sample_rate",
            default=1,
            help="Randomly sample and only send metrics for X% of metric operations to the "
            "backend. Default value of 1 means no sampling is done and all the metrics are "
            "sent to the backend. E.g. 0.1 would mean 10% of operations are sampled.",
        ),
    ]

    do_register_opts(metrics_opts, group="metrics", ignore_errors=ignore_errors)

    # Common timers engine options
    timer_logging_opts = [
        cfg.StrOpt(
            "logging",
            default=None,
            help="Location of the logging configuration file. "
            "NOTE: Deprecated in favor of timersengine.logging",
        ),
    ]

    timers_engine_logging_opts = [
        cfg.StrOpt(
            "logging",
            default="/etc/st2/logging.timersengine.conf",
            help="Location of the logging configuration file.",
        )
    ]

    do_register_opts(timer_logging_opts, group="timer", ignore_errors=ignore_errors)
    do_register_opts(
        timers_engine_logging_opts, group="timersengine", ignore_errors=ignore_errors
    )

    # NOTE: We default old style deprecated "timer" options to None so our code
    # works correclty and "timersengine" has precedence over "timers"
    # NOTE: "timer" section will be removed in v3.1
    timer_opts = [
        cfg.StrOpt(
            "local_timezone",
            default=None,
            help="Timezone pertaining to the location where st2 is run. "
            "NOTE: Deprecated in favor of timersengine.local_timezone",
        ),
        cfg.BoolOpt(
            "enable",
            default=None,
            help="Specify to enable timer service. "
            "NOTE: Deprecated in favor of timersengine.enable",
        ),
    ]

    timers_engine_opts = [
        cfg.StrOpt(
            "local_timezone",
            default="America/Los_Angeles",
            help="Timezone pertaining to the location where st2 is run.",
        ),
        cfg.BoolOpt("enable", default=True, help="Specify to enable timer service."),
    ]
    do_register_opts(timer_opts, group="timer", ignore_errors=ignore_errors)
    do_register_opts(
        timers_engine_opts, group="timersengine", ignore_errors=ignore_errors
    )


# Traceback (ToozConnectionError)
2019-06-04 17:08:05,405 139749901439856 ERROR consumers [-] VariableMessageQueueConsumer failed to process message: ActionExecutionDB(action={u'notify': {}, u'description': u'This executes a task in the net-task library', u'runner_type': u'python-script', u'tags': [], u'enabled': True, u'name': u'net-task', u'entry_point': u'python/net-task.py', u'metadata_file': u'actions/net-task.yaml', u'output_schema': {}, u'uid': u'action:shigo:net-task', u'parameters': {u'args': {u'position': 1, u'required': False, u'type': u'array', u'description': u'Args to be passed to the task'}, u'task_name': {u'position': 0, u'required': True, u'type': u'string', u'description': u'The name of the task'}, u'kwargs': {u'position': 2, u'required': False, u'type': u'object', u'description': u'Kwargs to be passed to the task'}}, u'ref': u'shigo.net-task', u'id': u'5c1af2cedb95700082de9860', u'pack': u'shigo'}, children=[], context={u'orquesta': {u'workflow_execution_id': u'5cf6a55f5f85230022d4bf06', u'task_id': u'get_nettask_version', u'task_execution_id': u'5cf6a563d0fa0000229108c0', u'task_name': u'get_nettask_version', u'task_route': 0}, u'user': u'st2admin', u'parent': {u'user': u'st2admin', u'execution_id': u'5cf6a55ea036ab0033dc934c', u'pack': u'shigo'}, u'pack': u'shigo'}, delay=None, end_timestamp="2019-06-04 17:08:05.182673+00:00", id=5cf6a563d0fa0000229108c2, liveaction={u'callback': {}, u'runner_info': {u'hostname': u'4051aa3ae5dd', u'pid': 34}, u'parameters': {u'task_name': u'net_task.version'}, u'action': u'shigo.net-task', u'action_is_workflow': False, u'id': u'5cf6a563d0fa0000229108c1'}, log=[{u'status': u'requested', u'timestamp': datetime.datetime(2019, 6, 4, 17, 7, 47, 469000, tzinfo=<bson.tz_util.FixedOffset object at 0x7f1a0f8212d0>)}, {u'status': u'scheduled', u'timestamp': datetime.datetime(2019, 6, 4, 17, 7, 48, 199000, tzinfo=<bson.tz_util.FixedOffset object at 0x7f1a0f8212d0>)}, {u'status': u'running', u'timestamp': datetime.datetime(2019, 6, 4, 17, 7, 48, 332000, tzinfo=<bson.tz_util.FixedOffset object at 0x7f1a0f8212d0>)}, {u'status': u'succeeded', u'timestamp': datetime.datetime(2019, 6, 4, 17, 8, 5, 217000, tzinfo=<bson.tz_util.FixedOffset object at 0x7f1a0f8212d0>)}], parameters={u'task_name': u'net_task.version'}, parent="5cf6a55ea036ab0033dc934c", result={u'result': {u'task-id': u'8726afab-915d-4f97-8205-5c7f73ffa4ae', u'state': u'SUCCESS', u'result': {u'optical-tech': u'0.6.4', u'network-state-service': u'0.4.3', u'net-devices2': u'1.4.2', u'kusto-proxy': u'0.1.1', u'phynet-credentials': u'0.8.2', u'device_grouping': u'0.0.2', u'starlab': u'0.1.60', u'wan-tech': u'0.7.7', u'icm-connector': u'0.8.12', u'azconfigure-tasks': u'1.0.13', u'celery': u'4.2.1', u'quality-checks': u'0.1.22', u'atom': u'0.9.44', u'net-task-contrib': u'0.4.72', u'net-assist': u'0.1.10', u'fabric-tools': u'0.1.6', u'ask-mode-service': u'0.3.2', u'safety-check-service': u'0.2.8', u'apache-airflow': u'2.0.0dev0+3.incubating', u'net-task': u'0.13.0'}}, u'exit_code': 0, u'stderr': u"st2.actions.python.NetTaskWrapper: DEBUG    json data: {}\nst2.actions.python.NetTaskWrapper: INFO     NetTask UUID: 8726afab-915d-4f97-8205-5c7f73ffa4ae\nst2.actions.python.NetTaskWrapper: INFO     task net_task.version completed, result is {u'task-id': u'8726afab-915d-4f97-8205-5c7f73ffa4ae', u'state': u'SUCCESS', u'result': {u'net-task': u'0.13.0', u'device_grouping': u'0.0.2', u'kusto-proxy': u'0.1.1', u'phynet-credentials': u'0.8.2', u'quality-checks': u'0.1.22', u'azconfigure-tasks': u'1.0.13', u'starlab': u'0.1.60', u'ask-mode-service': u'0.3.2', u'icm-connector': u'0.8.12', u'apache-airflow': u'2.0.0dev0+3.incubating', u'celery': u'4.2.1', u'net-task-contrib': u'0.4.72', u'network-state-service': u'0.4.3', u'wan-tech': u'0.7.7', u'net-assist': u'0.1.10', u'atom': u'0.9.44', u'safety-check-service': u'0.2.8', u'fabric-tools': u'0.1.6', u'net-devices2': u'1.4.2', u'optical-tech': u'0.6.4'}}\nst2.actions.python.NetTaskWrapper: WARNING  task did not return data in (status, result) format, as expected by stackstorm\n", u'stdout': u''}, rule={}, runner={u'runner_module': u'python_runner', u'uid': u'runner_type:python-script', u'runner_package': u'python_runner', u'enabled': True, u'name': u'python-script', u'output_key': u'result', u'output_schema': {u'exit_code': {u'required': True, u'type': u'integer'}, u'result': {u'anyOf': [{u'type': u'object'}, {u'type': u'string'}, {u'type': u'integer'}, {u'type': u'number'}, {u'type': u'boolean'}, {u'type': u'array'}, {u'type': u'null'}]}, u'stderr': {u'required': True, u'type': u'string'}, u'stdout': {u'required': True, u'type': u'string'}}, u'runner_parameters': {u'debug': {u'default': False, u'required': False, u'type': u'boolean', u'description': u'Enable runner debug mode.'}, u'content_version': {u'required': False, u'type': u'string', u'description': u'Git revision of the pack content to use for this action execution (git commit sha / tag / branch). Only applies to packs which are git repositories.'}, u'log_level': {u'default': u'DEBUG', u'enum': [u'AUDIT', u'CRITICAL', u'ERROR', u'WARNING', u'INFO', u'DEBUG'], u'type': u'string', u'description': u'Default log level for Python runner actions.'}, u'timeout': {u'default': 600, u'type': u'integer', u'description': u"Action timeout in seconds. Action will get killed if it doesn't finish in timeout seconds."}, u'env': {u'type': u'object', u'description': u'Environment variables which will be available to the script.'}}, u'id': u'5c1af28f26395d0024fc2741', u'description': u'A runner for launching python actions.'}, start_timestamp="2019-06-04 17:07:47.443217+00:00", status="succeeded", task_execution="5cf6a563d0fa0000229108c0", trigger={}, trigger_instance={}, trigger_type={}, web_url="https://befdd34ce4a4/#/history/5cf6a563d0fa0000229108c2/general", workflow_execution="5cf6a55f5f85230022d4bf06")
Traceback (most recent call last):
File "/opt/stackstorm/st2/local/lib/python2.7/site-packages/st2common/transport/consumers.py", line 72, in _process_message
self._handler.process(body)
File "/opt/stackstorm/st2/local/lib/python2.7/site-packages/st2actions/workflows/workflows.py", line 83, in process
handler_function(message)
File "/opt/stackstorm/st2/local/lib/python2.7/site-packages/st2actions/workflows/workflows.py", line 61, in handle_action_execution_with_instrumentation
return self.handle_action_execution(ac_ex_db=ac_ex_db)
File "/opt/stackstorm/st2/local/lib/python2.7/site-packages/st2actions/workflows/workflows.py", line 134, in handle_action_execution
wf_svc.handle_action_execution_completion(ac_ex_db)
File "/opt/stackstorm/st2/local/lib/python2.7/site-packages/st2common/services/workflows.py", line 733, in handle_action_execution_completion
with coord_svc.get_coordinator(start_heart=True).get_lock(wf_ex_id):
File "/opt/stackstorm/st2/local/lib/python2.7/site-packages/tooz/locking.py", line 52, in __enter__
acquired = self.acquire(*args, **kwargs)
File "/opt/stackstorm/st2/local/lib/python2.7/site-packages/tooz/drivers/redis.py", line 93, in acquire
return acquired
File "/usr/lib/python2.7/contextlib.py", line 35, in __exit__
self.gen.throw(type, value, traceback)
File "/opt/stackstorm/st2/local/lib/python2.7/site-packages/tooz/drivers/redis.py", line 51, in _translate_failures
cause=e)
File "/opt/stackstorm/st2/local/lib/python2.7/site-packages/tooz/utils.py", line 225, in raise_with_cause
excutils.raise_with_cause(exc_cls, message, *args, **kwargs)
File "/opt/stackstorm/st2/local/lib/python2.7/site-packages/oslo_utils/excutils.py", line 143, in raise_with_cause
six.raise_from(exc_cls(message, *args, **kwargs), kwargs.get('cause'))
File "/opt/stackstorm/st2/local/lib/python2.7/site-packages/six.py", line 737, in raise_from
raise value
ToozConnectionError: Error while reading from socket: (u'Connection closed by server.',)

# Fixed code
def register_opts(ignore_errors=False):
    rbac_opts = [
        cfg.BoolOpt("enable", default=False, help="Enable RBAC."),
        cfg.StrOpt("backend", default="noop", help="RBAC backend to use."),
        cfg.BoolOpt(
            "sync_remote_groups",
            default=False,
            help="True to synchronize remote groups returned by the auth backed for each "
            "StackStorm user with local StackStorm roles based on the group to role "
            "mapping definition files.",
        ),
        cfg.BoolOpt(
            "permission_isolation",
            default=False,
            help="Isolate resources by user. For now, these resources only include rules and "
            "executions. All resources can only be viewed or executed by the owning user "
            "except the admin and system_user who can view or run everything.",
        ),
    ]

    do_register_opts(rbac_opts, "rbac", ignore_errors)

    system_user_opts = [
        cfg.StrOpt("user", default="stanley", help="Default system user."),
        cfg.StrOpt(
            "ssh_key_file",
            default="/home/stanley/.ssh/stanley_rsa",
            help="SSH private key for the system user.",
        ),
    ]

    do_register_opts(system_user_opts, "system_user", ignore_errors)

    schema_opts = [
        cfg.IntOpt("version", default=4, help="Version of JSON schema to use."),
        cfg.StrOpt(
            "draft",
            default="http://json-schema.org/draft-04/schema#",
            help="URL to the JSON schema draft.",
        ),
    ]

    do_register_opts(schema_opts, "schema", ignore_errors)

    system_opts = [
        cfg.BoolOpt("debug", default=False, help="Enable debug mode."),
        cfg.StrOpt(
            "base_path",
            default="/opt/stackstorm",
            help="Base path to all st2 artifacts.",
        ),
        cfg.BoolOpt(
            "validate_trigger_parameters",
            default=True,
            help="True to validate parameters for non-system trigger types when creating"
            "a rule. By default, only parameters for system triggers are validated.",
        ),
        cfg.BoolOpt(
            "validate_trigger_payload",
            default=True,
            help="True to validate payload for non-system trigger types when dispatching a trigger "
            "inside the sensor. By default, only payload for system triggers is validated.",
        ),
        cfg.BoolOpt(
            "validate_output_schema",
            default=False,
            help="True to validate action and runner output against schema.",
        ),
    ]

    do_register_opts(system_opts, "system", ignore_errors)

    system_packs_base_path = os.path.join(cfg.CONF.system.base_path, "packs")
    system_runners_base_path = os.path.join(cfg.CONF.system.base_path, "runners")

    content_opts = [
        cfg.StrOpt(
            "pack_group",
            default="st2packs",
            help="User group that can write to packs directory.",
        ),
        cfg.StrOpt(
            "system_packs_base_path",
            default=system_packs_base_path,
            help="Path to the directory which contains system packs.",
        ),
        cfg.StrOpt(
            "system_runners_base_path",
            default=system_runners_base_path,
            help="Path to the directory which contains system runners. "
            "NOTE: This option has been deprecated and it's unused since StackStorm v3.0.0",
        ),
        cfg.StrOpt(
            "packs_base_paths",
            default=None,
            help="Paths which will be searched for integration packs.",
        ),
        cfg.StrOpt(
            "runners_base_paths",
            default=None,
            help="Paths which will be searched for runners. "
            "NOTE: This option has been deprecated and it's unused since StackStorm v3.0.0",
        ),
        cfg.ListOpt(
            "index_url",
            default=["https://index.stackstorm.org/v1/index.json"],
            help="A URL pointing to the pack index. StackStorm Exchange is used by "
            "default. Use a comma-separated list for multiple indexes if you "
            'want to get other packs discovered with "st2 pack search".',
        ),
    ]

    do_register_opts(content_opts, "content", ignore_errors)

    webui_opts = [
        cfg.StrOpt(
            "webui_base_url",
            default="https://%s" % socket.getfqdn(),
            help="Base https URL to access st2 Web UI. This is used to construct history URLs "
            "that are sent out when chatops is used to kick off executions.",
        )
    ]

    do_register_opts(webui_opts, "webui", ignore_errors)

    db_opts = [
        cfg.StrOpt("host", default="127.0.0.1", help="host of db server"),
        cfg.IntOpt("port", default=27017, help="port of db server"),
        cfg.StrOpt("db_name", default="st2", help="name of database"),
        cfg.StrOpt("username", help="username for db login"),
        cfg.StrOpt("password", help="password for db login"),
        cfg.IntOpt(
            "connection_retry_max_delay_m",
            default=3,
            help="Connection retry total time (minutes).",
        ),
        cfg.IntOpt(
            "connection_retry_backoff_max_s",
            default=10,
            help="Connection retry backoff max (seconds).",
        ),
        cfg.IntOpt(
            "connection_retry_backoff_mul",
            default=1,
            help="Backoff multiplier (seconds).",
        ),
        cfg.BoolOpt(
            "ssl", default=False, help="Create the connection to mongodb using SSL"
        ),
        cfg.StrOpt(
            "ssl_keyfile",
            default=None,
            help="Private keyfile used to identify the local connection against MongoDB.",
        ),
        cfg.StrOpt(
            "ssl_certfile",
            default=None,
            help="Certificate file used to identify the localconnection",
        ),
        cfg.StrOpt(
            "ssl_cert_reqs",
            default=None,
            choices="none, optional, required",
            help="Specifies whether a certificate is required from the other side of the "
            "connection, and whether it will be validated if provided",
        ),
        cfg.StrOpt(
            "ssl_ca_certs",
            default=None,
            help="ca_certs file contains a set of concatenated CA certificates, which are "
            "used to validate certificates passed from MongoDB.",
        ),
        cfg.BoolOpt(
            "ssl_match_hostname",
            default=True,
            help="If True and `ssl_cert_reqs` is not None, enables hostname verification",
        ),
        cfg.StrOpt(
            "authentication_mechanism",
            default=None,
            help="Specifies database authentication mechanisms. "
            "By default, it use SCRAM-SHA-1 with MongoDB 3.0 and later, "
            "MONGODB-CR (MongoDB Challenge Response protocol) for older servers.",
        ),
    ]

    do_register_opts(db_opts, "database", ignore_errors)

    messaging_opts = [
        # It would be nice to be able to deprecate url and completely switch to using
        # url. However, this will be a breaking change and will have impact so allowing both.
        cfg.StrOpt(
            "url",
            default="amqp://guest:guest@127.0.0.1:5672//",
            help="URL of the messaging server.",
        ),
        cfg.ListOpt(
            "cluster_urls",
            default=[],
            help="URL of all the nodes in a messaging service cluster.",
        ),
        cfg.IntOpt(
            "connection_retries",
            default=10,
            help="How many times should we retry connection before failing.",
        ),
        cfg.IntOpt(
            "connection_retry_wait",
            default=10000,
            help="How long should we wait between connection retries.",
        ),
        cfg.BoolOpt(
            "ssl",
            default=False,
            help="Use SSL / TLS to connect to the messaging server. Same as "
            'appending "?ssl=true" at the end of the connection URL string.',
        ),
        cfg.StrOpt(
            "ssl_keyfile",
            default=None,
            help="Private keyfile used to identify the local connection against RabbitMQ.",
        ),
        cfg.StrOpt(
            "ssl_certfile",
            default=None,
            help="Certificate file used to identify the local connection (client).",
        ),
        cfg.StrOpt(
            "ssl_cert_reqs",
            default=None,
            choices="none, optional, required",
            help="Specifies whether a certificate is required from the other side of the "
            "connection, and whether it will be validated if provided.",
        ),
        cfg.StrOpt(
            "ssl_ca_certs",
            default=None,
            help="ca_certs file contains a set of concatenated CA certificates, which are "
            "used to validate certificates passed from RabbitMQ.",
        ),
        cfg.StrOpt(
            "login_method",
            default=None,
            help="Login method to use (AMQPLAIN, PLAIN, EXTERNAL, etc.).",
        ),
    ]

    do_register_opts(messaging_opts, "messaging", ignore_errors)

    syslog_opts = [
        cfg.StrOpt("host", default="127.0.0.1", help="Host for the syslog server."),
        cfg.IntOpt("port", default=514, help="Port for the syslog server."),
        cfg.StrOpt("facility", default="local7", help="Syslog facility level."),
        cfg.StrOpt(
            "protocol", default="udp", help="Transport protocol to use (udp / tcp)."
        ),
    ]

    do_register_opts(syslog_opts, "syslog", ignore_errors)

    log_opts = [
        cfg.ListOpt("excludes", default="", help="Exclusion list of loggers to omit."),
        cfg.BoolOpt(
            "redirect_stderr",
            default=False,
            help="Controls if stderr should be redirected to the logs.",
        ),
        cfg.BoolOpt(
            "mask_secrets", default=True, help="True to mask secrets in the log files."
        ),
        cfg.ListOpt(
            "mask_secrets_blacklist",
            default=[],
            help="Blacklist of additional attribute names to mask in the log messages.",
        ),
    ]

    do_register_opts(log_opts, "log", ignore_errors)

    # Common API options
    api_opts = [
        cfg.StrOpt("host", default="127.0.0.1", help="StackStorm API server host"),
        cfg.IntOpt("port", default=9101, help="StackStorm API server port"),
        cfg.ListOpt(
            "allow_origin",
            default=["http://127.0.0.1:3000"],
            help="List of origins allowed for api, auth and stream",
        ),
        cfg.BoolOpt(
            "mask_secrets",
            default=True,
            help="True to mask secrets in the API responses",
        ),
    ]

    do_register_opts(api_opts, "api", ignore_errors)

    # Key Value store options
    keyvalue_opts = [
        cfg.BoolOpt(
            "enable_encryption",
            default=True,
            help='Allow encryption of values in key value stored qualified as "secret".',
        ),
        cfg.StrOpt(
            "encryption_key_path",
            default="",
            help="Location of the symmetric encryption key for encrypting values in kvstore. "
            "This key should be in JSON and should've been generated using "
            "st2-generate-symmetric-crypto-key tool.",
        ),
    ]

    do_register_opts(keyvalue_opts, group="keyvalue")

    # Common auth options
    auth_opts = [
        cfg.StrOpt(
            "api_url",
            default=None,
            help="Base URL to the API endpoint excluding the version",
        ),
        cfg.BoolOpt("enable", default=True, help="Enable authentication middleware."),
        cfg.IntOpt(
            "token_ttl", default=(24 * 60 * 60), help="Access token ttl in seconds."
        ),
        # This TTL is used for tokens which belong to StackStorm services
        cfg.IntOpt(
            "service_token_ttl",
            default=(24 * 60 * 60),
            help="Service token ttl in seconds.",
        ),
    ]

    do_register_opts(auth_opts, "auth", ignore_errors)

    # Runner options
    default_python_bin_path = sys.executable
    default_python3_bin_path = find_executable("python3")
    base_dir = os.path.dirname(os.path.realpath(default_python_bin_path))
    default_virtualenv_bin_path = os.path.join(base_dir, "virtualenv")

    action_runner_opts = [
        # Common runner options
        cfg.StrOpt(
            "logging",
            default="/etc/st2/logging.actionrunner.conf",
            help="location of the logging.conf file",
        ),
        # Python runner options
        cfg.StrOpt(
            "python_binary",
            default=default_python_bin_path,
            help="Python binary which will be used by Python actions.",
        ),
        cfg.StrOpt(
            "python3_binary",
            default=default_python3_bin_path,
            help="Python 3 binary which will be used by Python actions for packs which "
            "use Python 3 virtual environment.",
        ),
        cfg.StrOpt(
            "python3_prefix",
            default=None,
            help="Prefix for Python 3 installation (e.g. /opt/python3.6). If not specified, it "
            "tries to find Python 3 libraries in /usr/lib and /usr/local/lib.",
        ),
        cfg.StrOpt(
            "virtualenv_binary",
            default=default_virtualenv_bin_path,
            help="Virtualenv binary which should be used to create pack virtualenvs.",
        ),
        cfg.StrOpt(
            "python_runner_log_level",
            default=PYTHON_RUNNER_DEFAULT_LOG_LEVEL,
            help="Default log level to use for Python runner actions. Can be overriden on "
            'invocation basis using "log_level" runner parameter.',
        ),
        cfg.ListOpt(
            "virtualenv_opts",
            default=["--system-site-packages"],
            help='List of virtualenv options to be passsed to "virtualenv" command that '
            "creates pack virtualenv.",
        ),
        cfg.BoolOpt(
            "stream_output",
            default=True,
            help="True to store and stream action output (stdout and stderr) in real-time.",
        ),
    ]

    do_register_opts(action_runner_opts, group="actionrunner")

    dispatcher_pool_opts = [
        cfg.IntOpt(
            "workflows_pool_size",
            default=40,
            help="Internal pool size for dispatcher used by workflow actions.",
        ),
        cfg.IntOpt(
            "actions_pool_size",
            default=60,
            help="Internal pool size for dispatcher used by regular actions.",
        ),
    ]

    do_register_opts(dispatcher_pool_opts, group="actionrunner")

    ssh_runner_opts = [
        cfg.StrOpt(
            "remote_dir",
            default="/tmp",
            help="Location of the script on the remote filesystem.",
        ),
        cfg.BoolOpt(
            "allow_partial_failure",
            default=False,
            help="How partial success of actions run on multiple nodes should be treated.",
        ),
        cfg.IntOpt(
            "max_parallel_actions",
            default=50,
            help="Max number of parallel remote SSH actions that should be run. "
            "Works only with Paramiko SSH runner.",
        ),
        cfg.BoolOpt(
            "use_ssh_config",
            default=False,
            help="Use the .ssh/config file. Useful to override ports etc.",
        ),
        cfg.StrOpt(
            "ssh_config_file_path",
            default="~/.ssh/config",
            help="Path to the ssh config file.",
        ),
    ]

    do_register_opts(ssh_runner_opts, group="ssh_runner")

    # Common options (used by action runner and sensor container)
    action_sensor_opts = [
        cfg.BoolOpt(
            "enable",
            default=True,
            help="Whether to enable or disable the ability to post a trigger on action.",
        ),
        cfg.ListOpt(
            "emit_when",
            default=LIVEACTION_COMPLETED_STATES,
            help="List of execution statuses for which a trigger will be emitted. ",
        ),
    ]

    do_register_opts(action_sensor_opts, group="action_sensor")

    # Common options for content
    pack_lib_opts = [
        cfg.BoolOpt(
            "enable_common_libs",
            default=False,
            help="Enable/Disable support for pack common libs. "
            "Setting this config to ``True`` would allow you to "
            "place common library code for sensors and actions in lib/ folder "
            "in packs and use them in python sensors and actions. "
            "See https://docs.stackstorm.com/reference/"
            "sharing_code_sensors_actions.html "
            "for details.",
        )
    ]

    do_register_opts(pack_lib_opts, group="packs")

    # Coordination options
    coord_opts = [
        cfg.StrOpt("url", default=None, help="Endpoint for the coordination server."),
        cfg.IntOpt(
            "lock_timeout", default=60, help="TTL for the lock if backend suports it."
        ),
        cfg.BoolOpt(
            "service_registry",
            default=False,
            help="True to register StackStorm services in a service registry.",
        ),
    ]

    do_register_opts(coord_opts, "coordination", ignore_errors)

    # Mistral options
    mistral_opts = [
        cfg.StrOpt(
            "v2_base_url",
            default="http://127.0.0.1:8989/v2",
            help="v2 API root endpoint.",
        ),
        cfg.IntOpt(
            "retry_exp_msec",
            default=1000,
            help="Multiplier for the exponential backoff.",
        ),
        cfg.IntOpt(
            "retry_exp_max_msec",
            default=300000,
            help="Max time for each set of backoff.",
        ),
        cfg.IntOpt(
            "retry_stop_max_msec", default=600000, help="Max time to stop retrying."
        ),
        cfg.StrOpt(
            "keystone_username", default=None, help="Username for authentication."
        ),
        cfg.StrOpt(
            "keystone_password", default=None, help="Password for authentication."
        ),
        cfg.StrOpt(
            "keystone_project_name", default=None, help="OpenStack project scope."
        ),
        cfg.StrOpt(
            "keystone_auth_url", default=None, help="Auth endpoint for Keystone."
        ),
        cfg.StrOpt(
            "cacert", default=None, help="Optional certificate to validate endpoint."
        ),
        cfg.BoolOpt(
            "insecure", default=False, help="Allow insecure communication with Mistral."
        ),
        cfg.BoolOpt(
            "enable_polling",
            default=False,
            help="Enable results tracking and disable callbacks.",
        ),
        cfg.FloatOpt(
            "jitter_interval",
            default=0.1,
            help="Jitter interval to smooth out HTTP requests "
            "to mistral tasks and executions API.",
        ),
        cfg.StrOpt(
            "api_url",
            default=None,
            help="URL Mistral uses to talk back to the API."
            "If not provided it defaults to public API URL. "
            "Note: This needs to be a base URL without API "
            "version (e.g. http://127.0.0.1:9101)",
        ),
    ]

    do_register_opts(mistral_opts, group="mistral", ignore_errors=ignore_errors)

    # Results Tracker query module options
    # Note that these are currently used only by mistral query module.
    query_opts = [
        cfg.IntOpt(
            "thread_pool_size",
            default=10,
            help="Number of threads to use to query external workflow systems.",
        ),
        cfg.FloatOpt(
            "query_interval",
            default=5,
            help="Time interval between queries to external workflow system.",
        ),
        cfg.FloatOpt(
            "empty_q_sleep_time",
            default=1,
            help="Sleep delay in between queries when query queue is empty.",
        ),
        cfg.FloatOpt(
            "no_workers_sleep_time",
            default=1,
            help="Sleep delay for query when there is no more worker in pool.",
        ),
    ]

    do_register_opts(query_opts, group="resultstracker", ignore_errors=ignore_errors)

    # XXX: This is required for us to support deprecated config group results_tracker
    query_opts = [
        cfg.IntOpt(
            "thread_pool_size",
            help="Number of threads to use to query external workflow systems.",
        ),
        cfg.FloatOpt(
            "query_interval",
            help="Time interval between subsequent queries for a context "
            "to external workflow system.",
        ),
    ]

    do_register_opts(query_opts, group="results_tracker", ignore_errors=ignore_errors)

    # Common stream options
    stream_opts = [
        cfg.IntOpt(
            "heartbeat",
            default=25,
            help="Send empty message every N seconds to keep connection open",
        )
    ]

    do_register_opts(stream_opts, group="stream", ignore_errors=ignore_errors)

    # Common CLI options
    cli_opts = [
        cfg.BoolOpt(
            "debug",
            default=False,
            help="Enable debug mode. By default this will set all log levels to DEBUG.",
        ),
        cfg.BoolOpt(
            "profile",
            default=False,
            help="Enable profile mode. In the profile mode all the MongoDB queries and "
            "related profile data are logged.",
        ),
        cfg.BoolOpt(
            "use-debugger",
            default=True,
            help="Enables debugger. Note that using this option changes how the "
            "eventlet library is used to support async IO. This could result in "
            "failures that do not occur under normal operation.",
        ),
    ]

    do_register_cli_opts(cli_opts, ignore_errors=ignore_errors)

    # Metrics Options stream options
    metrics_opts = [
        cfg.StrOpt(
            "driver", default="noop", help="Driver type for metrics collection."
        ),
        cfg.StrOpt(
            "host",
            default="127.0.0.1",
            help="Destination server to connect to if driver requires connection.",
        ),
        cfg.IntOpt(
            "port",
            default=8125,
            help="Destination port to connect to if driver requires connection.",
        ),
        cfg.StrOpt(
            "prefix",
            default=None,
            help="Optional prefix which is prepended to all the metric names. Comes handy when "
            "you want to submit metrics from various environment to the same metric "
            "backend instance.",
        ),
        cfg.FloatOpt(
            "sample_rate",
            default=1,
            help="Randomly sample and only send metrics for X% of metric operations to the "
            "backend. Default value of 1 means no sampling is done and all the metrics are "
            "sent to the backend. E.g. 0.1 would mean 10% of operations are sampled.",
        ),
    ]

    do_register_opts(metrics_opts, group="metrics", ignore_errors=ignore_errors)

    # Common timers engine options
    timer_logging_opts = [
        cfg.StrOpt(
            "logging",
            default=None,
            help="Location of the logging configuration file. "
            "NOTE: Deprecated in favor of timersengine.logging",
        ),
    ]

    timers_engine_logging_opts = [
        cfg.StrOpt(
            "logging",
            default="/etc/st2/logging.timersengine.conf",
            help="Location of the logging configuration file.",
        )
    ]

    do_register_opts(timer_logging_opts, group="timer", ignore_errors=ignore_errors)
    do_register_opts(
        timers_engine_logging_opts, group="timersengine", ignore_errors=ignore_errors
    )

    # NOTE: We default old style deprecated "timer" options to None so our code
    # works correclty and "timersengine" has precedence over "timers"
    # NOTE: "timer" section will be removed in v3.1
    timer_opts = [
        cfg.StrOpt(
            "local_timezone",
            default=None,
            help="Timezone pertaining to the location where st2 is run. "
            "NOTE: Deprecated in favor of timersengine.local_timezone",
        ),
        cfg.BoolOpt(
            "enable",
            default=None,
            help="Specify to enable timer service. "
            "NOTE: Deprecated in favor of timersengine.enable",
        ),
    ]

    timers_engine_opts = [
        cfg.StrOpt(
            "local_timezone",
            default="America/Los_Angeles",
            help="Timezone pertaining to the location where st2 is run.",
        ),
        cfg.BoolOpt("enable", default=True, help="Specify to enable timer service."),
    ]
    do_register_opts(timer_opts, group="timer", ignore_errors=ignore_errors)
    do_register_opts(
        timers_engine_opts, group="timersengine", ignore_errors=ignore_errors
    )

    # Workflow engine options
    workflow_engine_opts = [
        cfg.IntOpt(
            "retry_stop_max_msec", default=60000, help="Max time to stop retrying."
        ),
        cfg.IntOpt(
            "retry_wait_fixed_msec", default=1000, help="Interval inbetween retries."
        ),
        cfg.FloatOpt(
            "retry_max_jitter_msec",
            default=1000,
            help="Max jitter interval to smooth out retries.",
        ),
        cfg.IntOpt(
            "gc_max_idle_sec",
            default=900,
            help="Max seconds to allow workflow execution be idled before it is identified as "
            "orphaned and cancelled by the garbage collector.",
        ),
    ]

    do_register_opts(
        workflow_engine_opts, group="workflow_engine", ignore_errors=ignore_errors
    )