Switch to a single config file, using a config group per service.

This has two advantages:

 - Avoids Naming Conflicts (e.g. backend-driver)
 - Allows common options to be specified once for all services (e.g. pybasedir, logdir)

Fixs bug #1096850

Change-Id: I5b02f591ccea6d1a8201b21c3cb8f92bcf6b30fa
This commit is contained in:
Kiall Mac Innes 2013-01-08 11:06:56 +00:00
parent f4c0f899d8
commit bc5fa37b20
24 changed files with 205 additions and 109 deletions

View File

@ -23,7 +23,7 @@ from moniker.agent import service as agent_service
eventlet.monkey_patch() eventlet.monkey_patch()
utils.read_config('moniker-agent', sys.argv) utils.read_config('moniker', sys.argv)
logging.setup('moniker') logging.setup('moniker')

View File

@ -23,7 +23,7 @@ from moniker.api import service as api_service
eventlet.monkey_patch() eventlet.monkey_patch()
utils.read_config('moniker-api', sys.argv) utils.read_config('moniker', sys.argv)
logging.setup('moniker') logging.setup('moniker')

View File

@ -23,7 +23,7 @@ from moniker.central import service as central_service
eventlet.monkey_patch() eventlet.monkey_patch()
utils.read_config('moniker-central', sys.argv) utils.read_config('moniker', sys.argv)
logging.setup('moniker') logging.setup('moniker')

View File

@ -15,7 +15,11 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import sys import sys
from moniker import utils
from moniker.manage import MonikerShell from moniker.manage import MonikerShell
# TODO: Sypport passing --config-file and --config-dir to read_config
utils.read_config('moniker', [])
shell = MonikerShell() shell = MonikerShell()
sys.exit(shell.run(sys.argv)) sys.exit(shell.run(sys.argv[1:]))

View File

@ -1,39 +0,0 @@
[DEFAULT]
# Show more verbose log output (sets INFO log level output)
verbose = True
# Show debugging output in logs (sets DEBUG log level output)
debug = False
# Top-level directory for maintaining moniker's state
#state_path = /var/lib/moniker
# Log directory
#logdir=/var/log/moniker
# Driver used for backend communication (e.g. bind9, powerdns)
#backend_driver=bind9
# There has to be a better way to set these defaults
allowed_rpc_exception_modules = moniker.exceptions, moniker.openstack.common.exception
logging_context_format_string = %(asctime)s %(levelname)s %(name)s [%(request_id)s %(user)s %(tenant)s] %(instance)s %(message)s
default_log_levels = amqplib=WARN, sqlalchemy=WARN, boto=WARN, suds=INFO, keystone=INFO, eventlet.wsgi.server=WARN, stevedore=WARN
# Ability to configure each backend individually
#[backend:bind9]
#rndc_path = /usr/sbin/rndc
#rndc_host = 127.0.0.1
#rndc_port = 953
#rndc_config_file = /etc/rndc.conf
#rndc_key_file = /etc/rndc.key
# MySQLBind agent options
#[backend:mysqlbind9]
#database_connection = mysql://user:password@host/schema
#rndc_path = /usr/sbin/rndc
#rndc_host = 127.0.0.1
#rndc_port = 953
#rndc_config_file = /etc/rndc.conf
#rndc_key_file = /etc/rndc.key
#write_database = True
#dns_server_type = master

View File

@ -1,26 +0,0 @@
[DEFAULT]
# Show more verbose log output (sets INFO log level output)
verbose = True
# Show debugging output in logs (sets DEBUG log level output)
debug = False
# Top-level directory for maintaining moniker's state
#state_path = /var/lib/moniker
# Log directory
#logdir=/var/log/moniker
# Address to bind the API server
api_host = 0.0.0.0
# Port the bind the API server to
api_port = 9001
# Authentication strategy to use - can be either "noauth" or "keystone"
# auth_strategy = noauth
# There has to be a better way to set these defaults
allowed_rpc_exception_modules = moniker.exceptions, moniker.openstack.common.exception
logging_context_format_string = %(asctime)s %(levelname)s %(name)s [%(request_id)s %(user)s %(tenant)s] %(instance)s %(message)s
default_log_levels = amqplib=WARN, sqlalchemy=WARN, boto=WARN, suds=INFO, keystone=INFO, eventlet.wsgi.server=WARN, stevedore=WARN

