[API] Migrate to oslo.config

Major configuration change. See examples in etc/ directory.

Change-Id: I8090e365f7c1d48ffeede55651ee54801f9d3b90
This commit is contained in:
David Shrewsbury
2013-10-16 11:11:28 -04:00
parent 3d36a4248e
commit cb3fe316b5
6 changed files with 176 additions and 154 deletions

72
etc/api.cfg Normal file
View File

@@ -0,0 +1,72 @@
########################################################################
# A sample configuration file read by the Libra pool manager utility.
########################################################################
#-----------------------------------------------------------------------
# The [DEFAULT] section contains options common to the various Libra
# utilities (worker, mgm, etc).
#-----------------------------------------------------------------------
[DEFAULT]
# Options to enable more verbose output
#verbose = false
#debug = false
# Daemon process options
#daemon = true
#user = libra
#group = libra
# Other logging options
#syslog = false
#syslog_socket = /dev/log
#syslog_faciltiy = local7
#logstash = HOST:PORT
#-----------------------------------------------------------------------
# Options for utilities that are Gearman workers or clients.
#-----------------------------------------------------------------------
[gearman]
#servers = localhost:4730, HOST:PORT
#keepalive = false
#keepcnt = COUNT
#keepidle = SECONDS
#keepintvl = SECONDS
#poll = 1
#reconnect_sleep = 60
#ssl_ca = /path/to/ssl_ca
#ssl_cert = /path/to/ssl_cert
#ssl_key = /path/to/ssl_key
#-----------------------------------------------------------------------
# The [api] section is specific to the libra_api utility.
#-----------------------------------------------------------------------
[api]
# Options with defaults
#disable_keystone=False
#host=0.0.0.0
#port=443
#keystone_module=keystoneclient.middleware.auth_token:AuthProtocol
#logfile=/var/log/libra/libra_api.log
#pid=/var/run/libra/libra_api.pid
# Required options
db_sections=mysql1
swift_basepath=lbaaslogs
swift_endpoint=https://host.com:443/v1/
# Others
ssl_certfile=certfile.crt
ssl_keyfile=keyfile.key
ip_filters=192.168.0.0/24
[mysql1]
username=root
password=
schema=lbaas
host=localhost
# Keystone options go here
[keystone]

View File

@@ -292,7 +292,8 @@ def main():
MaintThreads(logger, args, drivers)
sys.stderr = LogStdout(logger)
sock = server.make_socket(args)
sock = server.make_socket(args.host, args.port,
args.ssl_keyfile, args.ssl_certfile)
wsgi.server(sock, api, keepalive=False)
return 0

View File

@@ -11,3 +11,52 @@
# 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
api_group = cfg.OptGroup('api', 'Libra API options')
cfg.CONF.register_group(api_group)
cfg.CONF.register_opts(
[
cfg.ListOpt('db_sections',
required=True,
help='MySQL config sections in the config file'),
cfg.BoolOpt('disable_keystone',
default=False,
help='Unauthenticated server, for testing only'),
cfg.StrOpt('host',
default='0.0.0.0',
help='IP address to bind to, 0.0.0.0 for all IPs'),
cfg.ListOpt('ip_filters',
help='IP filters for backend nodes in the form '
'xxx.xxx.xxx.xxx/yy'),
cfg.StrOpt('keystone_module',
default='keystoneclient.middleware.auth_token:AuthProtocol',
help='A colon separated module and class for keystone '
' middleware'),
cfg.StrOpt('logfile',
default='/var/log/libra/libra_api.log',
help='Log file'),
cfg.StrOpt('pid',
default='/var/run/libra/libra_api.pid',
help='PID file'),
cfg.IntOpt('port',
default=443,
help='Port number for API server'),
cfg.StrOpt('ssl_certfile',
help='Path to an SSL certificate file'),
cfg.StrOpt('ssl_keyfile',
help='Path to an SSL key file'),
cfg.StrOpt('swift_basepath',
required=True,
help='Default Swift container to place log files'),
cfg.StrOpt('swift_endpoint',
required=True,
help='Default endpoint URL (tenant ID will be appended'
' to this)'),
],
group=api_group
)

View File

