conf: Move VPNaaS configuration options to neutron_vpnaas/conf

Centralize oslo.config option definitions under neutron_vpnaas/conf,
following the neutron/conf layout. Existing modules re-export opts and
register them at import time for backward compatibility.

This patch does not change any existing configuration option or section.
That can be confirmed by executing the following commands:
  tox -e pep8
  tox -e py-dev
  tox -e genconfig   # verify neutron_vpnaas.conf.sample is unchanged

Closes-Bug: #2166744
Signed-off-by: Rodolfo Alonso Hernandez <ralonsoh@redhat.com>
Change-Id: I73f07d946ee1eb97494a832fa44032b0bf9d72fb
This commit is contained in:
Rodolfo Alonso Hernandez authored and Rodolfo Alonso committed 2026-09-24 11:21:59 +00:00
1 parent 4285f290c4
commit b0b5a5e9b2
18 files changed
+352 -184

No files matched your search

View File
Whitespace-only changes.
Whitespace-only changes.
+48
View File
@@ -0,0 +1,48 @@
# Copyright 2023, SysEleven GmbH
# Copyright 2026 OpenStack Foundation
# All Rights Reserved.
#
# 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.
from oslo_config import cfg
from neutron_vpnaas._i18n import _
VPN_AGENT_OPTS = [
cfg.MultiStrOpt(
'vpn_device_driver',
default=['neutron_vpnaas.services.vpn.device_drivers.'
'ovn_ipsec.OvnStrongSwanDriver'],
sample_default=['neutron_vpnaas.services.vpn.device_drivers.'
'ovn_ipsec.OvnStrongSwanDriver'],
help=_("The OVN VPN device drivers Neutron will use")),
]
OVS_OPTS = [
cfg.StrOpt('ovsdb_connection',
default='unix:/usr/local/var/run/openvswitch/db.sock',
regex=r'^(tcp|ssl|unix):.+',
help=_('The connection string for the native OVSDB backend.\n'
'Use tcp:IP:PORT for TCP connection.\n'
'Use unix:FILE for unix domain socket connection.')),
cfg.IntOpt('ovsdb_connection_timeout',
default=180,
help=_('Timeout in seconds for the OVSDB '
'connection transaction'))
]
def register_ovn_vpn_agent_opts(conf=cfg.CONF):
conf.register_opts(VPN_AGENT_OPTS, 'vpnagent')
conf.register_opts(OVS_OPTS, 'ovs')
+37
View File
@@ -0,0 +1,37 @@
# Copyright 2013, Nachi Ueno, NTT I3, Inc.
# Copyright 2017, Fujitsu Limited
# Copyright 2026 OpenStack Foundation
# All Rights Reserved.
#
# 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.
from oslo_config import cfg
from neutron_vpnaas._i18n import _
vpn_agent_opts = [
cfg.MultiStrOpt(
'vpn_device_driver',
default=['neutron_vpnaas.services.vpn.device_drivers.'
'libreswan_ipsec.LibreSwanDriver'],
sample_default=['neutron_vpnaas.services.vpn.device_drivers.'
'libreswan_ipsec.LibreSwanDriver, '
'neutron_vpnaas.services.vpn.device_drivers.'
'strongswan_ipsec.StrongSwanDriver'],
help=_("The vpn device drivers Neutron will use")),
]
def register_vpn_agent_opts(conf=cfg.CONF):
conf.register_opts(vpn_agent_opts, 'vpnagent')
View File
Whitespace-only changes.
@@ -0,0 +1,38 @@
# Copyright (c) 2013 OpenStack Foundation.
# Copyright (c) 2023 SysEleven GmbH.
# Copyright 2026 OpenStack Foundation
# All Rights Reserved.
#
# 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.
from oslo_config import cfg
from neutron_vpnaas._i18n import _
VPN_AGENTS_SCHEDULER_OPTS = [
cfg.StrOpt('vpn_scheduler_driver',
default='neutron_vpnaas.scheduler.vpn_agent_scheduler'
'.LeastRoutersScheduler',
help=_('Driver to use for scheduling '
'router to a VPN agent')),
cfg.BoolOpt('vpn_auto_schedule', default=True,
help=_('Allow auto scheduling of routers to VPN agent.')),
cfg.BoolOpt('allow_automatic_vpnagent_failover', default=False,
help=_('Automatically reschedule routers from offline VPN '
'agents to online VPN agents.')),
]
def register_db_vpn_agentschedulers_opts(conf=cfg.CONF):
conf.register_opts(VPN_AGENTS_SCHEDULER_OPTS)
Whitespace-only changes.
Whitespace-only changes.
+67
View File
@@ -0,0 +1,67 @@
# Copyright 2013, Nachi Ueno, NTT I3, Inc.
# Copyright 2026 OpenStack Foundation
# All Rights Reserved.
#
# 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.
from oslo_config import cfg
from neutron_vpnaas._i18n import _
ipsec_opts = [
cfg.StrOpt(
'config_base_dir',
default='$state_path/ipsec',
help=_('Location to store ipsec server config files')),
cfg.IntOpt('ipsec_status_check_interval',
default=60,
help=_("Interval for checking ipsec status")),
cfg.BoolOpt('enable_detailed_logging',
default=False,
help=_("Enable detail logging for ipsec pluto process. "
"If the flag set to True, the detailed logging will "
"be written into config_base_dir/<pid>/log. "
"Note: This setting applies to LibreSwan "
"only. StrongSwan logs to syslog.")),
]
pluto_opts = [
cfg.IntOpt('shutdown_check_timeout',
default=1,
help=_('Initial interval in seconds for checking if pluto '
'daemon is shutdown'),
deprecated_group='libreswan'),
cfg.IntOpt('shutdown_check_retries',
default=5,
help=_('The maximum number of retries for checking for '
'pluto daemon shutdown'),
deprecated_group='libreswan'),
cfg.FloatOpt('shutdown_check_back_off',
default=1.5,
help=_('A factor to increase the retry interval for '
'each retry'),
deprecated_group='libreswan'),
cfg.BoolOpt('restart_check_config',
default=False,
help=_('Enable this flag to avoid from unnecessary restart'),
deprecated_group='libreswan')
]
def register_ipsec_opts(conf=cfg.CONF):
conf.register_opts(ipsec_opts, 'ipsec')
def register_pluto_opts(conf=cfg.CONF):
conf.register_opts(pluto_opts, 'pluto')
@@ -0,0 +1,45 @@
# Copyright (c) 2015 Red Hat, Inc.
# Copyright 2026 OpenStack Foundation
# All Rights Reserved.
#
# 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
from oslo_config import cfg
from neutron_vpnaas._i18n import _
_TEMPLATE_PATH = os.path.abspath(os.path.join(
os.path.dirname(__file__),
'../../../services/vpn/device_drivers'))
libreswan_opts = [
cfg.StrOpt(
'ipsec_config_template',
default=os.path.join(
_TEMPLATE_PATH,
'template/libreswan/ipsec.conf.template'),
help=_('Template file for ipsec configuration')),
cfg.StrOpt(
'ipsec_secret_template',
default=os.path.join(
_TEMPLATE_PATH,
'template/libreswan/ipsec.secret.template'),
help=_('Template file for ipsec secret configuration'))
]
def register_libreswan_opts(conf=cfg.CONF):
conf.register_opts(libreswan_opts, 'libreswan')
@@ -0,0 +1,84 @@
# Copyright (c) 2015 Canonical, Inc.
# Copyright 2026 OpenStack Foundation
# All Rights Reserved.
#
# 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
from oslo_config import cfg
from neutron_vpnaas._i18n import _
_TEMPLATE_PATH = os.path.abspath(os.path.join(
os.path.dirname(__file__),
'../../../services/vpn/device_drivers'))
strongswan_opts = [
cfg.StrOpt(
'ipsec_config_template',
default=os.path.join(
_TEMPLATE_PATH,
'template/strongswan/ipsec.conf.template'),
help=_('Template file for ipsec configuration.')),
cfg.StrOpt(
'strongswan_config_template',
default=os.path.join(
_TEMPLATE_PATH,
'template/strongswan/strongswan.conf.template'),
help=_('Template file for strongswan configuration.')),
cfg.StrOpt(
'ipsec_secret_template',
default=os.path.join(
_TEMPLATE_PATH,
'template/strongswan/ipsec.secret.template'),
help=_('Template file for ipsec secret configuration.')),
cfg.StrOpt(
'default_config_area',
default='/etc/strongswan.d',
help=_('The area where default StrongSwan configuration '
'files are located.')),
cfg.BoolOpt(
'use_swanctl',
default=True,
deprecated_since='2027.1',
deprecated_reason=_('The use_swanctl option is deprecated and will be '
'removed in the 2027.2 release. ``swanctl`` mode '
'is the default behavior.'),
help=_('Use ``swanctl`` (VICI protocol) instead of legacy stroke '
'interface. When True, configuration files are generated in '
'/etc/swanctl/ and charon is managed via systemd.')),
cfg.StrOpt(
'swanctl_config_template',
default=os.path.join(
_TEMPLATE_PATH,
'template/swanctl/swanctl.conf.template'),
help=_('Template file for swanctl configuration.')),
cfg.StrOpt(
'swanctl_secrets_template',
default=os.path.join(
_TEMPLATE_PATH,
'template/swanctl/ipsec.secrets.template'),
help=_('Template file for swanctl secrets configuration.')),
cfg.StrOpt(
'swanctl_config_dir',
default='/etc/swanctl',
help=_('Directory where swanctl loads its configuration from. '
'This directory must contain swanctl.conf, connections/, '
'secrets/.'))
]
def register_strongswan_opts(conf=cfg.CONF):
conf.register_opts(strongswan_opts, 'strongswan')
@@ -20,14 +20,13 @@ from neutron_lib.db import api as db_api
from neutron_lib.db import model_base
from neutron_lib.plugins import constants as plugin_const
from neutron_lib.plugins import directory
from oslo_config import cfg
from oslo_db import exception as db_exc
from oslo_log import log as logging
import oslo_messaging
import sqlalchemy as sa
from sqlalchemy import func
from neutron_vpnaas._i18n import _
from neutron_vpnaas.conf.db import vpn_agentschedulers_db as vpn_scheduler_conf
from neutron_vpnaas.db.vpn import vpn_models
from neutron_vpnaas.extensions import vpn_agentschedulers
from neutron_vpnaas.services.vpn.common.constants import AGENT_TYPE_VPN
@@ -35,20 +34,8 @@ from neutron_vpnaas.services.vpn.common.constants import AGENT_TYPE_VPN
LOG = logging.getLogger(__name__)
VPN_AGENTS_SCHEDULER_OPTS = [
cfg.StrOpt('vpn_scheduler_driver',
default='neutron_vpnaas.scheduler.vpn_agent_scheduler'
'.LeastRoutersScheduler',
help=_('Driver to use for scheduling '
'router to a VPN agent')),
cfg.BoolOpt('vpn_auto_schedule', default=True,
help=_('Allow auto scheduling of routers to VPN agent.')),
cfg.BoolOpt('allow_automatic_vpnagent_failover', default=False,
help=_('Automatically reschedule routers from offline VPN '
'agents to online VPN agents.')),
]
cfg.CONF.register_opts(VPN_AGENTS_SCHEDULER_OPTS)
VPN_AGENTS_SCHEDULER_OPTS = vpn_scheduler_conf.VPN_AGENTS_SCHEDULER_OPTS
vpn_scheduler_conf.register_db_vpn_agentschedulers_opts()
class RouterVPNAgentBinding(model_base.BASEV2):
+11 -11
View File
@@ -13,32 +13,32 @@
from neutron.conf.plugins.ml2.drivers.ovn import ovn_conf
from neutron.services import provider_configuration
from neutron_vpnaas.db.vpn import vpn_agentschedulers_db
from neutron_vpnaas.services.vpn import agent as vpn_agent
from neutron_vpnaas.services.vpn.device_drivers import ipsec
from neutron_vpnaas.services.vpn.device_drivers import libreswan_ipsec
from neutron_vpnaas.services.vpn.device_drivers import strongswan_ipsec
from neutron_vpnaas.services.vpn import ovn_agent
from neutron_vpnaas.conf.agent import ovn_agent
from neutron_vpnaas.conf.agent import vpn_agent
from neutron_vpnaas.conf.db import vpn_agentschedulers_db
from neutron_vpnaas.conf.services.vpn import ipsec
from neutron_vpnaas.conf.services.vpn import libreswan
from neutron_vpnaas.conf.services.vpn import strongswan
def list_agent_opts():
return [
('vpnagent', vpn_agent.vpn_agent_opts),
('ipsec', ipsec.ipsec_opts),
('libreswan', libreswan_ipsec.libreswan_opts),
('strongswan', strongswan_ipsec.strongswan_opts),
('libreswan', libreswan.libreswan_opts),
('strongswan', strongswan.strongswan_opts),
('pluto', ipsec.pluto_opts)
]
def list_ovn_agent_opts():
return [
('vpnagent', vpn_agent.vpn_agent_opts),
('vpnagent', ovn_agent.VPN_AGENT_OPTS),
('ovs', ovn_agent.OVS_OPTS),
('ovn', ovn_conf.ovn_opts),
('ipsec', ipsec.ipsec_opts),
('libreswan', libreswan_ipsec.libreswan_opts),
('strongswan', strongswan_ipsec.strongswan_opts),
('libreswan', libreswan.libreswan_opts),
('strongswan', strongswan.strongswan_opts),
('pluto', ipsec.pluto_opts)
]
+3 -13
View File
@@ -19,23 +19,13 @@ from neutron_lib.agent import l3_extension
from oslo_config import cfg
from oslo_log import log as logging
from neutron_vpnaas._i18n import _
from neutron_vpnaas.conf.agent import vpn_agent as vpn_agent_conf
from neutron_vpnaas.services.vpn import vpn_service
LOG = logging.getLogger(__name__)
vpn_agent_opts = [
cfg.MultiStrOpt(
'vpn_device_driver',
default=['neutron_vpnaas.services.vpn.device_drivers.'
'libreswan_ipsec.LibreSwanDriver'],
sample_default=['neutron_vpnaas.services.vpn.device_drivers.'
'libreswan_ipsec.LibreSwanDriver, '
'neutron_vpnaas.services.vpn.device_drivers.'
'strongswan_ipsec.StrongSwanDriver'],
help=_("The vpn device drivers Neutron will use")),
]
cfg.CONF.register_opts(vpn_agent_opts, 'vpnagent')
vpn_agent_opts = vpn_agent_conf.vpn_agent_opts
vpn_agent_conf.register_vpn_agent_opts()
class VPNAgent(l3_extension.L3AgentExtension):
@@ -38,54 +38,16 @@ from oslo_service import loopingcall
from oslo_utils import encodeutils
from oslo_utils import fileutils
from neutron_vpnaas._i18n import _
from neutron_vpnaas.conf.services.vpn import ipsec as ipsec_conf
from neutron_vpnaas.services.vpn.common import topics
from neutron_vpnaas.services.vpn import device_drivers
LOG = logging.getLogger(__name__)
ipsec_opts = [
cfg.StrOpt(
'config_base_dir',
default='$state_path/ipsec',
help=_('Location to store ipsec server config files')),
cfg.IntOpt('ipsec_status_check_interval',
default=60,
help=_("Interval for checking ipsec status")),
cfg.BoolOpt('enable_detailed_logging',
default=False,
help=_("Enable detail logging for ipsec pluto process. "
"If the flag set to True, the detailed logging will "
"be written into config_base_dir/<pid>/log. "
"Note: This setting applies to LibreSwan "
"only. StrongSwan logs to syslog.")),
]
cfg.CONF.register_opts(ipsec_opts, 'ipsec')
pluto_opts = [
cfg.IntOpt('shutdown_check_timeout',
default=1,
help=_('Initial interval in seconds for checking if pluto '
'daemon is shutdown'),
deprecated_group='libreswan'),
cfg.IntOpt('shutdown_check_retries',
default=5,
help=_('The maximum number of retries for checking for '
'pluto daemon shutdown'),
deprecated_group='libreswan'),
cfg.FloatOpt('shutdown_check_back_off',
default=1.5,
help=_('A factor to increase the retry interval for '
'each retry'),
deprecated_group='libreswan'),
cfg.BoolOpt('restart_check_config',
default=False,
help=_('Enable this flag to avoid from unnecessary restart'),
deprecated_group='libreswan')
]
cfg.CONF.register_opts(pluto_opts, 'pluto')
ipsec_opts = ipsec_conf.ipsec_opts
pluto_opts = ipsec_conf.pluto_opts
ipsec_conf.register_ipsec_opts()
ipsec_conf.register_pluto_opts()
JINJA_ENV = None
@@ -26,28 +26,13 @@ from neutron_lib.exceptions import vpn as vpn_exception
from oslo_config import cfg
from oslo_log import log as logging
from neutron_vpnaas._i18n import _
from neutron_vpnaas.conf.services.vpn import libreswan as libreswan_conf
from neutron_vpnaas.services.vpn.device_drivers import ipsec
LOG = logging.getLogger(__name__)
TEMPLATE_PATH = os.path.dirname(os.path.abspath(__file__))
libreswan_opts = [
cfg.StrOpt(
'ipsec_config_template',
default=os.path.join(
TEMPLATE_PATH,
'template/libreswan/ipsec.conf.template'),
help=_('Template file for ipsec configuration')),
cfg.StrOpt(
'ipsec_secret_template',
default=os.path.join(
TEMPLATE_PATH,
'template/libreswan/ipsec.secret.template'),
help=_('Template file for ipsec secret configuration'))
]
cfg.CONF.register_opts(libreswan_opts, 'libreswan')
libreswan_opts = libreswan_conf.libreswan_opts
libreswan_conf.register_libreswan_opts()
class LibreSwanProcess(ipsec.BaseSwanProcess):
@@ -26,67 +26,14 @@ from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import fileutils
from neutron_vpnaas._i18n import _
from neutron_vpnaas.conf.services.vpn import strongswan as strongswan_conf
from neutron_vpnaas.services.vpn.device_drivers import ipsec
LOG = logging.getLogger(__name__)
TEMPLATE_PATH = os.path.dirname(os.path.abspath(__file__))
strongswan_opts = [
cfg.StrOpt(
'ipsec_config_template',
default=os.path.join(
TEMPLATE_PATH,
'template/strongswan/ipsec.conf.template'),
help=_('Template file for ipsec configuration.')),
cfg.StrOpt(
'strongswan_config_template',
default=os.path.join(
TEMPLATE_PATH,
'template/strongswan/strongswan.conf.template'),
help=_('Template file for strongswan configuration.')),
cfg.StrOpt(
'ipsec_secret_template',
default=os.path.join(
TEMPLATE_PATH,
'template/strongswan/ipsec.secret.template'),
help=_('Template file for ipsec secret configuration.')),
cfg.StrOpt(
'default_config_area',
default='/etc/strongswan.d',
help=_('The area where default StrongSwan configuration '
'files are located.')),
# swanctl options
cfg.BoolOpt(
'use_swanctl',
default=True,
deprecated_since='2027.1',
deprecated_reason=_('The use_swanctl option is deprecated and will be '
'removed in the 2027.2 release. ``swanctl`` mode '
'is the default behavior.'),
help=_('Use ``swanctl`` (VICI protocol) instead of legacy stroke '
'interface. When True, configuration files are generated in '
'/etc/swanctl/ and charon is managed via systemd.')),
cfg.StrOpt(
'swanctl_config_template',
default=os.path.join(
TEMPLATE_PATH,
'template/swanctl/swanctl.conf.template'),
help=_('Template file for swanctl configuration.')),
cfg.StrOpt(
'swanctl_secrets_template',
default=os.path.join(
TEMPLATE_PATH,
'template/swanctl/ipsec.secrets.template'),
help=_('Template file for swanctl secrets configuration.')),
cfg.StrOpt(
'swanctl_config_dir',
default='/etc/swanctl',
help=_('Directory where swanctl loads its configuration from. '
'This directory must contain swanctl.conf, connections/, '
'secrets/.'))
]
cfg.CONF.register_opts(strongswan_opts, 'strongswan')
strongswan_opts = strongswan_conf.strongswan_opts
strongswan_conf.register_strongswan_opts()
class StrongSwanProcess(ipsec.BaseSwanProcess):
+4 -26
View File
@@ -22,34 +22,13 @@ from oslo_config import cfg
from oslo_log import log as logging
from oslo_service import service
from neutron_vpnaas._i18n import _
from neutron_vpnaas.agent.ovn.vpn import agent
from neutron_vpnaas.conf.agent import ovn_agent as ovn_agent_conf
LOG = logging.getLogger(__name__)
VPN_AGENT_OPTS = [
cfg.MultiStrOpt(
'vpn_device_driver',
default=['neutron_vpnaas.services.vpn.device_drivers.'
'ovn_ipsec.OvnStrongSwanDriver'],
sample_default=['neutron_vpnaas.services.vpn.device_drivers.'
'ovn_ipsec.OvnStrongSwanDriver'],
help=_("The OVN VPN device drivers Neutron will use")),
]
OVS_OPTS = [
cfg.StrOpt('ovsdb_connection',
default='unix:/usr/local/var/run/openvswitch/db.sock',
regex=r'^(tcp|ssl|unix):.+',
help=_('The connection string for the native OVSDB backend.\n'
'Use tcp:IP:PORT for TCP connection.\n'
'Use unix:FILE for unix domain socket connection.')),
cfg.IntOpt('ovsdb_connection_timeout',
default=180,
help=_('Timeout in seconds for the OVSDB '
'connection transaction'))
]
VPN_AGENT_OPTS = ovn_agent_conf.VPN_AGENT_OPTS
OVS_OPTS = ovn_agent_conf.OVS_OPTS
def register_opts(conf):
@@ -58,8 +37,7 @@ def register_opts(conf):
agent_config.register_interface_opts(conf)
agent_config.register_availability_zone_opts_helper(conf)
ovn_conf.register_opts()
conf.register_opts(VPN_AGENT_OPTS, 'vpnagent')
conf.register_opts(OVS_OPTS, 'ovs')
ovn_agent_conf.register_ovn_vpn_agent_opts(conf)
def main():