View File

@ -1,4 +1,5 @@
[DEFAULT] [DEFAULT]
## General Configuration
# Show more verbose log output (sets INFO log level output) # Show more verbose log output (sets INFO log level output)
verbose = True verbose = True
@ -11,9 +12,6 @@ debug = False
# Log directory # Log directory
#logdir=/var/log/moniker #logdir=/var/log/moniker
# Driver used for backend communication (e.g. rpc, bind9, powerdns)
#backend_driver=rpc
# There has to be a better way to set these defaults # There has to be a better way to set these defaults
allowed_rpc_exception_modules = moniker.exceptions, moniker.openstack.common.exception allowed_rpc_exception_modules = moniker.exceptions, moniker.openstack.common.exception
logging_context_format_string = %(asctime)s %(levelname)s %(name)s [%(request_id)s %(user)s %(tenant)s] %(instance)s %(message)s logging_context_format_string = %(asctime)s %(levelname)s %(name)s [%(request_id)s %(user)s %(tenant)s] %(instance)s %(message)s
@ -22,11 +20,30 @@ default_log_levels = amqplib=WARN, sqlalchemy=WARN, boto=WARN, suds=INFO, keysto
# Driver used for issuing notifications # Driver used for issuing notifications
#notification_driver=moniker.openstack.common.notifier.rabbit_notifier #notification_driver=moniker.openstack.common.notifier.rabbit_notifier
## Service Configuration
[service:central]
# Driver used for backend communication (e.g. rpc, bind9, powerdns)
#backend_driver=rpc
# List of notification handlers to enable, configuration of these needs to # List of notification handlers to enable, configuration of these needs to
# correspond to a [handler:my_driver] section below or else in the config # correspond to a [handler:my_driver] section below or else in the config
#enabled_notification_handlers = nova_fixed #enabled_notification_handlers = nova_fixed
# Sections for *SQL storages [service:api]
# Address to bind the API server
api_host = 0.0.0.0
# Port the bind the API server to
api_port = 9001
# Authentication strategy to use - can be either "noauth" or "keystone"
# auth_strategy = noauth
[service:agent]
# Driver used for backend communication (e.g. bind9, powerdns)
#backend_driver=bind9
## Storage Configuration
#[storage:sqlalchemy] #[storage:sqlalchemy]
# Database connection string - to configure options for a given implementation # Database connection string - to configure options for a given implementation
# like sqlalchemy or other see below # like sqlalchemy or other see below
@ -38,7 +55,26 @@ default_log_levels = amqplib=WARN, sqlalchemy=WARN, boto=WARN, suds=INFO, keysto
#max_retries = 10 #max_retries = 10
#retry_interval = 10 #retry_interval = 10
## Notification Handler Configuration
#[handler:nova_fixed] #[handler:nova_fixed]
#domain_id = <random uuid> #domain_id = <random uuid>
#notification_topics = monitor #notification_topics = monitor
#control_exchange = 'nova' #control_exchange = 'nova'
## Backend Configuration
#[backend:bind9]
#rndc_path = /usr/sbin/rndc
#rndc_host = 127.0.0.1
#rndc_port = 953
#rndc_config_file = /etc/rndc.conf
#rndc_key_file = /etc/rndc.key
#[backend:mysqlbind9]
#database_connection = mysql://user:password@host/schema
#rndc_path = /usr/sbin/rndc
#rndc_host = 127.0.0.1
#rndc_port = 953
#rndc_config_file = /etc/rndc.conf
#rndc_key_file = /etc/rndc.key
#write_database = True
#dns_server_type = master

View File

@ -0,0 +1,25 @@
# Copyright 2012 Hewlett-Packard Development Company, L.P. All Rights Reserved.
#
# Author: Kiall Mac Innes <kiall@hp.com>
#
# 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 moniker.openstack.common import cfg
cfg.CONF.register_group(cfg.OptGroup(
name='service:agent', title="Configuration for Agent Service"
))
cfg.CONF.register_opts([
cfg.StrOpt('backend-driver', default='bind9',
help='The backend driver to use'),
], group='service:agent')