@@ -12,10 +12,12 @@
# License for the specific language governing permissions and limitations
# under the License.
import ConfigParser
import importlib
import logging
from oslo.config import cfg
from pecan import request
from libra.api.library.exp import NotAuthorized
@@ -43,10 +45,9 @@ class AuthDirector(object):
will direct intentionally unauthenticated requests to the relevant
controllers. """
def __init__(self, app, args):
self.args = args
def __init__(self, app):
self.unauthed_app = app
if not args.disable_keystone:
if not cfg.CONF['api']['disable_keystone']:
self.app = self._install()
else:
self.app = app
@@ -60,9 +61,7 @@ class AuthDirector(object):
def _install(self):
"""Install ACL check on application."""
config = ConfigParser.SafeConfigParser()
config.read([self.args.config])
module_details = self.args.keystone_module.split(':')
module_details = cfg.CONF['api']['keystone_module'].split(':')
keystone = importlib.import_module(module_details[0])
auth_class = getattr(keystone, module_details[1])
return auth_class(self.unauthed_app, config._sections['keystone'])
return auth_class(self.unauthed_app, cfg.CONF['keystone'])

View File

@@ -13,6 +13,7 @@
# under the License.
import eventlet
eventlet.monkey_patch()
import daemon
import daemon.pidfile
import daemon.runner
@@ -20,14 +21,16 @@ import grp
import pwd
import pecan
import sys
import os
import wsme_overrides
from eventlet import wsgi
from libra import __version__
from libra.api import config as api_config
from libra.api import model
from libra.api import acl
from libra.common.api import server
from libra.common.options import Options, setup_logging
from eventlet import wsgi
from libra.common.options import add_common_opts, libra_logging, CONF
# Gets rid of pep8 error
@@ -40,31 +43,32 @@ def get_pecan_config():
return pecan.configuration.conf_from_file(filename)
def setup_app(pecan_config, args):
def setup_app(pecan_config):
model.init_model()
if not pecan_config:
pecan_config = get_pecan_config()
config = dict(pecan_config)
config['database'] = args.db_sections
config['conffile'] = args.config
config['database'] = CONF['api']['db_sections']
# NOTE: We support only 1 config file
config['conffile'] = CONF['config-file'][0]
config['swift'] = {
'swift_basepath': args.swift_basepath,
'swift_endpoint': args.swift_endpoint
'swift_basepath': CONF['api']['swift_basepath'],
'swift_endpoint': CONF['api']['swift_endpoint']
}
config['gearman'] = {
'server': args.gearman,
'ssl_key': args.gearman_ssl_key,
'ssl_cert': args.gearman_ssl_cert,
'ssl_ca': args.gearman_ssl_ca,
'keepalive': args.gearman_keepalive,
'keepcnt': args.gearman_keepcnt,
'keepidle': args.gearman_keepidle,
'keepintvl': args.gearman_keepintvl
'server': CONF['gearman']['servers'],
'ssl_key': CONF['gearman']['ssl_key'],
'ssl_cert': CONF['gearman']['ssl_cert'],
'ssl_ca': CONF['gearman']['ssl_ca'],
'keepalive': CONF['gearman']['keepalive'],
'keepcnt': CONF['gearman']['keepcnt'],
'keepidle': CONF['gearman']['keepidle'],
'keepintvl': CONF['gearman']['keepintvl']
}
config['ip_filters'] = args.ip_filters
if args.debug:
config['ip_filters'] = CONF['api']['ip_filters']
if CONF['debug']:
config['wsme'] = {'debug': True}
config['app']['debug'] = True
@@ -82,7 +86,7 @@ def setup_app(pecan_config, args):
True)
)
final_app = acl.AuthDirector(app, args)
final_app = acl.AuthDirector(app)
return final_app
@@ -100,125 +104,20 @@ class LogStdout(object):
def main():
options = Options('api', 'API Server')
options.parser.add_argument(
'--host', help='IP address to bind to, 0.0.0.0 for all IPs',
default='0.0.0.0'
)
options.parser.add_argument(
'--port', help='Port number for API server', type=int, default=443
)
options.parser.add_argument(
'--disable_keystone', help='Unauthenticated server, for testing only',
action='store_true'
)
options.parser.add_argument(
'--db_sections', action='append', default=[],
help='MySQL config sections in the config file'
)
options.parser.add_argument(
'--gearman', action='append', metavar='HOST:PORT', default=[],
help='Gearman job servers'
)
options.parser.add_argument(
'--gearman_keepalive', action="store_true",
help='use KEEPALIVE to Gearman server'
)
options.parser.add_argument(
'--gearman_keepcnt', type=int, metavar='COUNT',
help='max keepalive probes to send before killing connection'
)
options.parser.add_argument(
'--gearman_keepidle', type=int, metavar='SECONDS',
help='seconds of idle time before sending keepalive probes'
)
options.parser.add_argument(
'--gearman_keepintvl', type=int, metavar='SECONDS',
help='seconds between TCP keepalive probes'
)
options.parser.add_argument(
'--gearman_ssl_ca', metavar='FILE',
help='Gearman SSL certificate authority'
)
options.parser.add_argument(
'--gearman_ssl_cert', metavar='FILE',
help='Gearman SSL certificate'
)
options.parser.add_argument(
'--gearman_ssl_key', metavar='FILE',
help='Gearman SSL key'
)
options.parser.add_argument(
'--keystone_module',
default='keystoneclient.middleware.auth_token:AuthProtocol',
help='A colon separated module and class for keystone middleware'
)
options.parser.add_argument(
'--swift_basepath',
help='Default swift container to use for pushing log files to'
)
options.parser.add_argument(
'--swift_endpoint',
help='Default endpoint URL (tenant ID will be appended to this)'
)
options.parser.add_argument(
'--ssl_certfile',
help='Path to an SSL certificate file'
)
options.parser.add_argument(
'--ssl_keyfile',
help='Path to an SSL key file'
)
options.parser.add_argument(
'--ip_filters', action='append', default=[],
help='IP filters for backend nodes in the form xxx.xxx.xxx.xxx/yy'
)
args = options.run()
required_args = [
'db_sections', 'swift_basepath',
'swift_endpoint'
]
missing_args = 0
for req in required_args:
test_var = getattr(args, req)
if test_var is None:
missing_args += 1
sys.stderr.write(
'{app}: error: argument --{test_var} is required\n'
.format(app=os.path.basename(sys.argv[0]), test_var=req))
if missing_args:
return 2
if not args.gearman:
# NOTE(shrews): Can't set a default in argparse method because the
# value is appended to the specified default.
args.gearman.append('localhost:4730')
elif not isinstance(args.gearman, list):
# NOTE(shrews): The Options object cannot intelligently handle
# creating a list from an option that may have multiple values.
# We convert it to the expected type here.
svr_list = args.gearman.split()
args.gearman = svr_list
if not isinstance(args.db_sections, list):
db_list = args.db_sections.split()
args.db_sections = db_list
if not isinstance(args.ip_filters, list):
ip_list = args.ip_filters.split()
args.ip_filters = ip_list
add_common_opts()
CONF(project='libra', version=__version__)
pc = get_pecan_config()
# NOTE: Let's not force anyone to actually have to use SSL, it shouldn't be
# up to us to decide.
sock = server.make_socket(args)
sock = server.make_socket(CONF['api']['host'],
CONF['api']['port'],
CONF['api']['ssl_keyfile'],
CONF['api']['ssl_certfile'])
if not args.nodaemon:
pidfile = daemon.pidfile.TimeoutPIDLockFile(args.pid, 10)
if CONF['api']['daemon']:
pidfile = daemon.pidfile.TimeoutPIDLockFile(CONF['api']['pid'], 10)
if daemon.runner.is_pidfile_stale(pidfile):
pidfile.break_lock()
context = daemon.DaemonContext(
@@ -227,17 +126,19 @@ def main():
pidfile=pidfile,
files_preserve=[sock.fileno()]
)
if args.user:
context.uid = pwd.getpwnam(args.user).pw_uid
if args.group:
context.gid = grp.getgrnam(args.group).gr_gid
if CONF['user']:
context.uid = pwd.getpwnam(CONF['user']).pw_uid
if CONF['group']:
context.gid = grp.getgrnam(CONF['group']).gr_gid
context.open()
# Use the root logger due to lots of services using logger
logger = setup_logging('', args)
logger.info('Starting on {0}:{1}'.format(args.host, args.port))
api = setup_app(pc, args)
logger = libra_logging('', 'api')
logger.info('Starting on {0}:{1}'.format(CONF['api']['host'],
CONF['api']['port']))
api = setup_app(pc)
sys.stderr = LogStdout(logger)
wsgi.server(sock, api, keepalive=False, debug=args.debug)
wsgi.server(sock, api, keepalive=False, debug=CONF['debug'])
return 0

View File

@@ -14,11 +14,11 @@
import eventlet
def make_socket(args):
sock = eventlet.listen((args.host, args.port))
def make_socket(host, port, ssl_keyfile=None, ssl_certfile=None):
sock = eventlet.listen((host, port))
# TODO: set ca_certs and cert_reqs=CERT_REQUIRED
if args.ssl_keyfile and args.ssl_certfile:
sock = eventlet.wrap_ssl(sock, certfile=args.ssl_certfile,
keyfile=args.ssl_keyfile,
if ssl_keyfile and ssl_certfile:
sock = eventlet.wrap_ssl(sock, certfile=ssl_certfile,
keyfile=ssl_keyfile,
server_side=True)
return sock