View File

@ -20,15 +20,10 @@ from moniker import backend
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
cfg.CONF.register_opts([
cfg.StrOpt('backend-driver', default='bind9',
help='The backend driver to use'),
])
class Service(rpc_service.Service): class Service(rpc_service.Service):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
manager = backend.get_backend(cfg.CONF.backend_driver) manager = backend.get_backend(cfg.CONF['service:agent'].backend_driver)
kwargs.update( kwargs.update(
host=cfg.CONF.host, host=cfg.CONF.host,

View File

@ -17,6 +17,9 @@ import flask
from moniker.openstack.common import cfg from moniker.openstack.common import cfg
from moniker.openstack.common import jsonutils as json from moniker.openstack.common import jsonutils as json
cfg.CONF.register_group(cfg.OptGroup(
name='service:api', title="Configuration for API Service"
))
cfg.CONF.register_opts([ cfg.CONF.register_opts([
cfg.StrOpt('api_host', default='0.0.0.0', cfg.StrOpt('api_host', default='0.0.0.0',
@ -28,7 +31,7 @@ cfg.CONF.register_opts([
cfg.StrOpt('auth_strategy', default='noauth', cfg.StrOpt('auth_strategy', default='noauth',
help='The strategy to use for auth. Supports noauth or ' help='The strategy to use for auth. Supports noauth or '
'keystone'), 'keystone'),
]) ], group='service:api')
# Allows us to serialize datetime's etc # Allows us to serialize datetime's etc

View File

@ -27,7 +27,7 @@ def pipeline_factory(loader, global_conf, **local_conf):
Code nabbed from cinder. Code nabbed from cinder.
""" """
pipeline = local_conf[cfg.CONF.auth_strategy] pipeline = local_conf[cfg.CONF['service:api'].auth_strategy]
pipeline = pipeline.split() pipeline = pipeline.split()
filters = [loader.get_filter(n) for n in pipeline[:-1]] filters = [loader.get_filter(n) for n in pipeline[:-1]]
app = loader.get_app(pipeline[-1]) app = loader.get_app(pipeline[-1])

View File

@ -27,7 +27,8 @@ LOG = logging.getLogger(__name__)
class Service(wsgi.Service): class Service(wsgi.Service):
def __init__(self, backlog=128, threads=1000): def __init__(self, backlog=128, threads=1000):
config_paths = utils.find_config(cfg.CONF.api_paste_config) api_paste_config = cfg.CONF['service:api'].api_paste_config
config_paths = utils.find_config(api_paste_config)
if len(config_paths) == 0: if len(config_paths) == 0:
msg = 'Unable to determine appropriate api-paste-config file' msg = 'Unable to determine appropriate api-paste-config file'
@ -39,7 +40,7 @@ class Service(wsgi.Service):
name='osapi_dns') name='osapi_dns')
super(Service, self).__init__(application=application, super(Service, self).__init__(application=application,
host=cfg.CONF.api_host, host=cfg.CONF['service:api'].api_host,
port=cfg.CONF.api_port, port=cfg.CONF['service:api'].api_port,
backlog=backlog, backlog=backlog,
threads=threads) threads=threads)

View File

@ -0,0 +1,29 @@
# Copyright 2012 Hewlett-Packard Development Company, L.P. All Rights Reserved.
#
# Author: Kiall Mac Innes <kiall@hp.com>
#
# 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 moniker.openstack.common import cfg
cfg.CONF.register_group(cfg.OptGroup(
name='service:central', title="Configuration for Central Service"
))
cfg.CONF.register_opts([
cfg.StrOpt('backend-driver', default='rpc',
help='The backend driver to use'),
cfg.StrOpt('storage-driver', default='sqlalchemy',
help='The storage driver to use'),
cfg.ListOpt('enabled-notification-handlers', default=[],
help='Enabled Notification Handlers'),
], group='service:central')

View File

@ -27,20 +27,12 @@ LOG = logging.getLogger(__name__)
HANDLER_NAMESPACE = 'moniker.notification.handler' HANDLER_NAMESPACE = 'moniker.notification.handler'
cfg.CONF.register_opts([
cfg.StrOpt('backend-driver', default='rpc',
help='The backend driver to use'),
cfg.StrOpt('storage-driver', default='sqlalchemy',
help='The storage driver to use'),
cfg.ListOpt('enabled-notification-handlers', default=[],
help='Enabled Notification Handlers'),
])
class Service(rpc_service.Service): class Service(rpc_service.Service):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.backend = backend.get_backend(cfg.CONF.backend_driver) backend_driver = cfg.CONF['service:central'].backend_driver
self.backend = backend.get_backend(backend_driver)
kwargs.update( kwargs.update(
host=cfg.CONF.host, host=cfg.CONF.host,
@ -63,12 +55,14 @@ class Service(rpc_service.Service):
def _init_extensions(self): def _init_extensions(self):
""" Loads and prepares all enabled extensions """ """ Loads and prepares all enabled extensions """
enabled_notification_handlers = \
cfg.CONF['service:central'].enabled_notification_handlers
self.extensions_manager = NamedExtensionManager( self.extensions_manager = NamedExtensionManager(
HANDLER_NAMESPACE, names=cfg.CONF.enabled_notification_handlers) HANDLER_NAMESPACE, names=enabled_notification_handlers)
def _load_extension(ext): def _load_extension(ext):
handler_cls = ext.plugin handler_cls = ext.plugin
handler_cls.register_opts(cfg.CONF)
return handler_cls(central_service=self) return handler_cls(central_service=self)
try: try:

View File

@ -19,7 +19,6 @@ from migrate.versioning import api as versioning_api
from cliff.command import Command from cliff.command import Command
from moniker.openstack.common import log as logging from moniker.openstack.common import log as logging
from moniker.openstack.common import cfg from moniker.openstack.common import cfg
from moniker import utils
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
REPOSITORY = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', REPOSITORY = os.path.abspath(os.path.join(os.path.dirname(__file__), '..',
@ -33,8 +32,6 @@ class InitCommand(Command):
"Init database" "Init database"
def take_action(self, parsed_args): def take_action(self, parsed_args):
utils.read_config('moniker-central', [])
url = cfg.CONF['storage:sqlalchemy'].database_connection url = cfg.CONF['storage:sqlalchemy'].database_connection
if not os.path.exists(REPOSITORY): if not os.path.exists(REPOSITORY):
@ -53,8 +50,6 @@ class SyncCommand(Command):
def take_action(self, parsed_args): def take_action(self, parsed_args):
# TODO: Support specifying version # TODO: Support specifying version
utils.read_config('moniker-central', [])
url = cfg.CONF['storage:sqlalchemy'].database_connection url = cfg.CONF['storage:sqlalchemy'].database_connection
if not os.path.exists(REPOSITORY): if not os.path.exists(REPOSITORY):

View File

@ -28,7 +28,7 @@ def get_engine(engine_name):
def get_connection(): def get_connection():
engine = get_engine(cfg.CONF.storage_driver) engine = get_engine(cfg.CONF['service:central'].storage_driver)
return engine.get_connection() return engine.get_connection()

View File

@ -20,11 +20,18 @@ from moniker.openstack.common import cfg
from moniker.openstack.common import log as logging from moniker.openstack.common import log as logging
from moniker.context import MonikerContext from moniker.context import MonikerContext
from moniker import storage from moniker import storage
from moniker.agent import service as agent_service
from moniker.api import service as api_service from moniker.api import service as api_service
from moniker.central import service as central_service from moniker.central import service as central_service
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
cfg.CONF.import_opt('storage_driver', 'moniker.central',
group='service:central')
cfg.CONF.import_opt('backend_driver', 'moniker.agent',
group='service:agent')
cfg.CONF.import_opt('auth_strategy', 'moniker.api',
group='service:api')
cfg.CONF.import_opt('database_connection', 'moniker.storage.impl_sqlalchemy', cfg.CONF.import_opt('database_connection', 'moniker.storage.impl_sqlalchemy',
group='storage:sqlalchemy') group='storage:sqlalchemy')
@ -98,18 +105,33 @@ class TestCase(unittest2.TestCase, AssertMixin):
super(TestCase, self).setUp() super(TestCase, self).setUp()
self.mox = mox.Mox() self.mox = mox.Mox()
self.config(
notification_driver=[],
rpc_backend='moniker.openstack.common.rpc.impl_fake',
)
self.config( self.config(
storage_driver='sqlalchemy', storage_driver='sqlalchemy',
backend_driver='fake', backend_driver='fake',
notification_driver=[], group='service:central'
rpc_backend='moniker.openstack.common.rpc.impl_fake', )
auth_strategy='noauth'
self.config(
backend_driver='fake',
group='service:agent'
)
self.config(
auth_strategy='noauth',
group='service:api'
) )
self.config( self.config(
database_connection='sqlite://', database_connection='sqlite://',
group='storage:sqlalchemy' group='storage:sqlalchemy'
) )
storage.setup_schema() storage.setup_schema()
self.admin_context = self.get_admin_context() self.admin_context = self.get_admin_context()
@ -126,6 +148,9 @@ class TestCase(unittest2.TestCase, AssertMixin):
for k, v in kwargs.iteritems(): for k, v in kwargs.iteritems():
cfg.CONF.set_override(k, v, group) cfg.CONF.set_override(k, v, group)
def get_agent_service(self):
return agent_service.Service()
def get_api_service(self): def get_api_service(self):
return api_service.Service() return api_service.Service()

View File

@ -0,0 +1,20 @@
# Copyright 2012 Hewlett-Packard Development Company, L.P. All Rights Reserved.
#
# Author: Kiall Mac Innes <kiall@hp.com>
#
# 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 moniker.tests import TestCase
class AgentTestCase(TestCase):
__test__ = False

View File

@ -0,0 +1,29 @@
# Copyright 2012 Hewlett-Packard Development Company, L.P. All Rights Reserved.
#
# Author: Kiall Mac Innes <kiall@hp.com>
#
# 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 moniker.tests.test_agent import AgentTestCase
class AgentServiceTest(AgentTestCase):
__test__ = True
def setUp(self):
super(AgentServiceTest, self).setUp()
self.service = self.get_agent_service()
def test_start_and_stop(self):
# Ensures the start/stop actions don't raise
self.service.start()
self.service.stop()

View File

@ -25,7 +25,7 @@ class BackendTestCase(TestCase):
__test__ = False __test__ = False
def get_backend_driver(self): def get_backend_driver(self):
return backend.get_backend(cfg.CONF.backend_driver) return backend.get_backend(cfg.CONF['service:agent'].backend_driver)
def test_constructor(self): def test_constructor(self):
self.get_backend_driver() self.get_backend_driver()

View File

@ -25,4 +25,4 @@ class Bind9BackendDriverTestCase(BackendTestCase):
def setUp(self): def setUp(self):
super(Bind9BackendDriverTestCase, self).setUp() super(Bind9BackendDriverTestCase, self).setUp()
self.config(backend_driver='bind9') self.config(backend_driver='bind9', group='service:agent')

View File

@ -25,4 +25,4 @@ class FakeBackendDriverTestCase(BackendTestCase):
def setUp(self): def setUp(self):
super(FakeBackendDriverTestCase, self).setUp() super(FakeBackendDriverTestCase, self).setUp()
self.config(backend_driver='fake') self.config(backend_driver='fake', group='service:agent')

View File

@ -25,4 +25,4 @@ class MySQLBind9BackendDriverTestCase(BackendTestCase):
def setUp(self): def setUp(self):
super(MySQLBind9BackendDriverTestCase, self).setUp() super(MySQLBind9BackendDriverTestCase, self).setUp()
self.config(backend_driver='mysqlbind9') self.config(backend_driver='mysqlbind9', group='service:agent')

View File

@ -28,6 +28,11 @@ class CentralServiceTest(CentralTestCase):
super(CentralServiceTest, self).setUp() super(CentralServiceTest, self).setUp()
self.central_service = self.get_central_service() self.central_service = self.get_central_service()
def test_start_and_stop(self):
# Ensures the start/stop actions don't raise
self.central_service.start()
self.central_service.stop()
# Server Tests # Server Tests
def test_create_server(self): def test_create_server(self):
context = self.get_admin_context() context = self.get_admin_context()