Add cfg's new global CONF object

Implements blueprint cfg-global-object

Begin adopting cfg's global CONF object pattern rather than passing
a conf object around everywhere.

This iterations does just enough to have each of the glance programs
initialize CONF and get the unit tests working.

Change-Id: Ia34959b3ba52cbe933d5d347f31319271b2e14f9
This commit is contained in:
Mark McLoughlin 2012-05-29 08:51:12 +01:00
parent 41d285ab02
commit 1038a19a32
55 changed files with 653 additions and 628 deletions

View File

@ -39,6 +39,9 @@ gettext.install('glance', unicode=1)
from glance.common import config from glance.common import config
from glance.common import wsgi from glance.common import wsgi
from glance.common import exception from glance.common import exception
from glance.openstack.common import cfg
CONF = cfg.CONF
def fail(returncode, e): def fail(returncode, e):
@ -48,13 +51,12 @@ def fail(returncode, e):
if __name__ == '__main__': if __name__ == '__main__':
try: try:
conf = config.GlanceConfigOpts() config.parse_args()
conf()
app = config.load_paste_app(conf) app = config.load_paste_app(CONF)
server = wsgi.Server() server = wsgi.Server()
server.start(app, conf, default_port=9292) server.start(app, CONF, default_port=9292)
server.wait() server.wait()
except exception.WorkerCreationFailure, e: except exception.WorkerCreationFailure, e:
fail(2, e) fail(2, e)

View File

@ -47,14 +47,17 @@ if os.path.exists(os.path.join(possible_topdir, 'glance', '__init__.py')):
gettext.install('glance', unicode=1) gettext.install('glance', unicode=1)
from glance.common import config from glance.common import config
from glance.openstack.common import cfg
CONF = cfg.CONF
if __name__ == '__main__': if __name__ == '__main__':
try: try:
conf = config.GlanceCacheConfigOpts() config.parse_cache_args()
conf()
app = config.load_paste_app(conf, 'glance-cleaner') app = config.load_paste_app(CONF,
'glance-cleaner', 'glance-cache-paste.ini')
app.run() app.run()
except RuntimeError, e: except RuntimeError, e:
sys.exit("ERROR: %s" % e) sys.exit("ERROR: %s" % e)

View File

@ -38,14 +38,17 @@ if os.path.exists(os.path.join(possible_topdir, 'glance', '__init__.py')):
gettext.install('glance', unicode=1) gettext.install('glance', unicode=1)
from glance.common import config from glance.common import config
from glance.openstack.common import cfg
CONF = cfg.CONF
if __name__ == '__main__': if __name__ == '__main__':
try: try:
conf = config.GlanceCacheConfigOpts() config.parse_cache_args()
conf()
app = config.load_paste_app(conf, 'glance-prefetcher') app = config.load_paste_app(CONF, 'glance-prefetcher',
'glance-cache-paste.ini')
app.run() app.run()
except RuntimeError, e: except RuntimeError, e:
sys.exit("ERROR: %s" % e) sys.exit("ERROR: %s" % e)

View File

@ -39,14 +39,17 @@ if os.path.exists(os.path.join(possible_topdir, 'glance', '__init__.py')):
gettext.install('glance', unicode=1) gettext.install('glance', unicode=1)
from glance.common import config from glance.common import config
from glance.openstack.common import cfg
CONF = cfg.CONF
if __name__ == '__main__': if __name__ == '__main__':
try: try:
conf = config.GlanceCacheConfigOpts() config.parse_cache_args()
conf()
app = config.load_paste_app(conf, 'glance-pruner') app = config.load_paste_app(CONF,
'glance-pruner', 'glance-cache-paste.ini')
app.run() app.run()
except RuntimeError, e: except RuntimeError, e:
sys.exit("ERROR: %s" % e) sys.exit("ERROR: %s" % e)

View File

@ -46,6 +46,8 @@ gettext.install('glance', unicode=1)
from glance.common import config from glance.common import config
from glance.openstack.common import cfg from glance.openstack.common import cfg
CONF = cfg.CONF
ALL_COMMANDS = ['start', 'stop', 'shutdown', 'restart', ALL_COMMANDS = ['start', 'stop', 'shutdown', 'restart',
'reload', 'force-reload'] 'reload', 'force-reload']
ALL_SERVERS = ['glance-api', 'glance-registry', 'glance-scrubber'] ALL_SERVERS = ['glance-api', 'glance-registry', 'glance-scrubber']
@ -77,11 +79,11 @@ def gated_by(predicate):
return wrap return wrap
def pid_files(server, conf): def pid_files(server, pid_file):
pid_files = [] pid_files = []
if conf.pid_file: if pid_file:
if os.path.exists(os.path.abspath(conf.pid_file)): if os.path.exists(os.path.abspath(pid_file)):
pid_files = [os.path.abspath(conf.pid_file)] pid_files = [os.path.abspath(pid_file)]
else: else:
if os.path.exists('/var/run/glance/%s.pid' % server): if os.path.exists('/var/run/glance/%s.pid' % server):
pid_files = ['/var/run/glance/%s.pid' % server] pid_files = ['/var/run/glance/%s.pid' % server]
@ -90,9 +92,9 @@ def pid_files(server, conf):
yield pid_file, pid yield pid_file, pid
def do_start(verb, server, conf, args): def do_start(verb, server, args):
if verb != 'Respawn': if verb != 'Respawn':
for pid_file, pid in pid_files(server, conf): for pid_file, pid in pid_files(server, CONF.pid_file):
if os.path.exists('/proc/%s' % pid): if os.path.exists('/proc/%s' % pid):
print ("%s appears to already be running: %s" % print ("%s appears to already be running: %s" %
(server, pid_file)) (server, pid_file))
@ -143,23 +145,23 @@ def do_start(verb, server, conf, args):
except OSError: except OSError:
pass pass
def redirect_stdio(conf, server): def redirect_stdio(server, capture_output):
input = [sys.stdin.fileno()] input = [sys.stdin.fileno()]
output = [sys.stdout.fileno(), sys.stderr.fileno()] output = [sys.stdout.fileno(), sys.stderr.fileno()]
redirect_to_null(input) redirect_to_null(input)
if conf.capture_output: if capture_output:
redirect_to_syslog(output, server) redirect_to_syslog(output, server)
else: else:
redirect_to_null(output) redirect_to_null(output)
@gated_by(conf.capture_output) @gated_by(CONF.capture_output)
def close_stdio_on_exec(): def close_stdio_on_exec():
fds = [sys.stdin.fileno(), sys.stdout.fileno(), sys.stderr.fileno()] fds = [sys.stdin.fileno(), sys.stdout.fileno(), sys.stderr.fileno()]
for desc in fds: # set close on exec flag for desc in fds: # set close on exec flag
fcntl.fcntl(desc, fcntl.F_SETFD, fcntl.FD_CLOEXEC) fcntl.fcntl(desc, fcntl.F_SETFD, fcntl.FD_CLOEXEC)
def launch(pid_file, conf_file=None): def launch(pid_file, conf_file=None, capture_output=False, await_time=0):
args = [server] args = [server]
print '%sing %s' % (verb, server), print '%sing %s' % (verb, server),
if conf_file: if conf_file:
@ -172,7 +174,7 @@ def do_start(verb, server, conf, args):
pid = os.fork() pid = os.fork()
if pid == 0: if pid == 0:
os.setsid() os.setsid()
redirect_stdio(conf, server) redirect_stdio(server, capture_output)
try: try:
os.execlp('%s' % server, *args) os.execlp('%s' % server, *args)
except OSError, e: except OSError, e:
@ -181,12 +183,12 @@ def do_start(verb, server, conf, args):
sys.exit(0) sys.exit(0)
else: else:
write_pid_file(pid_file, pid) write_pid_file(pid_file, pid)
await_child(pid) await_child(pid, await_time)
return pid return pid
@gated_by(conf.await_child) @gated_by(CONF.await_child)
def await_child(pid): def await_child(pid, await_time):
bail_time = time.time() + conf.await_child bail_time = time.time() + await_time
while time.time() < bail_time: while time.time() < bail_time:
reported_pid, status = os.waitpid(pid, os.WNOHANG) reported_pid, status = os.waitpid(pid, os.WNOHANG)
if reported_pid == pid: if reported_pid == pid:
@ -195,28 +197,28 @@ def do_start(verb, server, conf, args):
break break
time.sleep(0.05) time.sleep(0.05)
pid_file = get_pid_file(server, conf) pid_file = get_pid_file(server, CONF.pid_file)
conf_file = None conf_file = None
if args and os.path.exists(args[0]): if args and os.path.exists(args[0]):
conf_file = os.path.abspath(os.path.expanduser(args[0])) conf_file = os.path.abspath(os.path.expanduser(args[0]))
return launch(pid_file, conf_file) return launch(pid_file, conf_file, CONF.capture_output, CONF.await_child)
def get_pid_file(pid, conf): def get_pid_file(pid, pid_file):
return (os.path.abspath(conf.pid_file) if conf.pid_file else return (os.path.abspath(pid_file) if pid_file else
'/var/run/glance/%s.pid' % server) '/var/run/glance/%s.pid' % server)
def do_stop(server, conf, args, graceful=False): def do_stop(server, args, graceful=False):
if graceful and server in GRACEFUL_SHUTDOWN_SERVERS: if graceful and server in GRACEFUL_SHUTDOWN_SERVERS:
sig = signal.SIGHUP sig = signal.SIGHUP
else: else:
sig = signal.SIGTERM sig = signal.SIGTERM
did_anything = False did_anything = False
pfiles = pid_files(server, conf) pfiles = pid_files(server, CONF.pid_file)
for pid_file, pid in pfiles: for pid_file, pid in pfiles:
did_anything = True did_anything = True
try: try:
@ -243,8 +245,6 @@ def do_stop(server, conf, args, graceful=False):
if __name__ == '__main__': if __name__ == '__main__':
exitcode = 0 exitcode = 0
conf = config.GlanceConfigOpts(usage=USAGE)
opts = [ opts = [
cfg.StrOpt('pid-file', cfg.StrOpt('pid-file',
metavar='PATH', metavar='PATH',
@ -264,12 +264,12 @@ if __name__ == '__main__':
default=False, default=False,
help='Restart service on unexpected death'), help='Restart service on unexpected death'),
] ]
conf.register_cli_opts(opts) CONF.register_cli_opts(opts)
args = conf() args = config.parse_args(usage=USAGE)
@gated_by(conf.await_child) @gated_by(CONF.await_child)
@gated_by(conf.respawn) @gated_by(CONF.respawn)
def mutually_exclusive(): def mutually_exclusive():
sys.stderr.write('--await-child and --respawn are mutually exclusive') sys.stderr.write('--await-child and --respawn are mutually exclusive')
sys.exit(1) sys.exit(1)
@ -277,7 +277,7 @@ if __name__ == '__main__':
mutually_exclusive() mutually_exclusive()
if len(args) < 2: if len(args) < 2:
conf.print_usage() CONF.print_usage()
sys.exit(1) sys.exit(1)
server = args.pop(0).lower() server = args.pop(0).lower()
@ -301,19 +301,19 @@ if __name__ == '__main__':
"command in this list: %(command_list)s" % locals()) "command in this list: %(command_list)s" % locals())
sys.exit(msg) sys.exit(msg)
@gated_by(conf.respawn) @gated_by(CONF.respawn)
def anticipate_respawn(children): def anticipate_respawn(children):
while children: while children:
pid, status = os.wait() pid, status = os.wait()
if pid in children: if pid in children:
(server, conf, args) = children.pop(pid) (server, args) = children.pop(pid)
pid_file = get_pid_file(server, conf) pid_file = get_pid_file(server, CONF.pid_file)
running = os.path.exists(pid_file) running = os.path.exists(pid_file)
one_second_ago = time.time() - 1 one_second_ago = time.time() - 1
bouncing = (running and bouncing = (running and
os.path.getmtime(pid_file) >= one_second_ago) os.path.getmtime(pid_file) >= one_second_ago)
if running and not bouncing: if running and not bouncing:
args = (server, conf, args) args = (server, args)
new_pid = do_start('Respawn', *args) new_pid = do_start('Respawn', *args)
children[new_pid] = args children[new_pid] = args
else: else:
@ -323,7 +323,7 @@ if __name__ == '__main__':
if command == 'start': if command == 'start':
children = {} children = {}
for server in servers: for server in servers:
args = (server, conf, args) args = (server, args)
pid = do_start('Start', *args) pid = do_start('Start', *args)
children[pid] = args children[pid] = args
@ -331,21 +331,21 @@ if __name__ == '__main__':
if command == 'stop': if command == 'stop':
for server in servers: for server in servers:
do_stop(server, conf, args) do_stop(server, args)
if command == 'shutdown': if command == 'shutdown':
for server in servers: for server in servers:
do_stop(server, conf, args, graceful=True) do_stop(server, args, graceful=True)
if command == 'restart': if command == 'restart':
for server in servers: for server in servers:
do_stop(server, conf, args) do_stop(server, args)
for server in servers: for server in servers:
do_start('Restart', server, conf, args) do_start('Restart', server, args)
if command == 'reload' or command == 'force-reload': if command == 'reload' or command == 'force-reload':
for server in servers: for server in servers:
do_stop(server, conf, args, graceful=True) do_stop(server, args, graceful=True)
do_start(server, conf, args) do_start(server, args)
sys.exit(exitcode) sys.exit(exitcode)

View File

@ -47,49 +47,51 @@ import glance.db
import glance.db.api import glance.db.api
import glance.db.migration import glance.db.migration
CONF = cfg.CONF
def do_db_version(conf, args):
def do_db_version(args):
"""Print database's current migration level""" """Print database's current migration level"""
print glance.db.migration.db_version(conf) print glance.db.migration.db_version(CONF)
def do_upgrade(conf, args): def do_upgrade(args):
"""Upgrade the database's migration level""" """Upgrade the database's migration level"""
version = args.pop(0) if args else None version = args.pop(0) if args else None
glance.db.migration.upgrade(conf, version) glance.db.migration.upgrade(CONF, version)
def do_downgrade(conf, args): def do_downgrade(args):
"""Downgrade the database's migration level""" """Downgrade the database's migration level"""
if not args: if not args:
raise exception.MissingArgumentError( raise exception.MissingArgumentError(
"downgrade requires a version argument") "downgrade requires a version argument")
version = args.pop(0) version = args.pop(0)
glance.db.migration.downgrade(conf, version) glance.db.migration.downgrade(CONF, version)
def do_version_control(conf, args): def do_version_control(args):
"""Place a database under migration control""" """Place a database under migration control"""
version = args.pop(0) if args else None version = args.pop(0) if args else None
glance.db.migration.version_control(conf, version) glance.db.migration.version_control(CONF, version)
def do_db_sync(conf, args): def do_db_sync(args):
""" """
Place a database under migration control and upgrade, Place a database under migration control and upgrade,
creating first if necessary. creating first if necessary.
""" """
# override auto-create flag, as complete DB should always # override auto-create flag, as complete DB should always
# be created on sync if not already existing # be created on sync if not already existing
conf.db_auto_create = True CONF.db_auto_create = True
glance.db.api.configure_db(conf) glance.db.api.configure_db(CONF)
version = args.pop(0) if args else None version = args.pop(0) if args else None
current_version = args.pop(0) if args else None current_version = args.pop(0) if args else None
glance.db.migration.db_sync(conf, version, current_version) glance.db.migration.db_sync(CONF, version, current_version)
def dispatch_cmd(conf, args): def dispatch_cmd(args):
"""Search for do_* cmd in this module and then run it""" """Search for do_* cmd in this module and then run it"""
cmd = args.pop(0) cmd = args.pop(0)
try: try:
@ -98,7 +100,7 @@ def dispatch_cmd(conf, args):
sys.exit("ERROR: unrecognized command '%s'" % cmd) sys.exit("ERROR: unrecognized command '%s'" % cmd)
try: try:
cmd_func(conf, args) cmd_func(args)
except exception.GlanceException, e: except exception.GlanceException, e:
sys.exit("ERROR: %s" % e) sys.exit("ERROR: %s" % e)
@ -107,22 +109,22 @@ def main():
try: try:
# We load the glance-registry config section because # We load the glance-registry config section because
# sql_connection is only part of the glance registry. # sql_connection is only part of the glance registry.
glance.db.add_cli_options()
default_cfg_files = cfg.find_config_files(project='glance', default_cfg_files = cfg.find_config_files(project='glance',
prog='glance-registry') prog='glance-registry')
conf = config.GlanceConfigOpts(default_config_files=default_cfg_files, args = config.parse_args(default_config_files=default_cfg_files,
usage="%prog [options] <cmd>") usage="%prog [options] <cmd>")
glance.db.add_options(conf) config.setup_logging(CONF)
args = conf()
config.setup_logging(conf)
except RuntimeError, e: except RuntimeError, e:
sys.exit("ERROR: %s" % e) sys.exit("ERROR: %s" % e)
if not args: if not args:
conf.print_usage() CONF.print_usage()
sys.exit(1) sys.exit(1)
dispatch_cmd(conf, args) dispatch_cmd(args)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -38,17 +38,19 @@ gettext.install('glance', unicode=1)
from glance.common import config from glance.common import config
from glance.common import wsgi from glance.common import wsgi
from glance.openstack.common import cfg
CONF = cfg.CONF
if __name__ == '__main__': if __name__ == '__main__':
try: try:
conf = config.GlanceConfigOpts() config.parse_args()
conf()
app = config.load_paste_app(conf) app = config.load_paste_app(CONF)
server = wsgi.Server() server = wsgi.Server()
server.start(app, conf, default_port=9191) server.start(app, CONF, default_port=9191)
server.wait() server.wait()
except RuntimeError, e: except RuntimeError, e:
sys.exit("ERROR: %s" % e) sys.exit("ERROR: %s" % e)

View File

@ -38,11 +38,12 @@ from glance.common import config
from glance.openstack.common import cfg from glance.openstack.common import cfg
from glance.store import scrubber from glance.store import scrubber
CONF = cfg.CONF
if __name__ == '__main__': if __name__ == '__main__':
try: try:
conf = config.GlanceConfigOpts() CONF.register_cli_opt(
conf.register_cli_opt(
cfg.BoolOpt('daemon', cfg.BoolOpt('daemon',
short='D', short='D',
default=False, default=False,
@ -51,13 +52,14 @@ if __name__ == '__main__':
'once and then exits. When specified do not exit ' 'once and then exits. When specified do not exit '
'and run scrub on wakeup_time interval as ' 'and run scrub on wakeup_time interval as '
'specified in the config.')) 'specified in the config.'))
conf.register_opt(cfg.IntOpt('wakeup_time', default=300)) CONF.register_opt(cfg.IntOpt('wakeup_time', default=300))
conf()
app = config.load_paste_app(conf, 'glance-scrubber') config.parse_args()
if conf.daemon: app = config.load_paste_app(CONF, 'glance-scrubber')
server = scrubber.Daemon(conf.wakeup_time)
if CONF.daemon:
server = scrubber.Daemon(CONF.wakeup_time)
server.start(app) server.start(app)
server.wait() server.wait()
else: else:

View File

@ -27,19 +27,19 @@ from glance.openstack.common import cfg
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
policy_opts = (
cfg.StrOpt('policy_file', default=None),
cfg.StrOpt('policy_default_rule', default='default'),
)
CONF = cfg.CONF
CONF.register_opts(policy_opts)
class Enforcer(object): class Enforcer(object):
"""Responsible for loading and enforcing rules""" """Responsible for loading and enforcing rules"""
policy_opts = (
cfg.StrOpt('policy_file', default=None),
cfg.StrOpt('policy_default_rule', default='default'),
)
def __init__(self, conf): def __init__(self, conf):
for opt in self.policy_opts:
conf.register_opt(opt)
self.default_rule = conf.policy_default_rule self.default_rule = conf.policy_default_rule
self.policy_path = self._find_policy_file(conf) self.policy_path = self._find_policy_file(conf)
self.policy_file_mtime = None self.policy_file_mtime = None

View File

@ -66,6 +66,9 @@ IMAGE_SIZE_CAP = 1 << 50
# identity check (not equality). # identity check (not equality).
default_store_opt = cfg.StrOpt('default_store', default='file') default_store_opt = cfg.StrOpt('default_store', default='file')
CONF = cfg.CONF
CONF.register_opt(default_store_opt)
class Controller(controller.BaseController): class Controller(controller.BaseController):
""" """
@ -88,7 +91,6 @@ class Controller(controller.BaseController):
def __init__(self, conf): def __init__(self, conf):
self.conf = conf self.conf = conf
self.conf.register_opt(default_store_opt)
create_stores(self.conf) create_stores(self.conf)
self.verify_scheme_or_exit(self.conf.default_store) self.verify_scheme_or_exit(self.conf.default_store)
self.notifier = notifier.Notifier(conf) self.notifier = notifier.Notifier(conf)

View File

@ -30,8 +30,6 @@ from glance.common import wsgi
from glance.openstack.common import cfg from glance.openstack.common import cfg
from glance import version from glance import version
paste_deploy_group = cfg.OptGroup('paste_deploy')
paste_deploy_opts = [ paste_deploy_opts = [
cfg.StrOpt('flavor'), cfg.StrOpt('flavor'),
cfg.StrOpt('config_file'), cfg.StrOpt('config_file'),
@ -42,26 +40,22 @@ common_opts = [
'beyond what the image schema provides'), 'beyond what the image schema provides'),
] ]
CONF = cfg.CONF
class GlanceConfigOpts(cfg.CommonConfigOpts): CONF.register_opts(paste_deploy_opts, group='paste_deploy')
CONF.register_opts(common_opts)
def __init__(self, default_config_files=None, **kwargs):
super(GlanceConfigOpts, self).__init__(
project='glance',
version='%%prog %s' % version.version_string(),
default_config_files=default_config_files,
**kwargs)
self.register_opts(common_opts)
self.default_paste_file = self.prog + '-paste.ini'
class GlanceCacheConfigOpts(GlanceConfigOpts): def parse_args(args=None, usage=None, default_config_files=None):
return CONF(args=args,
project='glance',
version='%%prog %s' % version.version_string(),
usage=usage,
default_config_files=default_config_files)
def __init__(self, **kwargs):
config_files = cfg.find_config_files(project='glance', def parse_cache_args(args=None):
prog='glance-cache') config_files = cfg.find_config_files(project='glance', prog='glance-cache')
super(GlanceCacheConfigOpts, self).__init__(config_files, **kwargs) return parse_args(args=args, default_config_files=config_files)
self.default_paste_file = 'glance-cache-paste.ini'
def setup_logging(conf): def setup_logging(conf):
@ -111,16 +105,6 @@ def setup_logging(conf):
root_logger.addHandler(handler) root_logger.addHandler(handler)
def _register_paste_deploy_opts(conf):
"""
Idempotent registration of paste_deploy option group
:param conf: a cfg.ConfigOpts object
"""
conf.register_group(paste_deploy_group)
conf.register_opts(paste_deploy_opts, group=paste_deploy_group)
def _get_deployment_flavor(conf): def _get_deployment_flavor(conf):
""" """
Retrieve the paste_deploy.flavor config item, formatted appropriately Retrieve the paste_deploy.flavor config item, formatted appropriately
@ -128,42 +112,41 @@ def _get_deployment_flavor(conf):
:param conf: a cfg.ConfigOpts object :param conf: a cfg.ConfigOpts object
""" """
_register_paste_deploy_opts(conf)
flavor = conf.paste_deploy.flavor flavor = conf.paste_deploy.flavor
return '' if not flavor else ('-' + flavor) return '' if not flavor else ('-' + flavor)
def _get_paste_config_path(conf): def _get_paste_config_path(conf, default_paste_file=None):
paste_suffix = '-paste.ini' paste_suffix = '-paste.ini'
conf_suffix = '.conf' conf_suffix = '.conf'
if conf.config_file: if conf.config_file:
# Assume paste config is in a paste.ini file corresponding # Assume paste config is in a paste.ini file corresponding
# to the last config file # to the last config file
path = conf.config_file[-1].replace(conf_suffix, paste_suffix) path = conf.config_file[-1].replace(conf_suffix, paste_suffix)
elif default_paste_file:
path = default_paste_file
else: else:
path = conf.default_paste_file path = conf.prog + '-paste.ini'
return conf.find_file(os.path.basename(path)) return conf.find_file(os.path.basename(path))
def _get_deployment_config_file(conf): def _get_deployment_config_file(conf, default_paste_file=None):
""" """
Retrieve the deployment_config_file config item, formatted as an Retrieve the deployment_config_file config item, formatted as an
absolute pathname. absolute pathname.
:param conf: a cfg.ConfigOpts object :param conf: a cfg.ConfigOpts object
""" """
_register_paste_deploy_opts(conf) path = conf.paste_deploy.config_file
config_file = conf.paste_deploy.config_file if not path:
path = _get_paste_config_path(conf) if not config_file else config_file path = _get_paste_config_path(conf, default_paste_file)
if not path: if not path:
msg = "Unable to locate paste config file for %s." % conf.prog msg = "Unable to locate paste config file for %s." % conf.prog
raise RuntimeError(msg) raise RuntimeError(msg)
return os.path.abspath(path) return os.path.abspath(path)
def load_paste_app(conf, app_name=None): def load_paste_app(conf, app_name=None, default_paste_file=None):
""" """
Builds and returns a WSGI app from a paste config file. Builds and returns a WSGI app from a paste config file.
@ -183,7 +166,7 @@ def load_paste_app(conf, app_name=None):
# in order to identify the appropriate paste pipeline # in order to identify the appropriate paste pipeline
app_name += _get_deployment_flavor(conf) app_name += _get_deployment_flavor(conf)
conf_file = _get_deployment_config_file(conf) conf_file = _get_deployment_config_file(conf, default_paste_file)
try: try:
# Setup logging early # Setup logging early

View File

@ -22,6 +22,15 @@ from glance.common import wsgi
from glance.openstack.common import cfg from glance.openstack.common import cfg
from glance.db import api as db_api from glance.db import api as db_api
context_opts = [
cfg.BoolOpt('owner_is_tenant', default=True),
cfg.StrOpt('admin_role', default='admin'),
cfg.BoolOpt('allow_anonymous_access', default=False),
]
CONF = cfg.CONF
CONF.register_opts(context_opts)
class RequestContext(object): class RequestContext(object):
""" """
@ -129,15 +138,8 @@ class RequestContext(object):
class ContextMiddleware(wsgi.Middleware): class ContextMiddleware(wsgi.Middleware):
opts = [
cfg.BoolOpt('owner_is_tenant', default=True),
cfg.StrOpt('admin_role', default='admin'),
cfg.BoolOpt('allow_anonymous_access', default=False),
]
def __init__(self, app, conf, **local_conf): def __init__(self, app, conf, **local_conf):
self.conf = conf self.conf = conf
self.conf.register_opts(self.opts)
super(ContextMiddleware, self).__init__(app) super(ContextMiddleware, self).__init__(app)
def process_request(self, req): def process_request(self, req):

View File

@ -59,6 +59,11 @@ socket_opts = [
workers_opt = cfg.IntOpt('workers', default=0) workers_opt = cfg.IntOpt('workers', default=0)
CONF = cfg.CONF
CONF.register_opts(bind_opts)
CONF.register_opts(socket_opts)
CONF.register_opt(workers_opt)
class WritableLogger(object): class WritableLogger(object):
"""A thin wrapper that responds to `write` and logs.""" """A thin wrapper that responds to `write` and logs."""
@ -73,7 +78,6 @@ class WritableLogger(object):
def get_bind_addr(conf, default_port=None): def get_bind_addr(conf, default_port=None):
"""Return the host and port to bind to.""" """Return the host and port to bind to."""
conf.register_opts(bind_opts)
return (conf.bind_host, conf.bind_port or default_port) return (conf.bind_host, conf.bind_port or default_port)
@ -98,8 +102,6 @@ def get_socket(conf, default_port):
bind_addr[1], socket.AF_UNSPEC, socket.SOCK_STREAM) bind_addr[1], socket.AF_UNSPEC, socket.SOCK_STREAM)
if addr[0] in (socket.AF_INET, socket.AF_INET6)][0] if addr[0] in (socket.AF_INET, socket.AF_INET6)][0]
conf.register_opts(socket_opts)
cert_file = conf.cert_file cert_file = conf.cert_file
key_file = conf.key_file key_file = conf.key_file
use_ssl = cert_file or key_file use_ssl = cert_file or key_file
@ -169,7 +171,6 @@ class Server(object):
self.application = application self.application = application
self.sock = get_socket(conf, default_port) self.sock = get_socket(conf, default_port)
conf.register_opt(workers_opt)
self.logger = logging.getLogger('eventlet.wsgi.server') self.logger = logging.getLogger('eventlet.wsgi.server')

View File

@ -19,21 +19,22 @@
from glance.openstack.common import cfg from glance.openstack.common import cfg
sql_connection_opt = cfg.StrOpt('sql_connection',
default='sqlite:///glance.sqlite',
metavar='CONNECTION',
help='A valid SQLAlchemy connection '
'string for the registry database. '
'Default: %default')
def add_options(conf): CONF = cfg.CONF
CONF.register_opt(sql_connection_opt)
def add_cli_options():
""" """
Adds any configuration options that the db layer might have. Adds any configuration options that the db layer might have.
:param conf: A ConfigOpts object
:retval None :retval None
""" """
conf.register_group(cfg.OptGroup('registrydb', CONF.unregister_opt(sql_connection_opt)
title='Registry Database Options', CONF.register_cli_opt(sql_connection_opt)
help='The following configuration options '
'are specific to the Glance image '
'registry database.'))
conf.register_cli_opt(cfg.StrOpt('sql_connection',
metavar='CONNECTION',
help='A valid SQLAlchemy connection '
'string for the registry database. '
'Default: %default'))

View File

@ -37,6 +37,7 @@ from sqlalchemy.sql import or_, and_
from glance.common import exception from glance.common import exception
from glance.common import utils from glance.common import utils
from glance.openstack.common import cfg from glance.openstack.common import cfg
from glance import db
from glance.db import migration from glance.db import migration
from glance.db import models from glance.db import models
@ -66,12 +67,14 @@ STATUSES = ['active', 'saving', 'queued', 'killed', 'pending_delete',
db_opts = [ db_opts = [
cfg.IntOpt('sql_idle_timeout', default=3600), cfg.IntOpt('sql_idle_timeout', default=3600),
cfg.StrOpt('sql_connection', default='sqlite:///glance.sqlite'),
cfg.IntOpt('sql_max_retries', default=10), cfg.IntOpt('sql_max_retries', default=10),
cfg.IntOpt('sql_retry_interval', default=1), cfg.IntOpt('sql_retry_interval', default=1),
cfg.BoolOpt('db_auto_create', default=True), cfg.BoolOpt('db_auto_create', default=True),
] ]
CONF = cfg.CONF
CONF.register_opts(db_opts)
class MySQLPingListener(object): class MySQLPingListener(object):
@ -103,10 +106,6 @@ def configure_db(conf):
""" """
global _ENGINE, sa_logger, logger, _MAX_RETRIES, _RETRY_INTERVAL global _ENGINE, sa_logger, logger, _MAX_RETRIES, _RETRY_INTERVAL
if not _ENGINE: if not _ENGINE:
for opt in db_opts:
# avoid duplicate registration
if not opt.name in conf:
conf.register_opt(opt)
sql_connection = conf.sql_connection sql_connection = conf.sql_connection
_MAX_RETRIES = conf.sql_max_retries _MAX_RETRIES = conf.sql_max_retries
_RETRY_INTERVAL = conf.sql_retry_interval _RETRY_INTERVAL = conf.sql_retry_interval

View File

@ -27,6 +27,17 @@ from glance.openstack.common import cfg
from glance.openstack.common import importutils from glance.openstack.common import importutils
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
image_cache_opts = [
cfg.StrOpt('image_cache_driver', default='sqlite'),
cfg.IntOpt('image_cache_max_size', default=10 * (1024 ** 3)), # 10 GB
cfg.IntOpt('image_cache_stall_time', default=86400), # 24 hours
cfg.StrOpt('image_cache_dir'),
]
CONF = cfg.CONF
CONF.register_opts(image_cache_opts)
DEFAULT_MAX_CACHE_SIZE = 10 * 1024 * 1024 * 1024 # 10 GB DEFAULT_MAX_CACHE_SIZE = 10 * 1024 * 1024 * 1024 # 10 GB
@ -34,16 +45,8 @@ class ImageCache(object):
"""Provides an LRU cache for image data.""" """Provides an LRU cache for image data."""
opts = [
cfg.StrOpt('image_cache_driver', default='sqlite'),
cfg.IntOpt('image_cache_max_size', default=10 * (1024 ** 3)), # 10 GB
cfg.IntOpt('image_cache_stall_time', default=86400), # 24 hours
cfg.StrOpt('image_cache_dir'),
]
def __init__(self, conf): def __init__(self, conf):
self.conf = conf self.conf = conf
self.conf.register_opts(self.opts)
self.init_driver() self.init_driver()
def init_driver(self): def init_driver(self):

View File

@ -34,6 +34,14 @@ from glance.image_cache.drivers import base
from glance.openstack.common import cfg from glance.openstack.common import cfg
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
sqlite_opts = [
cfg.StrOpt('image_cache_sqlite_db', default='cache.db'),
]
CONF = cfg.CONF
CONF.register_opts(sqlite_opts)
DEFAULT_SQL_CALL_TIMEOUT = 2 DEFAULT_SQL_CALL_TIMEOUT = 2
@ -79,10 +87,6 @@ class Driver(base.Driver):
that has atimes set. that has atimes set.
""" """
opts = [
cfg.StrOpt('image_cache_sqlite_db', default='cache.db'),
]
def configure(self): def configure(self):
""" """
Configure the driver to use the stored configuration options Configure the driver to use the stored configuration options
@ -92,8 +96,6 @@ class Driver(base.Driver):
""" """
super(Driver, self).configure() super(Driver, self).configure()
self.conf.register_opts(self.opts)
# Create the SQLite database that will hold our cache attributes # Create the SQLite database that will hold our cache attributes
self.initialize_db() self.initialize_db()

View File

@ -24,6 +24,12 @@ from glance.common import exception
from glance.openstack.common import cfg from glance.openstack.common import cfg
from glance.openstack.common import importutils from glance.openstack.common import importutils
notifier_opts = [
cfg.StrOpt('notifier_strategy', default='default')
]
CONF = cfg.CONF
CONF.register_opts(notifier_opts)
_STRATEGIES = { _STRATEGIES = {
"logging": "glance.notifier.notify_log.LoggingStrategy", "logging": "glance.notifier.notify_log.LoggingStrategy",
@ -37,12 +43,7 @@ _STRATEGIES = {
class Notifier(object): class Notifier(object):
"""Uses a notification strategy to send out messages about events.""" """Uses a notification strategy to send out messages about events."""
opts = [
cfg.StrOpt('notifier_strategy', default='default')
]
def __init__(self, conf, strategy=None): def __init__(self, conf, strategy=None):
conf.register_opts(self.opts)
strategy = conf.notifier_strategy strategy = conf.notifier_strategy
try: try:
strategy_cls = _STRATEGIES[strategy] strategy_cls = _STRATEGIES[strategy]

View File

@ -24,9 +24,26 @@ import kombu.entity
from glance.notifier import strategy from glance.notifier import strategy
from glance.openstack.common import cfg from glance.openstack.common import cfg
logger = logging.getLogger('glance.notifier.notify_kombu') logger = logging.getLogger('glance.notifier.notify_kombu')
rabbit_opts = [
cfg.StrOpt('rabbit_host', default='localhost'),
cfg.IntOpt('rabbit_port', default=5672),
cfg.BoolOpt('rabbit_use_ssl', default=False),
cfg.StrOpt('rabbit_userid', default='guest'),
cfg.StrOpt('rabbit_password', default='guest'),
cfg.StrOpt('rabbit_virtual_host', default='/'),
cfg.StrOpt('rabbit_notification_exchange', default='glance'),
cfg.StrOpt('rabbit_notification_topic',
default='glance_notifications'),
cfg.StrOpt('rabbit_max_retries', default=0),
cfg.StrOpt('rabbit_retry_backoff', default=2),
cfg.StrOpt('rabbit_retry_max_backoff', default=30)
]
CONF = cfg.CONF
CONF.register_opts(rabbit_opts)
class KombuMaxRetriesReached(Exception): class KombuMaxRetriesReached(Exception):
pass pass
@ -35,25 +52,9 @@ class KombuMaxRetriesReached(Exception):
class RabbitStrategy(strategy.Strategy): class RabbitStrategy(strategy.Strategy):
"""A notifier that puts a message on a queue when called.""" """A notifier that puts a message on a queue when called."""
opts = [
cfg.StrOpt('rabbit_host', default='localhost'),
cfg.IntOpt('rabbit_port', default=5672),
cfg.BoolOpt('rabbit_use_ssl', default=False),
cfg.StrOpt('rabbit_userid', default='guest'),
cfg.StrOpt('rabbit_password', default='guest'),
cfg.StrOpt('rabbit_virtual_host', default='/'),
cfg.StrOpt('rabbit_notification_exchange', default='glance'),
cfg.StrOpt('rabbit_notification_topic',
default='glance_notifications'),
cfg.StrOpt('rabbit_max_retries', default=0),
cfg.StrOpt('rabbit_retry_backoff', default=2),
cfg.StrOpt('rabbit_retry_max_backoff', default=30)
]
def __init__(self, conf): def __init__(self, conf):
"""Initialize the rabbit notification strategy.""" """Initialize the rabbit notification strategy."""
self._conf = conf self._conf = conf
self._conf.register_opts(self.opts)
self.topic = self._conf.rabbit_notification_topic self.topic = self._conf.rabbit_notification_topic
self.max_retries = self._conf.rabbit_max_retries self.max_retries = self._conf.rabbit_max_retries

View File

@ -22,10 +22,8 @@ import qpid.messaging
from glance.notifier import strategy from glance.notifier import strategy
from glance.openstack.common import cfg from glance.openstack.common import cfg
logger = logging.getLogger('glance.notifier.notify_qpid') logger = logging.getLogger('glance.notifier.notify_qpid')
qpid_opts = [ qpid_opts = [
cfg.StrOpt('qpid_notification_exchange', cfg.StrOpt('qpid_notification_exchange',
default='glance', default='glance',
@ -74,6 +72,9 @@ qpid_opts = [
help='Disable Nagle algorithm'), help='Disable Nagle algorithm'),
] ]
CONF = cfg.CONF
CONF.register_opts(qpid_opts)
class QpidStrategy(strategy.Strategy): class QpidStrategy(strategy.Strategy):
"""A notifier that puts a message on a queue when called.""" """A notifier that puts a message on a queue when called."""
@ -81,7 +82,6 @@ class QpidStrategy(strategy.Strategy):
def __init__(self, conf): def __init__(self, conf):
"""Initialize the Qpid notification strategy.""" """Initialize the Qpid notification strategy."""
self.conf = conf self.conf = conf
self.conf.register_opts(qpid_opts)
self.broker = self.conf.qpid_hostname + ":" + self.conf.qpid_port self.broker = self.conf.qpid_hostname + ":" + self.conf.qpid_port
self.connection = qpid.messaging.Connection(self.broker) self.connection = qpid.messaging.Connection(self.broker)

View File

@ -95,7 +95,7 @@ and --config-dir::
class ConfigOpts(object): class ConfigOpts(object):
def __init__(self, ...): def __call__(self, ...):
opts = [ opts = [
MultiStrOpt('config-file', MultiStrOpt('config-file',
@ -233,6 +233,22 @@ log files:
... ...
] ]
This module also contains a global instance of the CommonConfigOpts class
in order to support a common usage pattern in OpenStack:
from openstack.common import cfg
opts = [
cfg.StrOpt('bind_host' default='0.0.0.0'),
cfg.IntOpt('bind_port', default=9292),
]
CONF = cfg.CONF
CONF.register_opts(opts)
def start(server, app):
server.start(app, CONF.bind_port, CONF.bind_host)
""" """
import collections import collections
@ -768,6 +784,14 @@ class OptGroup(object):
return True return True
def _unregister_opt(self, opt):
"""Remove an opt from this group.
:param opt: an Opt object
"""
if opt.dest in self._opts:
del self._opts[opt.dest]
def _get_optparse_group(self, parser): def _get_optparse_group(self, parser):
"""Build an optparse.OptionGroup for this group.""" """Build an optparse.OptionGroup for this group."""
if self._optparse_group is None: if self._optparse_group is None:
@ -775,6 +799,10 @@ class OptGroup(object):
self.help) self.help)
return self._optparse_group return self._optparse_group
def _clear(self):
"""Clear this group's option parsing state."""
self._optparse_group = None
class ParseError(iniparser.ParseError): class ParseError(iniparser.ParseError):
def __init__(self, msg, lineno, line, filename): def __init__(self, msg, lineno, line, filename):
@ -849,57 +877,41 @@ class ConfigOpts(collections.Mapping):
the values of options. the values of options.
""" """
def __init__(self, def __init__(self):
project=None, """Construct a ConfigOpts object."""
prog=None, self._opts = {} # dict of dicts of (opt:, override:, default:)
version=None, self._groups = {}
usage=None,
default_config_files=None):
"""Construct a ConfigOpts object.
Automatically registers the --config-file option with either a supplied self._args = None
list of default config files, or a list from find_config_files(). self._oparser = None
self._cparser = None
self._cli_values = {}
self.__cache = {}
self._config_opts = []
self._disable_interspersed_args = False
:param project: the toplevel project name, used to locate config files def _setup(self, project, prog, version, usage, default_config_files):
:param prog: the name of the program (defaults to sys.argv[0] basename) """Initialize a ConfigOpts object for option parsing."""
:param version: the program version (for --version)
:param usage: a usage string (%prog will be expanded)
:param default_config_files: config files to use by default
"""
if prog is None: if prog is None:
prog = os.path.basename(sys.argv[0]) prog = os.path.basename(sys.argv[0])
if default_config_files is None: if default_config_files is None:
default_config_files = find_config_files(project, prog) default_config_files = find_config_files(project, prog)
self.project = project self._oparser = optparse.OptionParser(prog=prog,
self.prog = prog version=version,
self.version = version usage=usage)
self.usage = usage if self._disable_interspersed_args:
self.default_config_files = default_config_files self._oparser.disable_interspersed_args()
self._opts = {} # dict of dicts of (opt:, override:, default:) self._config_opts = [
self._groups = {}
self._args = None
self._cli_values = {}
self._oparser = optparse.OptionParser(prog=self.prog,
version=self.version,
usage=self.usage)
self._cparser = None
self.__cache = {}
opts = [
MultiStrOpt('config-file', MultiStrOpt('config-file',
default=self.default_config_files, default=default_config_files,
metavar='PATH', metavar='PATH',
help='Path to a config file to use. Multiple config ' help='Path to a config file to use. Multiple config '
'files can be specified, with values in later ' 'files can be specified, with values in later '
'files taking precedence. The default files ' 'files taking precedence. The default files '
' used are: %s' % ' used are: %s' % (default_config_files, )),
(self.default_config_files, )),
StrOpt('config-dir', StrOpt('config-dir',
metavar='DIR', metavar='DIR',
help='Path to a config directory to pull *.conf ' help='Path to a config directory to pull *.conf '
@ -910,7 +922,13 @@ class ConfigOpts(collections.Mapping):
'hence over-ridden options in the directory take ' 'hence over-ridden options in the directory take '
'precedence.'), 'precedence.'),
] ]
self.register_cli_opts(opts) self.register_cli_opts(self._config_opts)
self.project = project
self.prog = prog
self.version = version
self.usage = usage
self.default_config_files = default_config_files
def __clear_cache(f): def __clear_cache(f):
@functools.wraps(f) @functools.wraps(f)
@ -921,7 +939,13 @@ class ConfigOpts(collections.Mapping):
return __inner return __inner
def __call__(self, args=None): def __call__(self,
args=None,
project=None,
prog=None,
version=None,
usage=None,
default_config_files=None):
"""Parse command line arguments and config files. """Parse command line arguments and config files.
Calling a ConfigOpts object causes the supplied command line arguments Calling a ConfigOpts object causes the supplied command line arguments
@ -931,35 +955,34 @@ class ConfigOpts(collections.Mapping):
The object may be called multiple times, each time causing the previous The object may be called multiple times, each time causing the previous
set of values to be overwritten. set of values to be overwritten.
Automatically registers the --config-file option with either a supplied
list of default config files, or a list from find_config_files().
If the --config-dir option is set, any *.conf files from this If the --config-dir option is set, any *.conf files from this
directory are pulled in, after all the file(s) specified by the directory are pulled in, after all the file(s) specified by the
--config-file option. --config-file option.
:params args: command line arguments (defaults to sys.argv[1:]) :param args: command line arguments (defaults to sys.argv[1:])
:param project: the toplevel project name, used to locate config files
:param prog: the name of the program (defaults to sys.argv[0] basename)
:param version: the program version (for --version)
:param usage: a usage string (%prog will be expanded)
:param default_config_files: config files to use by default
:returns: the list of arguments left over after parsing options :returns: the list of arguments left over after parsing options
:raises: SystemExit, ConfigFilesNotFoundError, ConfigFileParseError, :raises: SystemExit, ConfigFilesNotFoundError, ConfigFileParseError,
RequiredOptError RequiredOptError, DuplicateOptError
""" """
self.clear() self.clear()
self._args = args self._setup(project, prog, version, usage, default_config_files)
(values, args) = self._oparser.parse_args(self._args) self._cli_values, leftovers = self._parse_cli_opts(args)
self._cli_values = vars(values) self._parse_config_files()
def _list_config_dir():
return sorted(glob.glob(os.path.join(self.config_dir, '*.conf')))
from_file = list(self.config_file)
from_dir = _list_config_dir() if self.config_dir else []
self._parse_config_files(from_file + from_dir)
self._check_required_opts() self._check_required_opts()
return args return leftovers
def __getattr__(self, name): def __getattr__(self, name):
"""Look up an option value and perform string substitution. """Look up an option value and perform string substitution.
@ -996,8 +1019,12 @@ class ConfigOpts(collections.Mapping):
def clear(self): def clear(self):
"""Clear the state of the object to before it was called.""" """Clear the state of the object to before it was called."""
self._args = None self._args = None
self._cli_values = {} self._cli_values.clear()
self._oparser = None
self._cparser = None self._cparser = None
self.unregister_opts(self._config_opts)
for group in self._groups.values():
group._clear()
@__clear_cache @__clear_cache
def register_opt(self, opt, group=None): def register_opt(self, opt, group=None):
@ -1044,15 +1071,7 @@ class ConfigOpts(collections.Mapping):
if self._args is not None: if self._args is not None:
raise ArgsAlreadyParsedError("cannot register CLI option") raise ArgsAlreadyParsedError("cannot register CLI option")
if not self.register_opt(opt, group, clear_cache=False): return self.register_opt(opt, group, clear_cache=False)
return False
if group is not None:
group = self._get_group(group, autocreate=True)
opt._add_to_cli(self._oparser, group)
return True
@__clear_cache @__clear_cache
def register_cli_opts(self, opts, group=None): def register_cli_opts(self, opts, group=None):
@ -1073,6 +1092,28 @@ class ConfigOpts(collections.Mapping):
self._groups[group.name] = copy.copy(group) self._groups[group.name] = copy.copy(group)
@__clear_cache
def unregister_opt(self, opt, group=None):
"""Unregister an option.
:param opt: an Opt object
:param group: an optional OptGroup object or group name
:raises: ArgsAlreadyParsedError, NoSuchGroupError
"""
if self._args is not None:
raise ArgsAlreadyParsedError("reset before unregistering options")
if group is not None:
self._get_group(group)._unregister_opt(opt)
elif opt.dest in self._opts:
del self._opts[opt.dest]
@__clear_cache
def unregister_opts(self, opts, group=None):
"""Unregister multiple CLI option schemas at once."""
for opt in opts:
self.unregister_opt(opt, group, clear_cache=False)
@__clear_cache @__clear_cache
def set_override(self, name, override, group=None): def set_override(self, name, override, group=None):
"""Override an opt value. """Override an opt value.
@ -1103,16 +1144,24 @@ class ConfigOpts(collections.Mapping):
opt_info = self._get_opt_info(name, group) opt_info = self._get_opt_info(name, group)
opt_info['default'] = default opt_info['default'] = default
def _all_opt_infos(self):
"""A generator function for iteration opt infos."""
for info in self._opts.values():
yield info, None
for group in self._groups.values():
for info in group._opts.values():
yield info, group
def _all_opts(self):
"""A generator function for iteration opts."""
for info, group in self._all_opt_infos():
yield info['opt'], group
def _unset_defaults_and_overrides(self): def _unset_defaults_and_overrides(self):
"""Unset any default or override on all options.""" """Unset any default or override on all options."""
def unset(opts): for info, group in self._all_opt_infos():
for info in opts.values(): info['default'] = None
info['default'] = None info['override'] = None
info['override'] = None
unset(self._opts)
for group in self._groups.values():
unset(group._opts)
def disable_interspersed_args(self): def disable_interspersed_args(self):
"""Set parsing to stop on the first non-option. """Set parsing to stop on the first non-option.
@ -1131,13 +1180,13 @@ class ConfigOpts(collections.Mapping):
i.e. argument parsing is stopped at the first non-option argument. i.e. argument parsing is stopped at the first non-option argument.
""" """
self._oparser.disable_interspersed_args() self._disable_interspersed_args = True
def enable_interspersed_args(self): def enable_interspersed_args(self):
"""Set parsing to not stop on the first non-option. """Set parsing to not stop on the first non-option.
This it the default behaviour.""" This it the default behaviour."""
self._oparser.enable_interspersed_args() self._disable_interspersed_args = False
def find_file(self, name): def find_file(self, name):
"""Locate a file located alongside the config files. """Locate a file located alongside the config files.
@ -1331,11 +1380,17 @@ class ConfigOpts(collections.Mapping):
return opts[opt_name] return opts[opt_name]
def _parse_config_files(self, config_files): def _parse_config_files(self):
"""Parse the supplied configuration files. """Parse the config files from --config-file and --config-dir.
:raises: ConfigFilesNotFoundError, ConfigFileParseError :raises: ConfigFilesNotFoundError, ConfigFileParseError
""" """
config_files = list(self.config_file)
if self.config_dir:
config_dir_glob = os.path.join(self.config_dir, '*.conf')
config_files += sorted(glob.glob(config_dir_glob))
self._cparser = MultiConfigParser() self._cparser = MultiConfigParser()
try: try:
@ -1347,8 +1402,12 @@ class ConfigOpts(collections.Mapping):
not_read_ok = filter(lambda f: f not in read_ok, config_files) not_read_ok = filter(lambda f: f not in read_ok, config_files)
raise ConfigFilesNotFoundError(not_read_ok) raise ConfigFilesNotFoundError(not_read_ok)
def _do_check_required_opts(self, opts, group=None): def _check_required_opts(self):
for info in opts.values(): """Check that all opts marked as required have values specified.
:raises: RequiredOptError
"""
for info, group in self._all_opt_infos():
default, opt, override = [info[k] for k in sorted(info.keys())] default, opt, override = [info[k] for k in sorted(info.keys())]
if opt.required: if opt.required:
@ -1359,15 +1418,25 @@ class ConfigOpts(collections.Mapping):
if self._get(opt.name, group) is None: if self._get(opt.name, group) is None:
raise RequiredOptError(opt.name, group) raise RequiredOptError(opt.name, group)
def _check_required_opts(self): def _parse_cli_opts(self, args):
"""Check that all opts marked as required have values specified. """Parse command line options.
Initializes the command line option parser and parses the supplied
command line arguments.
:param args: the command line arguments
:returns: a dict of parsed option values
:raises: SystemExit, DuplicateOptError
:raises: RequiredOptError
""" """
self._do_check_required_opts(self._opts) self._args = args
for group in self._groups.values(): for opt, group in self._all_opts():
self._do_check_required_opts(group._opts, group) opt._add_to_cli(self._oparser, group)
values, leftovers = self._oparser.parse_args(args)
return vars(values), leftovers
class GroupAttr(collections.Mapping): class GroupAttr(collections.Mapping):
@ -1483,7 +1552,10 @@ class CommonConfigOpts(ConfigOpts):
help='syslog facility to receive log lines') help='syslog facility to receive log lines')
] ]
def __init__(self, **kwargs): def __init__(self):
super(CommonConfigOpts, self).__init__(**kwargs) super(CommonConfigOpts, self).__init__()
self.register_cli_opts(self.common_cli_opts) self.register_cli_opts(self.common_cli_opts)
self.register_cli_opts(self.logging_cli_opts) self.register_cli_opts(self.logging_cli_opts)
CONF = CommonConfigOpts()

View File

@ -28,14 +28,6 @@ from glance.registry import client
logger = logging.getLogger('glance.registry') logger = logging.getLogger('glance.registry')
_CLIENT_CREDS = None
_CLIENT_HOST = None
_CLIENT_PORT = None
_CLIENT_KWARGS = {}
# AES key used to encrypt 'location' metadata
_METADATA_ENCRYPTION_KEY = None
registry_addr_opts = [ registry_addr_opts = [
cfg.StrOpt('registry_host', default='0.0.0.0'), cfg.StrOpt('registry_host', default='0.0.0.0'),
cfg.IntOpt('registry_port', default=9191), cfg.IntOpt('registry_port', default=9191),
@ -56,9 +48,20 @@ registry_client_ctx_opts = [
cfg.StrOpt('auth_region'), cfg.StrOpt('auth_region'),
] ]
CONF = cfg.CONF
CONF.register_opts(registry_addr_opts)
CONF.register_opts(registry_client_opts)
CONF.register_opts(registry_client_ctx_opts)
_CLIENT_CREDS = None
_CLIENT_HOST = None
_CLIENT_PORT = None
_CLIENT_KWARGS = {}
# AES key used to encrypt 'location' metadata
_METADATA_ENCRYPTION_KEY = None
def get_registry_addr(conf): def get_registry_addr(conf):
conf.register_opts(registry_addr_opts)
return (conf.registry_host, conf.registry_port) return (conf.registry_host, conf.registry_port)
@ -80,8 +83,6 @@ def configure_registry_client(conf):
logger.error(msg) logger.error(msg)
raise exception.BadRegistryConnectionConfiguration(msg) raise exception.BadRegistryConnectionConfiguration(msg)
conf.register_opts(registry_client_opts)
_CLIENT_HOST = host _CLIENT_HOST = host
_CLIENT_PORT = port _CLIENT_PORT = port
_METADATA_ENCRYPTION_KEY = conf.metadata_encryption_key _METADATA_ENCRYPTION_KEY = conf.metadata_encryption_key
@ -95,7 +96,6 @@ def configure_registry_client(conf):
def configure_registry_admin_creds(conf): def configure_registry_admin_creds(conf):
global _CLIENT_CREDS global _CLIENT_CREDS
conf.register_opts(registry_client_ctx_opts)
if conf.auth_url or os.getenv('OS_AUTH_URL'): if conf.auth_url or os.getenv('OS_AUTH_URL'):
strategy = 'keystone' strategy = 'keystone'

View File

@ -29,9 +29,16 @@ from glance.common import wsgi
from glance.openstack.common import cfg from glance.openstack.common import cfg
from glance.db import api as db_api from glance.db import api as db_api
logger = logging.getLogger('glance.registry.api.v1.images') logger = logging.getLogger('glance.registry.api.v1.images')
images_opts = [
cfg.IntOpt('limit_param_default', default=25),
cfg.IntOpt('api_limit_max', default=1000),
]
CONF = cfg.CONF
CONF.register_opts(images_opts)
DISPLAY_FIELDS_IN_INDEX = ['id', 'name', 'size', DISPLAY_FIELDS_IN_INDEX = ['id', 'name', 'size',
'disk_format', 'container_format', 'disk_format', 'container_format',
'checksum'] 'checksum']
@ -50,14 +57,8 @@ SUPPORTED_PARAMS = ('limit', 'marker', 'sort_key', 'sort_dir')
class Controller(object): class Controller(object):
opts = [
cfg.IntOpt('limit_param_default', default=25),
cfg.IntOpt('api_limit_max', default=1000),
]
def __init__(self, conf): def __init__(self, conf):
self.conf = conf self.conf = conf
self.conf.register_opts(self.opts)
db_api.configure_db(conf) db_api.configure_db(conf)
def _get_images(self, context, **params): def _get_images(self, context, **params):

View File

@ -29,6 +29,18 @@ from glance.store import location
logger = logging.getLogger('glance.store') logger = logging.getLogger('glance.store')
store_opts = [
cfg.ListOpt('known_stores',
default=['glance.store.filesystem.Store', ]),
cfg.StrOpt('scrubber_datadir',
default='/var/lib/glance/scrubber'),
cfg.BoolOpt('delayed_delete', default=False),
cfg.IntOpt('scrub_time', default=0),
]
CONF = cfg.CONF
CONF.register_opts(store_opts)
# Set of store objects, constructed in create_stores() # Set of store objects, constructed in create_stores()
STORES = {} STORES = {}
@ -138,16 +150,11 @@ def _get_store_class(store_entry):
return store_cls return store_cls
known_stores_opt = cfg.ListOpt('known_stores',
default=('glance.store.filesystem.Store',))
def create_stores(conf): def create_stores(conf):
""" """
Registers all store modules and all schemes Registers all store modules and all schemes
from the given config. Duplicates are not re-registered. from the given config. Duplicates are not re-registered.
""" """
conf.register_opt(known_stores_opt)
store_count = 0 store_count = 0
for store_entry in conf.known_stores: for store_entry in conf.known_stores:
store_entry = store_entry.strip() store_entry = store_entry.strip()
@ -242,26 +249,14 @@ def get_store_from_location(uri):
return loc.store_name return loc.store_name
scrubber_datadir_opt = cfg.StrOpt('scrubber_datadir',
default='/var/lib/glance/scrubber')
def get_scrubber_datadir(conf): def get_scrubber_datadir(conf):
conf.register_opt(scrubber_datadir_opt)
return conf.scrubber_datadir return conf.scrubber_datadir
delete_opts = [
cfg.BoolOpt('delayed_delete', default=False),
cfg.IntOpt('scrub_time', default=0)
]
def schedule_delete_from_backend(uri, conf, context, image_id, **kwargs): def schedule_delete_from_backend(uri, conf, context, image_id, **kwargs):
""" """
Given a uri and a time, schedule the deletion of an image. Given a uri and a time, schedule the deletion of an image.
""" """
conf.register_opts(delete_opts)
if not conf.delayed_delete: if not conf.delayed_delete:
registry.update_image_metadata(context, image_id, registry.update_image_metadata(context, image_id,
{'status': 'deleted'}) {'status': 'deleted'})

View File

@ -34,6 +34,11 @@ import glance.store.location
logger = logging.getLogger('glance.store.filesystem') logger = logging.getLogger('glance.store.filesystem')
datadir_opt = cfg.StrOpt('filesystem_store_datadir')
CONF = cfg.CONF
CONF.register_opt(datadir_opt)
class StoreLocation(glance.store.location.StoreLocation): class StoreLocation(glance.store.location.StoreLocation):
@ -96,8 +101,6 @@ class ChunkedFile(object):
class Store(glance.store.base.Store): class Store(glance.store.base.Store):
datadir_opt = cfg.StrOpt('filesystem_store_datadir')
def get_schemes(self): def get_schemes(self):
return ('file', 'filesystem') return ('file', 'filesystem')
@ -108,8 +111,6 @@ class Store(glance.store.base.Store):
this method. If the store was not able to successfully configure this method. If the store was not able to successfully configure
itself, it should raise `exception.BadStoreConfiguration` itself, it should raise `exception.BadStoreConfiguration`
""" """
self.conf.register_opt(self.datadir_opt)
self.datadir = self.conf.filesystem_store_datadir self.datadir = self.conf.filesystem_store_datadir
if self.datadir is None: if self.datadir is None:
reason = (_("Could not find %s in configuration options.") % reason = (_("Could not find %s in configuration options.") %

View File

@ -43,6 +43,16 @@ DEFAULT_CHUNKSIZE = 4 # in MiB
logger = logging.getLogger('glance.store.rbd') logger = logging.getLogger('glance.store.rbd')
rbd_opts = [
cfg.IntOpt('rbd_store_chunk_size', default=DEFAULT_CHUNKSIZE),
cfg.StrOpt('rbd_store_pool', default=DEFAULT_POOL),
cfg.StrOpt('rbd_store_user', default=DEFAULT_USER),
cfg.StrOpt('rbd_store_ceph_conf', default=DEFAULT_CONFFILE),
]
CONF = cfg.CONF
CONF.register_opts(rbd_opts)
class StoreLocation(glance.store.location.StoreLocation): class StoreLocation(glance.store.location.StoreLocation):
""" """
@ -101,13 +111,6 @@ class Store(glance.store.base.Store):
EXAMPLE_URL = "rbd://<IMAGE>" EXAMPLE_URL = "rbd://<IMAGE>"
opts = [
cfg.IntOpt('rbd_store_chunk_size', default=DEFAULT_CHUNKSIZE),
cfg.StrOpt('rbd_store_pool', default=DEFAULT_POOL),
cfg.StrOpt('rbd_store_user', default=DEFAULT_USER),
cfg.StrOpt('rbd_store_ceph_conf', default=DEFAULT_CONFFILE),
]
def get_schemes(self): def get_schemes(self):
return ('rbd',) return ('rbd',)
@ -118,7 +121,6 @@ class Store(glance.store.base.Store):
this method. If the store was not able to successfully configure this method. If the store was not able to successfully configure
itself, it should raise `exception.BadStoreConfiguration` itself, it should raise `exception.BadStoreConfiguration`
""" """
self.conf.register_opts(self.opts)
try: try:
self.chunk_size = self.conf.rbd_store_chunk_size * 1024 * 1024 self.chunk_size = self.conf.rbd_store_chunk_size * 1024 * 1024

View File

@ -33,6 +33,18 @@ import glance.store.location
logger = logging.getLogger('glance.store.s3') logger = logging.getLogger('glance.store.s3')
s3_opts = [
cfg.StrOpt('s3_store_host'),
cfg.StrOpt('s3_store_access_key', secret=True),
cfg.StrOpt('s3_store_secret_key', secret=True),
cfg.StrOpt('s3_store_bucket'),
cfg.StrOpt('s3_store_object_buffer_dir'),
cfg.BoolOpt('s3_store_create_bucket_on_put', default=False),
]
CONF = cfg.CONF
CONF.register_opts(s3_opts)
class StoreLocation(glance.store.location.StoreLocation): class StoreLocation(glance.store.location.StoreLocation):
@ -189,15 +201,6 @@ class Store(glance.store.base.Store):
EXAMPLE_URL = "s3://<ACCESS_KEY>:<SECRET_KEY>@<S3_URL>/<BUCKET>/<OBJ>" EXAMPLE_URL = "s3://<ACCESS_KEY>:<SECRET_KEY>@<S3_URL>/<BUCKET>/<OBJ>"
opts = [
cfg.StrOpt('s3_store_host'),
cfg.StrOpt('s3_store_access_key', secret=True),
cfg.StrOpt('s3_store_secret_key', secret=True),
cfg.StrOpt('s3_store_bucket'),
cfg.StrOpt('s3_store_object_buffer_dir'),
cfg.BoolOpt('s3_store_create_bucket_on_put', default=False),
]
def get_schemes(self): def get_schemes(self):
return ('s3', 's3+http', 's3+https') return ('s3', 's3+http', 's3+https')
@ -208,7 +211,6 @@ class Store(glance.store.base.Store):
this method. If the store was not able to successfully configure this method. If the store was not able to successfully configure
itself, it should raise `exception.BadStoreConfiguration` itself, it should raise `exception.BadStoreConfiguration`
""" """
self.conf.register_opts(self.opts)
self.s3_host = self._option_get('s3_store_host') self.s3_host = self._option_get('s3_store_host')
access_key = self._option_get('s3_store_access_key') access_key = self._option_get('s3_store_access_key')
secret_key = self._option_get('s3_store_secret_key') secret_key = self._option_get('s3_store_secret_key')

View File

@ -31,9 +31,16 @@ from glance.common import utils
from glance.openstack.common import cfg from glance.openstack.common import cfg
from glance.registry import client from glance.registry import client
logger = logging.getLogger('glance.store.scrubber') logger = logging.getLogger('glance.store.scrubber')
scrubber_opts = [
cfg.BoolOpt('cleanup_scrubber', default=False),
cfg.IntOpt('cleanup_scrubber_time', default=86400)
]
CONF = cfg.CONF
CONF.register_opts(scrubber_opts)
class Daemon(object): class Daemon(object):
def __init__(self, wakeup_time=300, threads=1000): def __init__(self, wakeup_time=300, threads=1000):
@ -63,14 +70,8 @@ class Daemon(object):
class Scrubber(object): class Scrubber(object):
CLEANUP_FILE = ".cleanup" CLEANUP_FILE = ".cleanup"
opts = [
cfg.BoolOpt('cleanup_scrubber', default=False),
cfg.IntOpt('cleanup_scrubber_time', default=86400)
]
def __init__(self, conf, **local_conf): def __init__(self, conf, **local_conf):
self.conf = conf self.conf = conf
self.conf.register_opts(self.opts)
self.datadir = store.get_scrubber_datadir(conf) self.datadir = store.get_scrubber_datadir(conf)
self.cleanup = self.conf.cleanup_scrubber self.cleanup = self.conf.cleanup_scrubber

View File

@ -37,12 +37,30 @@ try:
except ImportError: except ImportError:
pass pass
logger = logging.getLogger('glance.store.swift')
DEFAULT_CONTAINER = 'glance' DEFAULT_CONTAINER = 'glance'
DEFAULT_LARGE_OBJECT_SIZE = 5 * 1024 # 5GB DEFAULT_LARGE_OBJECT_SIZE = 5 * 1024 # 5GB
DEFAULT_LARGE_OBJECT_CHUNK_SIZE = 200 # 200M DEFAULT_LARGE_OBJECT_CHUNK_SIZE = 200 # 200M
ONE_MB = 1000 * 1024 ONE_MB = 1000 * 1024
logger = logging.getLogger('glance.store.swift') swift_opts = [
cfg.BoolOpt('swift_enable_snet', default=False),
cfg.StrOpt('swift_store_auth_address'),
cfg.StrOpt('swift_store_user', secret=True),
cfg.StrOpt('swift_store_key', secret=True),
cfg.StrOpt('swift_store_auth_version', default='2'),
cfg.StrOpt('swift_store_container',
default=DEFAULT_CONTAINER),
cfg.IntOpt('swift_store_large_object_size',
default=DEFAULT_LARGE_OBJECT_SIZE),
cfg.IntOpt('swift_store_large_object_chunk_size',
default=DEFAULT_LARGE_OBJECT_CHUNK_SIZE),
cfg.BoolOpt('swift_store_create_container_on_put', default=False),
]
CONF = cfg.CONF
CONF.register_opts(swift_opts)
class StoreLocation(glance.store.location.StoreLocation): class StoreLocation(glance.store.location.StoreLocation):
@ -180,26 +198,10 @@ class Store(glance.store.base.Store):
CHUNKSIZE = 65536 CHUNKSIZE = 65536
opts = [
cfg.BoolOpt('swift_enable_snet', default=False),
cfg.StrOpt('swift_store_auth_address'),
cfg.StrOpt('swift_store_user', secret=True),
cfg.StrOpt('swift_store_key', secret=True),
cfg.StrOpt('swift_store_auth_version', default='2'),
cfg.StrOpt('swift_store_container',
default=DEFAULT_CONTAINER),
cfg.IntOpt('swift_store_large_object_size',
default=DEFAULT_LARGE_OBJECT_SIZE),
cfg.IntOpt('swift_store_large_object_chunk_size',
default=DEFAULT_LARGE_OBJECT_CHUNK_SIZE),
cfg.BoolOpt('swift_store_create_container_on_put', default=False),
]
def get_schemes(self): def get_schemes(self):
return ('swift+https', 'swift', 'swift+http') return ('swift+https', 'swift', 'swift+http')
def configure(self): def configure(self):
self.conf.register_opts(self.opts)
self.snet = self.conf.swift_enable_snet self.snet = self.conf.swift_enable_snet
self.auth_version = self._option_get('swift_store_auth_version') self.auth_version = self._option_get('swift_store_auth_version')

View File

@ -176,7 +176,7 @@ class ApiServer(Server):
super(ApiServer, self).__init__(test_dir, port) super(ApiServer, self).__init__(test_dir, port)
self.server_name = 'api' self.server_name = 'api'
self.default_store = 'file' self.default_store = 'file'
self.known_stores = test_utils.get_default_stores() self.known_stores = ", ".join(test_utils.get_default_stores())
self.key_file = "" self.key_file = ""
self.cert_file = "" self.cert_file = ""
self.metadata_encryption_key = "012345678901234567890123456789ab" self.metadata_encryption_key = "012345678901234567890123456789ab"
@ -426,6 +426,7 @@ class FunctionalTest(test_utils.BaseTestCase):
log_files = [] log_files = []
def setUp(self): def setUp(self):
super(FunctionalTest, self).setUp()
self.test_id, self.test_dir = test_utils.get_isolated_test_env() self.test_id, self.test_dir = test_utils.get_isolated_test_env()
self.api_protocol = 'http' self.api_protocol = 'http'
@ -463,6 +464,7 @@ class FunctionalTest(test_utils.BaseTestCase):
# from the tests # from the tests
self._reset_database(self.registry_server.sql_connection) self._reset_database(self.registry_server.sql_connection)
self._reset_database(self.api_server.sql_connection) self._reset_database(self.api_server.sql_connection)
super(FunctionalTest, self).tearDown()
def set_policy_rules(self, rules): def set_policy_rules(self, rules):
fap = open(self.policy_file, 'w') fap = open(self.policy_file, 'w')

View File

@ -69,8 +69,8 @@ class TestClientExceptions(functional.FunctionalTest):
super(TestClientExceptions, self).setUp() super(TestClientExceptions, self).setUp()
self.port = utils.get_unused_port() self.port = utils.get_unused_port()
server = wsgi.Server() server = wsgi.Server()
conf = utils.TestConfigOpts({'bind_host': '127.0.0.1'}) self.config(bind_host='127.0.0.1')
server.start(ExceptionTestApp(), conf, self.port) server.start(ExceptionTestApp(), self.conf, self.port)
self.client = client.BaseClient("127.0.0.1", self.port) self.client = client.BaseClient("127.0.0.1", self.port)
def _do_test_exception(self, path, exc_type): def _do_test_exception(self, path, exc_type):

View File

@ -86,9 +86,9 @@ class TestClientRedirects(functional.FunctionalTest):
self.port_two = utils.get_unused_port() self.port_two = utils.get_unused_port()
server_one = wsgi.Server() server_one = wsgi.Server()
server_two = wsgi.Server() server_two = wsgi.Server()
conf = utils.TestConfigOpts({'bind_host': '127.0.0.1'}) self.config(bind_host='127.0.0.1')
server_one.start(RedirectTestApp("one"), conf, self.port_one) server_one.start(RedirectTestApp("one"), self.conf, self.port_one)
server_two.start(RedirectTestApp("two"), conf, self.port_two) server_two.start(RedirectTestApp("two"), self.conf, self.port_two)
self.client = client.BaseClient("127.0.0.1", self.port_one) self.client = client.BaseClient("127.0.0.1", self.port_one)
def test_get_without_redirect(self): def test_get_without_redirect(self):

View File

@ -21,8 +21,7 @@ class TestSchemaAPI(utils.BaseTestCase):
def setUp(self): def setUp(self):
super(TestSchemaAPI, self).setUp() super(TestSchemaAPI, self).setUp()
conf = utils.TestConfigOpts() self.schema_api = glance.schema.API(self.conf)
self.schema_api = glance.schema.API(conf)
def test_load_image_schema(self): def test_load_image_schema(self):
output = self.schema_api.get_schema('image') output = self.schema_api.get_schema('image')

View File

@ -92,6 +92,7 @@ class TestRBD(test_api.TestApi):
def setUp(self): def setUp(self):
if self.disabled: if self.disabled:
return return
super(TestRBD, self).setUp()
import rados import rados
try: try:
self.create_pool() self.create_pool()
@ -99,11 +100,11 @@ class TestRBD(test_api.TestApi):
self.disabled_message = ("Failed to create pool: %s" % e) self.disabled_message = ("Failed to create pool: %s" % e)
self.disabled = True self.disabled = True
return return
super(TestRBD, self).setUp()
def tearDown(self): def tearDown(self):
if not self.disabled: if self.disabled:
self.delete_pool() return
self.delete_pool()
super(TestRBD, self).tearDown() super(TestRBD, self).tearDown()
def create_pool(self): def create_pool(self):

View File

@ -89,6 +89,11 @@ class TestSSL(functional.FunctionalTest):
super(TestSSL, self).setUp() super(TestSSL, self).setUp()
def tearDown(self):
if getattr(self, 'inited', False):
return
super(TestSSL, self).tearDown()
@skip_if_disabled @skip_if_disabled
def test_get_head_simple_post(self): def test_get_head_simple_post(self):
""" """

View File

@ -23,6 +23,7 @@ import stubout
from glance import store from glance import store
from glance.store import location from glance.store import location
from glance.store import filesystem
from glance.tests import stubs from glance.tests import stubs
from glance.tests import utils as test_utils from glance.tests import utils as test_utils
@ -34,6 +35,7 @@ class StoreClearingUnitTest(test_utils.BaseTestCase):
# Ensure stores + locations cleared # Ensure stores + locations cleared
store.STORES = {} store.STORES = {}
location.SCHEME_TO_CLS_MAP = {} location.SCHEME_TO_CLS_MAP = {}
store.create_stores(self.conf)
def tearDown(self): def tearDown(self):
super(StoreClearingUnitTest, self).tearDown() super(StoreClearingUnitTest, self).tearDown()
@ -50,18 +52,17 @@ class IsolatedUnitTest(StoreClearingUnitTest):
""" """
def setUp(self): def setUp(self):
super(IsolatedUnitTest, self).setUp()
self.test_id, self.test_dir = test_utils.get_isolated_test_env() self.test_id, self.test_dir = test_utils.get_isolated_test_env()
self.stubs = stubout.StubOutForTesting() self.stubs = stubout.StubOutForTesting()
policy_file = self._copy_data_file('policy.json', self.test_dir) policy_file = self._copy_data_file('policy.json', self.test_dir)
options = {'sql_connection': 'sqlite://', self.config(sql_connection='sqlite://',
'verbose': False, verbose=False,
'debug': False, debug=False,
'default_store': 'filesystem', default_store='filesystem',
'known_stores': test_utils.get_default_stores(), known_stores=test_utils.get_default_stores(),
'filesystem_store_datadir': os.path.join(self.test_dir), filesystem_store_datadir=os.path.join(self.test_dir),
'policy_file': policy_file} policy_file=policy_file)
self.conf = test_utils.TestConfigOpts(options) super(IsolatedUnitTest, self).setUp()
stubs.stub_out_registry_and_store_server(self.stubs, stubs.stub_out_registry_and_store_server(self.stubs,
self.conf, self.conf,
self.test_dir) self.test_dir)

View File

@ -30,8 +30,6 @@ from glance.registry import client as rclient
from glance.tests.unit import base from glance.tests.unit import base
from glance.tests import utils as test_utils from glance.tests import utils as test_utils
CONF = {'sql_connection': 'sqlite://'}
_gen_uuid = utils.generate_uuid _gen_uuid = utils.generate_uuid
UUID1 = _gen_uuid() UUID1 = _gen_uuid()

View File

@ -17,12 +17,14 @@
import os.path import os.path
import shutil import shutil
import tempfile
import stubout import stubout
from glance.common import config from glance.common import config
from glance.common import context from glance.common import context
from glance.image_cache import pruner from glance.image_cache import pruner
from glance.openstack.common import cfg
from glance.tests import utils as test_utils from glance.tests import utils as test_utils
@ -38,12 +40,14 @@ class TestPasteApp(test_utils.BaseTestCase):
def _do_test_load_paste_app(self, def _do_test_load_paste_app(self,
expected_app_type, expected_app_type,
paste_group={}, paste_flavor=None,
paste_copy=True, paste_config_file=None,
paste_append=None): paste_append=None):
conf = test_utils.TestConfigOpts(groups=paste_group, def _writeto(path, str):
clean=False) with open(path, 'wb') as f:
f.write(str or '')
f.flush()
def _appendto(orig, copy, str): def _appendto(orig, copy, str):
shutil.copy(orig, copy) shutil.copy(orig, copy)
@ -51,42 +55,47 @@ class TestPasteApp(test_utils.BaseTestCase):
f.write(str or '') f.write(str or '')
f.flush() f.flush()
paste_to = os.path.join(conf.temp_file.replace('.conf', self.config(flavor=paste_flavor,
'-paste.ini')) config_file=paste_config_file,
if paste_copy: group='paste_deploy')
paste_from = os.path.join(os.getcwd(),
'etc/glance-registry-paste.ini')
_appendto(paste_from, paste_to, paste_append)
app = config.load_paste_app(conf, 'glance-registry') temp_file = os.path.join(tempfile.mkdtemp(), 'testcfg.conf')
self.assertEquals(expected_app_type, type(app)) try:
_writeto(temp_file, '[DEFAULT]\n')
if paste_copy: config.parse_args(['--config-file', temp_file])
os.remove(conf.temp_file)
os.remove(paste_to) paste_to = temp_file.replace('.conf', '-paste.ini')
os.rmdir(os.path.dirname(conf.temp_file)) if not paste_config_file:
paste_from = os.path.join(os.getcwd(),
'etc/glance-registry-paste.ini')
_appendto(paste_from, paste_to, paste_append)
app = config.load_paste_app(self.conf, 'glance-registry')
self.assertEquals(expected_app_type, type(app))
finally:
shutil.rmtree(os.path.dirname(temp_file))
def test_load_paste_app(self): def test_load_paste_app(self):
expected_middleware = context.UnauthenticatedContextMiddleware expected_middleware = context.UnauthenticatedContextMiddleware
self._do_test_load_paste_app(expected_middleware) self._do_test_load_paste_app(expected_middleware)
def test_load_paste_app_with_paste_flavor(self): def test_load_paste_app_with_paste_flavor(self):
paste_group = {'paste_deploy': {'flavor': 'incomplete'}}
pipeline = ('[pipeline:glance-registry-incomplete]\n' pipeline = ('[pipeline:glance-registry-incomplete]\n'
'pipeline = context registryapp') 'pipeline = context registryapp')
expected_middleware = context.ContextMiddleware
type = context.ContextMiddleware self._do_test_load_paste_app(expected_middleware,
self._do_test_load_paste_app(type, paste_group, paste_append=pipeline) paste_flavor='incomplete',
paste_append=pipeline)
def test_load_paste_app_with_paste_config_file(self): def test_load_paste_app_with_paste_config_file(self):
paste_config_file = os.path.join(os.getcwd(), paste_config_file = os.path.join(os.getcwd(),
'etc/glance-registry-paste.ini') 'etc/glance-registry-paste.ini')
paste_group = {'paste_deploy': {'config_file': paste_config_file}}
expected_middleware = context.UnauthenticatedContextMiddleware expected_middleware = context.UnauthenticatedContextMiddleware
self._do_test_load_paste_app(expected_middleware, self._do_test_load_paste_app(expected_middleware,
paste_group, paste_copy=False) paste_config_file=paste_config_file)
def test_load_paste_app_with_conf_name(self): def test_load_paste_app_with_conf_name(self):
def fake_join(*args): def fake_join(*args):
@ -100,12 +109,11 @@ class TestPasteApp(test_utils.BaseTestCase):
orig_join = os.path.join orig_join = os.path.join
self.stubs.Set(os.path, 'join', fake_join) self.stubs.Set(os.path, 'join', fake_join)
conf = config.GlanceCacheConfigOpts() config.parse_cache_args([])
conf([])
self.stubs.Set(config, 'setup_logging', lambda *a: None) self.stubs.Set(config, 'setup_logging', lambda *a: None)
self.stubs.Set(pruner, 'Pruner', lambda conf, **lc: 'pruner') self.stubs.Set(pruner, 'Pruner', lambda conf, **lc: 'pruner')
app = config.load_paste_app(conf, 'glance-pruner') app = config.load_paste_app(self.conf, 'glance-pruner')
self.assertEquals('pruner', app) self.assertEquals('pruner', app)

View File

@ -43,19 +43,16 @@ if UUID1 > UUID2:
UUID1, UUID2 = UUID2, UUID1 UUID1, UUID2 = UUID2, UUID1
CONF = {'sql_connection': 'sqlite://',
'verbose': False,
'debug': False}
class BaseDBTestCase(base.IsolatedUnitTest): class BaseDBTestCase(base.IsolatedUnitTest):
def setUp(self): def setUp(self):
super(BaseDBTestCase, self).setUp() super(BaseDBTestCase, self).setUp()
conf = test_utils.TestConfigOpts(CONF) self.config(sql_connection='sqlite://',
verbose=False,
debug=False)
self.adm_context = context.RequestContext(is_admin=True) self.adm_context = context.RequestContext(is_admin=True)
self.context = context.RequestContext(is_admin=False) self.context = context.RequestContext(is_admin=False)
db_api.configure_db(conf) db_api.configure_db(self.conf)
self.destroy_fixtures() self.destroy_fixtures()
self.create_fixtures() self.create_fixtures()
@ -229,10 +226,12 @@ class TestPagingOrder(base.IsolatedUnitTest):
def setUp(self): def setUp(self):
"""Establish a clean test environment""" """Establish a clean test environment"""
super(TestPagingOrder, self).setUp() super(TestPagingOrder, self).setUp()
conf = test_utils.TestConfigOpts(CONF) self.config(sql_connection='sqlite://',
verbose=False,
debug=False)
self.adm_context = context.RequestContext(is_admin=True) self.adm_context = context.RequestContext(is_admin=True)
self.context = context.RequestContext(is_admin=False) self.context = context.RequestContext(is_admin=False)
db_api.configure_db(conf) db_api.configure_db(self.conf)
self.destroy_fixtures() self.destroy_fixtures()
self.create_fixtures() self.create_fixtures()

View File

@ -91,15 +91,13 @@ def stub_out_registry_image_update(stubs, conf):
class TestHttpStore(base.StoreClearingUnitTest): class TestHttpStore(base.StoreClearingUnitTest):
def setUp(self): def setUp(self):
self.config(default_store='http',
known_stores=['glance.store.http.Store'])
super(TestHttpStore, self).setUp() super(TestHttpStore, self).setUp()
self.stubs = stubout.StubOutForTesting() self.stubs = stubout.StubOutForTesting()
stub_out_http_backend(self.stubs) stub_out_http_backend(self.stubs)
Store.CHUNKSIZE = 2 Store.CHUNKSIZE = 2
self.store = Store({}) self.store = Store({})
self.conf = utils.TestConfigOpts({
'default_store': 'http',
'known_stores': "glance.store.http.Store",
})
configure_registry_client(self.conf) configure_registry_client(self.conf)
def test_http_get(self): def test_http_get(self):

View File

@ -254,12 +254,11 @@ class TestImageCacheXattr(test_utils.BaseTestCase,
self.inited = True self.inited = True
self.disabled = False self.disabled = False
self.conf = test_utils.TestConfigOpts({ self.config(image_cache_dir=self.cache_dir,
'image_cache_dir': self.cache_dir, image_cache_driver='xattr',
'image_cache_driver': 'xattr', image_cache_max_size=1024 * 5,
'image_cache_max_size': 1024 * 5, registry_host='0.0.0.0',
'registry_host': '0.0.0.0', registry_port=9191)
'registry_port': 9191})
self.cache = image_cache.ImageCache(self.conf) self.cache = image_cache.ImageCache(self.conf)
if not xattr_writes_supported(self.cache_dir): if not xattr_writes_supported(self.cache_dir):
@ -302,12 +301,11 @@ class TestImageCacheSqlite(test_utils.BaseTestCase,
self.disabled = False self.disabled = False
self.cache_dir = os.path.join("/", "tmp", "test.cache.%d" % self.cache_dir = os.path.join("/", "tmp", "test.cache.%d" %
random.randint(0, 1000000)) random.randint(0, 1000000))
self.conf = test_utils.TestConfigOpts({ self.config(image_cache_dir=self.cache_dir,
'image_cache_dir': self.cache_dir, image_cache_driver='sqlite',
'image_cache_driver': 'sqlite', image_cache_max_size=1024 * 5,
'image_cache_max_size': 1024 * 5, registry_host='0.0.0.0',
'registry_host': '0.0.0.0', registry_port=9191)
'registry_port': 9191})
self.cache = image_cache.ImageCache(self.conf) self.cache = image_cache.ImageCache(self.conf)
def tearDown(self): def tearDown(self):

View File

@ -146,10 +146,8 @@ class TestMigrations(utils.BaseTestCase):
that there are no errors in the version scripts for each engine that there are no errors in the version scripts for each engine
""" """
for key, engine in self.engines.items(): for key, engine in self.engines.items():
conf = utils.TestConfigOpts({ self.config(sql_connection=TestMigrations.TEST_DATABASES[key])
'sql_connection': TestMigrations.TEST_DATABASES[key]}) self._walk_versions(self.conf)
conf.register_opt(cfg.StrOpt('sql_connection'))
self._walk_versions(conf)
def test_version_control_existing_db(self): def test_version_control_existing_db(self):
""" """
@ -158,11 +156,9 @@ class TestMigrations(utils.BaseTestCase):
without errors. without errors.
""" """
for key, engine in self.engines.items(): for key, engine in self.engines.items():
conf = utils.TestConfigOpts({ self.config(sql_connection=TestMigrations.TEST_DATABASES[key])
'sql_connection': TestMigrations.TEST_DATABASES[key]})
conf.register_opt(cfg.StrOpt('sql_connection'))
self._create_unversioned_001_db(engine) self._create_unversioned_001_db(engine)
self._walk_versions(conf, initial_version=1) self._walk_versions(self.conf, initial_version=1)
def _create_unversioned_001_db(self, engine): def _create_unversioned_001_db(self, engine):
# Create the initial version of the images table # Create the initial version of the images table
@ -221,10 +217,8 @@ class TestMigrations(utils.BaseTestCase):
the image_properties table back into the base image table. the image_properties table back into the base image table.
""" """
for key, engine in self.engines.items(): for key, engine in self.engines.items():
conf = utils.TestConfigOpts({ self.config(sql_connection=TestMigrations.TEST_DATABASES[key])
'sql_connection': TestMigrations.TEST_DATABASES[key]}) self._no_data_loss_2_to_3_to_2(engine, self.conf)
conf.register_opt(cfg.StrOpt('sql_connection'))
self._no_data_loss_2_to_3_to_2(engine, conf)
def _no_data_loss_2_to_3_to_2(self, engine, conf): def _no_data_loss_2_to_3_to_2(self, engine, conf):
migration_api.version_control(conf, version=0) migration_api.version_control(conf, version=0)
@ -320,10 +314,8 @@ class TestMigrations(utils.BaseTestCase):
def test_no_data_loss_14_to_15(self): def test_no_data_loss_14_to_15(self):
for key, engine in self.engines.items(): for key, engine in self.engines.items():
conf = utils.TestConfigOpts({ self.config(sql_connection=TestMigrations.TEST_DATABASES[key])
'sql_connection': TestMigrations.TEST_DATABASES[key]}) self._check_no_data_loss_14_to_15(engine, self.conf)
conf.register_opt(cfg.StrOpt('sql_connection'))
self._check_no_data_loss_14_to_15(engine, conf)
def _check_no_data_loss_14_to_15(self, engine, conf): def _check_no_data_loss_14_to_15(self, engine, conf):
""" """

View File

@ -38,10 +38,10 @@ class TestInvalidNotifier(utils.BaseTestCase):
"""Test that notifications are generated appropriately""" """Test that notifications are generated appropriately"""
def test_cannot_create(self): def test_cannot_create(self):
conf = utils.TestConfigOpts({"notifier_strategy": "invalid_notifier"}) self.config(notifier_strategy="invalid_notifier")
self.assertRaises(exception.InvalidNotifierStrategy, self.assertRaises(exception.InvalidNotifierStrategy,
notifier.Notifier, notifier.Notifier,
conf) self.conf)
class TestLoggingNotifier(utils.BaseTestCase): class TestLoggingNotifier(utils.BaseTestCase):
@ -49,10 +49,10 @@ class TestLoggingNotifier(utils.BaseTestCase):
def setUp(self): def setUp(self):
super(TestLoggingNotifier, self).setUp() super(TestLoggingNotifier, self).setUp()
conf = utils.TestConfigOpts({"notifier_strategy": "logging"}) self.config(notifier_strategy="logging")
self.called = False self.called = False
self.logger = logging.getLogger("glance.notifier.logging_notifier") self.logger = logging.getLogger("glance.notifier.logging_notifier")
self.notifier = notifier.Notifier(conf) self.notifier = notifier.Notifier(self.conf)
def _called(self, msg): def _called(self, msg):
self.called = msg self.called = msg
@ -81,8 +81,8 @@ class TestNoopNotifier(utils.BaseTestCase):
def setUp(self): def setUp(self):
super(TestNoopNotifier, self).setUp() super(TestNoopNotifier, self).setUp()
conf = utils.TestConfigOpts({"notifier_strategy": "noop"}) self.config(notifier_strategy="noop")
self.notifier = notifier.Notifier(conf) self.notifier = notifier.Notifier(self.conf)
def test_warn(self): def test_warn(self):
self.notifier.warn("test_event", "test_message") self.notifier.warn("test_event", "test_message")
@ -110,10 +110,9 @@ class TestRabbitNotifier(utils.BaseTestCase):
self.notify_kombu.RabbitStrategy._send_message = self._send_message self.notify_kombu.RabbitStrategy._send_message = self._send_message
self.notify_kombu.RabbitStrategy._connect = _fake_connect self.notify_kombu.RabbitStrategy._connect = _fake_connect
self.called = False self.called = False
self.conf = utils.TestConfigOpts({"notifier_strategy": "rabbit", self.config(notifier_strategy="rabbit",
"rabbit_retry_backoff": 0, rabbit_retry_backoff=0,
"rabbit_notification_topic": rabbit_notification_topic="fake_topic")
"fake_topic"})
self.notifier = notifier.Notifier(self.conf) self.notifier = notifier.Notifier(self.conf)
def _send_message(self, message, routing_key): def _send_message(self, message, routing_key):
@ -338,8 +337,8 @@ class TestQpidNotifier(utils.BaseTestCase):
self.mocker.ReplayAll() self.mocker.ReplayAll()
conf = utils.TestConfigOpts({"notifier_strategy": "qpid"}) self.config(notifier_strategy="qpid")
notifier = self.notify_qpid.QpidStrategy(conf) notifier = self.notify_qpid.QpidStrategy(self.conf)
if priority == 'info': if priority == 'info':
notifier.info(test_msg) notifier.info(test_msg)
elif priority == 'warn': elif priority == 'warn':
@ -382,10 +381,9 @@ class TestRabbitContentType(utils.BaseTestCase):
self.stubs.Set(glance.notifier.notify_kombu.RabbitStrategy, '_connect', self.stubs.Set(glance.notifier.notify_kombu.RabbitStrategy, '_connect',
_fake_connect) _fake_connect)
self.called = False self.called = False
self.conf = utils.TestConfigOpts({"notifier_strategy": "rabbit", self.config(notifier_strategy="rabbit",
"rabbit_retry_backoff": 0, rabbit_retry_backoff=0,
"rabbit_notification_topic": rabbit_notification_topic="fake_topic")
"fake_topic"})
self.notifier = notifier.Notifier(self.conf) self.notifier = notifier.Notifier(self.conf)
def _fake_exchange(self): def _fake_exchange(self):

View File

@ -25,6 +25,7 @@ import boto.s3.connection
from glance.common import exception from glance.common import exception
from glance.common import utils from glance.common import utils
from glance.openstack.common import cfg
from glance.store import UnsupportedBackend from glance.store import UnsupportedBackend
from glance.store.location import get_location_from_uri from glance.store.location import get_location_from_uri
from glance.store.s3 import Store, get_s3_location from glance.store.s3 import Store, get_s3_location
@ -161,10 +162,11 @@ class TestStore(base.StoreClearingUnitTest):
def setUp(self): def setUp(self):
"""Establish a clean test environment""" """Establish a clean test environment"""
self.config(**S3_CONF)
super(TestStore, self).setUp() super(TestStore, self).setUp()
self.stubs = stubout.StubOutForTesting() self.stubs = stubout.StubOutForTesting()
stub_out_s3(self.stubs) stub_out_s3(self.stubs)
self.store = Store(test_utils.TestConfigOpts(S3_CONF)) self.store = Store(self.conf)
def tearDown(self): def tearDown(self):
"""Clear the test environment""" """Clear the test environment"""
@ -261,7 +263,8 @@ class TestStore(base.StoreClearingUnitTest):
expected_image_id) expected_image_id)
image_s3 = StringIO.StringIO(expected_s3_contents) image_s3 = StringIO.StringIO(expected_s3_contents)
self.store = Store(test_utils.TestConfigOpts(new_conf)) self.config(**new_conf)
self.store = Store(self.conf)
location, size, checksum = self.store.add(expected_image_id, location, size, checksum = self.store.add(expected_image_id,
image_s3, image_s3,
expected_s3_size) expected_s3_size)
@ -290,10 +293,11 @@ class TestStore(base.StoreClearingUnitTest):
def _option_required(self, key): def _option_required(self, key):
conf = S3_CONF.copy() conf = S3_CONF.copy()
del conf[key] conf[key] = None
try: try:
self.store = Store(test_utils.TestConfigOpts(conf)) self.config(**conf)
self.store = Store(self.conf)
return self.store.add == self.store.add_disabled return self.store.add == self.store.add_disabled
except: except:
return False return False

View File

@ -51,7 +51,6 @@ class TestSchemaAPI(test_utils.BaseTestCase):
def setUp(self): def setUp(self):
super(TestSchemaAPI, self).setUp() super(TestSchemaAPI, self).setUp()
self.conf = test_utils.TestConfigOpts()
self.schema_api = glance.schema.API(self.conf, FAKE_BASE_PROPERTIES) self.schema_api = glance.schema.API(self.conf, FAKE_BASE_PROPERTIES)
def test_get_schema(self): def test_get_schema(self):
@ -180,7 +179,7 @@ class TestSchemaAPI(test_utils.BaseTestCase):
self.assertEqual(output, expected) self.assertEqual(output, expected)
def test_get_image_schema_with_additional_properties_disabled(self): def test_get_image_schema_with_additional_properties_disabled(self):
self.conf.allow_additional_image_properties = False self.config(allow_additional_image_properties=False)
output = self.schema_api.get_schema('image') output = self.schema_api.get_schema('image')
expected = { expected = {
'name': 'image', 'name': 'image',
@ -201,7 +200,7 @@ class TestSchemaAPI(test_utils.BaseTestCase):
self.assertEqual(output, expected) self.assertEqual(output, expected)
def test_get_image_schema_with_additional_properties_enabled(self): def test_get_image_schema_with_additional_properties_enabled(self):
self.conf.allow_additional_image_properties = True self.config(allow_additional_image_properties=True)
output = self.schema_api.get_schema('image') output = self.schema_api.get_schema('image')
expected = { expected = {
'name': 'image', 'name': 'image',
@ -222,7 +221,7 @@ class TestSchemaAPI(test_utils.BaseTestCase):
self.assertEqual(output, expected) self.assertEqual(output, expected)
def test_get_other_schema_with_additional_image_properties_enabled(self): def test_get_other_schema_with_additional_image_properties_enabled(self):
self.conf.allow_additional_image_properties = True self.config(allow_additional_image_properties=False)
output = self.schema_api.get_schema('fake1') output = self.schema_api.get_schema('fake1')
expected = { expected = {
'name': 'fake1', 'name': 'fake1',

View File

@ -29,11 +29,9 @@ from glance.tests import utils
class TestStoreLocation(base.StoreClearingUnitTest): class TestStoreLocation(base.StoreClearingUnitTest):
def setUp(self): def setUp(self):
self.config(known_stores=utils.get_default_stores(),
default_store='file')
super(TestStoreLocation, self).setUp() super(TestStoreLocation, self).setUp()
self.conf = utils.TestConfigOpts({
'known_stores': utils.get_default_stores(),
'default_store': 'file',
})
def test_get_location_from_uri_back_to_uri(self): def test_get_location_from_uri_back_to_uri(self):
""" """

View File

@ -44,7 +44,7 @@ MAX_SWIFT_OBJECT_SIZE = FIVE_GB
SWIFT_PUT_OBJECT_CALLS = 0 SWIFT_PUT_OBJECT_CALLS = 0
SWIFT_CONF = {'verbose': True, SWIFT_CONF = {'verbose': True,
'debug': True, 'debug': True,
'known_stores': "glance.store.swift.Store", 'known_stores': ['glance.store.swift.Store'],
'default_store': 'swift', 'default_store': 'swift',
'swift_store_user': 'user', 'swift_store_user': 'user',
'swift_store_key': 'key', 'swift_store_key': 'key',
@ -55,7 +55,7 @@ SWIFT_CONF = {'verbose': True,
# We stub out as little as possible to ensure that the code paths # We stub out as little as possible to ensure that the code paths
# between glance.store.swift and swift.common.client are tested # between glance.store.swift and swift.common.client are tested
# thoroughly # thoroughly
def stub_out_swift_common_client(stubs, conf): def stub_out_swift_common_client(stubs, swift_store_auth_version):
fixture_containers = ['glance'] fixture_containers = ['glance']
fixture_headers = {'glance/%s' % FAKE_UUID: fixture_headers = {'glance/%s' % FAKE_UUID:
@ -165,7 +165,7 @@ def stub_out_swift_common_client(stubs, conf):
if 'http' in url and '://' not in url: if 'http' in url and '://' not in url:
raise ValueError('Invalid url %s' % url) raise ValueError('Invalid url %s' % url)
# Check the auth version against the configured value # Check the auth version against the configured value
if conf['swift_store_auth_version'] != auth_version: if swift_store_auth_version != auth_version:
msg = 'AUTHENTICATION failed (version mismatch)' msg = 'AUTHENTICATION failed (version mismatch)'
raise swift.common.client.ClientException(msg) raise swift.common.client.ClientException(msg)
return None, None return None, None
@ -192,7 +192,7 @@ class SwiftTests(object):
@property @property
def swift_store_user(self): def swift_store_user(self):
return urllib.quote(self.conf['swift_store_user']) return urllib.quote(self.conf.swift_store_user)
def test_get_size(self): def test_get_size(self):
""" """
@ -314,14 +314,14 @@ class SwiftTests(object):
expected_swift_contents = "*" * expected_swift_size expected_swift_contents = "*" * expected_swift_size
expected_checksum = \ expected_checksum = \
hashlib.md5(expected_swift_contents).hexdigest() hashlib.md5(expected_swift_contents).hexdigest()
self.conf['swift_store_auth_address'] = variation
image_swift = StringIO.StringIO(expected_swift_contents) image_swift = StringIO.StringIO(expected_swift_contents)
global SWIFT_PUT_OBJECT_CALLS global SWIFT_PUT_OBJECT_CALLS
SWIFT_PUT_OBJECT_CALLS = 0 SWIFT_PUT_OBJECT_CALLS = 0
self.store = Store(test_utils.TestConfigOpts(self.conf)) self.config(swift_store_auth_address=variation)
self.store = Store(self.conf)
location, size, checksum = self.store.add(image_id, image_swift, location, size, checksum = self.store.add(image_id, image_swift,
expected_swift_size) expected_swift_size)
@ -343,10 +343,11 @@ class SwiftTests(object):
Tests that adding an image with a non-existing container Tests that adding an image with a non-existing container
raises an appropriate exception raises an appropriate exception
""" """
self.conf['swift_store_create_container_on_put'] = 'False' self.config(swift_store_create_container_on_put=False,
self.conf['swift_store_container'] = 'noexist' swift_store_container='noexist')
self.store = Store(self.conf)
image_swift = StringIO.StringIO("nevergonnamakeit") image_swift = StringIO.StringIO("nevergonnamakeit")
self.store = Store(test_utils.TestConfigOpts(self.conf))
global SWIFT_PUT_OBJECT_CALLS global SWIFT_PUT_OBJECT_CALLS
SWIFT_PUT_OBJECT_CALLS = 0 SWIFT_PUT_OBJECT_CALLS = 0
@ -369,8 +370,6 @@ class SwiftTests(object):
Tests that adding an image with a non-existing container Tests that adding an image with a non-existing container
creates the container automatically if flag is set creates the container automatically if flag is set
""" """
self.conf['swift_store_create_container_on_put'] = 'True'
self.conf['swift_store_container'] = 'noexist'
expected_swift_size = FIVE_KB expected_swift_size = FIVE_KB
expected_swift_contents = "*" * expected_swift_size expected_swift_contents = "*" * expected_swift_size
expected_checksum = hashlib.md5(expected_swift_contents).hexdigest() expected_checksum = hashlib.md5(expected_swift_contents).hexdigest()
@ -383,7 +382,9 @@ class SwiftTests(object):
global SWIFT_PUT_OBJECT_CALLS global SWIFT_PUT_OBJECT_CALLS
SWIFT_PUT_OBJECT_CALLS = 0 SWIFT_PUT_OBJECT_CALLS = 0
self.store = Store(test_utils.TestConfigOpts(self.conf)) self.config(swift_store_create_container_on_put=True,
swift_store_container='noexist')
self.store = Store(self.conf)
location, size, checksum = self.store.add(expected_image_id, location, size, checksum = self.store.add(expected_image_id,
image_swift, image_swift,
expected_swift_size) expected_swift_size)
@ -408,7 +409,6 @@ class SwiftTests(object):
and then verify that there have been a number of calls to and then verify that there have been a number of calls to
put_object()... put_object()...
""" """
self.conf['swift_store_container'] = 'glance'
expected_swift_size = FIVE_KB expected_swift_size = FIVE_KB
expected_swift_contents = "*" * expected_swift_size expected_swift_contents = "*" * expected_swift_size
expected_checksum = hashlib.md5(expected_swift_contents).hexdigest() expected_checksum = hashlib.md5(expected_swift_contents).hexdigest()
@ -421,7 +421,8 @@ class SwiftTests(object):
global SWIFT_PUT_OBJECT_CALLS global SWIFT_PUT_OBJECT_CALLS
SWIFT_PUT_OBJECT_CALLS = 0 SWIFT_PUT_OBJECT_CALLS = 0
self.store = Store(test_utils.TestConfigOpts(self.conf)) self.config(swift_store_container='glance')
self.store = Store(self.conf)
orig_max_size = self.store.large_object_size orig_max_size = self.store.large_object_size
orig_temp_size = self.store.large_object_chunk_size orig_temp_size = self.store.large_object_chunk_size
try: try:
@ -460,8 +461,6 @@ class SwiftTests(object):
Bug lp:891738 Bug lp:891738
""" """
self.conf['swift_store_container'] = 'glance'
# Set up a 'large' image of 5KB # Set up a 'large' image of 5KB
expected_swift_size = FIVE_KB expected_swift_size = FIVE_KB
expected_swift_contents = "*" * expected_swift_size expected_swift_contents = "*" * expected_swift_size
@ -477,7 +476,8 @@ class SwiftTests(object):
# Temporarily set Swift MAX_SWIFT_OBJECT_SIZE to 1KB and add our image, # Temporarily set Swift MAX_SWIFT_OBJECT_SIZE to 1KB and add our image,
# explicitly setting the image_length to 0 # explicitly setting the image_length to 0
self.store = Store(test_utils.TestConfigOpts(self.conf)) self.config(swift_store_container='glance')
self.store = Store(self.conf)
orig_max_size = self.store.large_object_size orig_max_size = self.store.large_object_size
orig_temp_size = self.store.large_object_chunk_size orig_temp_size = self.store.large_object_chunk_size
global MAX_SWIFT_OBJECT_SIZE global MAX_SWIFT_OBJECT_SIZE
@ -521,10 +521,12 @@ class SwiftTests(object):
FAKE_UUID, image_swift, 0) FAKE_UUID, image_swift, 0)
def _option_required(self, key): def _option_required(self, key):
del self.conf[key] conf = self.getConfig()
conf[key] = None
try: try:
self.store = Store(test_utils.TestConfigOpts(self.conf)) self.config(**conf)
self.store = Store(self.conf)
return self.store.add == self.store.add_disabled return self.store.add == self.store.add_disabled
except: except:
return False return False
@ -579,11 +581,13 @@ class TestStoreAuthV1(base.StoreClearingUnitTest, SwiftTests):
def setUp(self): def setUp(self):
"""Establish a clean test environment""" """Establish a clean test environment"""
conf = self.getConfig()
self.config(**conf)
super(TestStoreAuthV1, self).setUp() super(TestStoreAuthV1, self).setUp()
self.conf = self.getConfig()
self.stubs = stubout.StubOutForTesting() self.stubs = stubout.StubOutForTesting()
stub_out_swift_common_client(self.stubs, self.conf) stub_out_swift_common_client(self.stubs,
self.store = Store(test_utils.TestConfigOpts(self.conf)) conf['swift_store_auth_version'])
self.store = Store(self.conf)
def tearDown(self): def tearDown(self):
"""Clear the test environment""" """Clear the test environment"""

View File

@ -31,9 +31,8 @@ class VersionsTest(base.IsolatedUnitTest):
def test_get_version_list(self): def test_get_version_list(self):
req = webob.Request.blank('/', base_url='http://0.0.0.0:9292/') req = webob.Request.blank('/', base_url='http://0.0.0.0:9292/')
req.accept = 'application/json' req.accept = 'application/json'
config_opts = {'bind_host': '0.0.0.0', 'bind_port': 9292} self.config(bind_host='0.0.0.0', bind_port=9292)
conf = utils.TestConfigOpts(config_opts) res = versions.Controller(self.conf).index(req)
res = versions.Controller(conf).index(req)
self.assertEqual(res.status_int, 300) self.assertEqual(res.status_int, 300)
self.assertEqual(res.content_type, 'application/json') self.assertEqual(res.content_type, 'application/json')
results = json.loads(res.body)['versions'] results = json.loads(res.body)['versions']

View File

@ -55,16 +55,13 @@ class TestRegistryDb(test_utils.BaseTestCase):
API controller results in a) an Exception being thrown and b) API controller results in a) an Exception being thrown and b)
a message being logged to the registry log file... a message being logged to the registry log file...
""" """
bad_conf = test_utils.TestConfigOpts({ self.config(verbose=True, debug=True, sql_connection='baddriver:///')
'verbose': True,
'debug': True,
'sql_connection': 'baddriver:///'
})
# We set this to None to trigger a reconfigure, otherwise # We set this to None to trigger a reconfigure, otherwise
# other modules may have already correctly configured the DB # other modules may have already correctly configured the DB
db_api._ENGINE = None db_api._ENGINE = None
self.assertRaises((ImportError, exc.ArgumentError), self.assertRaises((ImportError, exc.ArgumentError),
db_api.configure_db, bad_conf) db_api.configure_db, self.conf)
exc_raised = False exc_raised = False
self.log_written = False self.log_written = False
@ -74,7 +71,7 @@ class TestRegistryDb(test_utils.BaseTestCase):
self.stubs.Set(db_api.logger, 'error', fake_log_error) self.stubs.Set(db_api.logger, 'error', fake_log_error)
try: try:
api_obj = rserver.API(bad_conf) api_obj = rserver.API(self.conf)
except exc.ArgumentError: except exc.ArgumentError:
exc_raised = True exc_raised = True
except ImportError: except ImportError:

View File

@ -111,8 +111,7 @@ class TestImageAccessDeserializer(test_utils.BaseTestCase):
def setUp(self): def setUp(self):
super(TestImageAccessDeserializer, self).setUp() super(TestImageAccessDeserializer, self).setUp()
conf = test_utils.TestConfigOpts() schema_api = glance.schema.API(self.conf)
schema_api = glance.schema.API(conf)
self.deserializer = image_access.RequestDeserializer({}, schema_api) self.deserializer = image_access.RequestDeserializer({}, schema_api)
def test_create(self): def test_create(self):
@ -136,8 +135,7 @@ class TestImageAccessDeserializerWithExtendedSchema(test_utils.BaseTestCase):
def setUp(self): def setUp(self):
super(TestImageAccessDeserializerWithExtendedSchema, self).setUp() super(TestImageAccessDeserializerWithExtendedSchema, self).setUp()
conf = test_utils.TestConfigOpts() schema_api = glance.schema.API(self.conf)
schema_api = glance.schema.API(conf)
props = { props = {
'color': { 'color': {
'type': 'string', 'type': 'string',

View File

@ -28,11 +28,10 @@ class TestImagesController(base.StoreClearingUnitTest):
def setUp(self): def setUp(self):
super(TestImagesController, self).setUp() super(TestImagesController, self).setUp()
conf = glance.tests.utils.TestConfigOpts({ self.config(verbose=True, debug=True)
'verbose': True,
'debug': True, controller_class = glance.api.v2.image_data.ImageDataController
}) self.controller = controller_class(self.conf,
self.controller = glance.api.v2.image_data.ImageDataController(conf,
db_api=unit_test_utils.FakeDB(), db_api=unit_test_utils.FakeDB(),
store_api=unit_test_utils.FakeStoreAPI()) store_api=unit_test_utils.FakeStoreAPI())

View File

@ -140,7 +140,6 @@ class TestImagesDeserializer(test_utils.BaseTestCase):
def setUp(self): def setUp(self):
super(TestImagesDeserializer, self).setUp() super(TestImagesDeserializer, self).setUp()
self.conf = test_utils.TestConfigOpts()
schema_api = glance.schema.API(self.conf) schema_api = glance.schema.API(self.conf)
self.deserializer = glance.api.v2.images.RequestDeserializer( self.deserializer = glance.api.v2.images.RequestDeserializer(
{}, schema_api) {}, schema_api)
@ -215,8 +214,7 @@ class TestImagesDeserializerWithExtendedSchema(test_utils.BaseTestCase):
def setUp(self): def setUp(self):
super(TestImagesDeserializerWithExtendedSchema, self).setUp() super(TestImagesDeserializerWithExtendedSchema, self).setUp()
conf = test_utils.TestConfigOpts() schema_api = glance.schema.API(self.conf)
schema_api = glance.schema.API(conf)
props = { props = {
'pants': { 'pants': {
'type': 'string', 'type': 'string',
@ -269,8 +267,7 @@ class TestImagesDeserializerWithAdditionalProperties(test_utils.BaseTestCase):
def setUp(self): def setUp(self):
super(TestImagesDeserializerWithAdditionalProperties, self).setUp() super(TestImagesDeserializerWithAdditionalProperties, self).setUp()
self.conf = test_utils.TestConfigOpts() self.config(allow_additional_image_properties=True)
self.conf.allow_additional_image_properties = True
schema_api = glance.schema.API(self.conf) schema_api = glance.schema.API(self.conf)
self.deserializer = glance.api.v2.images.RequestDeserializer( self.deserializer = glance.api.v2.images.RequestDeserializer(
{}, schema_api) {}, schema_api)
@ -283,7 +280,7 @@ class TestImagesDeserializerWithAdditionalProperties(test_utils.BaseTestCase):
self.assertEqual(expected, output) self.assertEqual(expected, output)
def test_create_with_additional_properties_disallowed(self): def test_create_with_additional_properties_disallowed(self):
self.conf.allow_additional_image_properties = False self.config(allow_additional_image_properties=False)
request = unit_test_utils.FakeRequest() request = unit_test_utils.FakeRequest()
request.body = json.dumps({'foo': 'bar'}) request.body = json.dumps({'foo': 'bar'})
self.assertRaises(exception.InvalidObject, self.assertRaises(exception.InvalidObject,
@ -309,7 +306,7 @@ class TestImagesDeserializerWithAdditionalProperties(test_utils.BaseTestCase):
self.assertEqual(expected, output) self.assertEqual(expected, output)
def test_update_with_additional_properties_disallowed(self): def test_update_with_additional_properties_disallowed(self):
self.conf.allow_additional_image_properties = False self.config(allow_additional_image_properties=False)
request = unit_test_utils.FakeRequest() request = unit_test_utils.FakeRequest()
request.body = json.dumps({'foo': 'bar'}) request.body = json.dumps({'foo': 'bar'})
self.assertRaises(exception.InvalidObject, self.assertRaises(exception.InvalidObject,
@ -320,8 +317,7 @@ class TestImagesSerializer(test_utils.BaseTestCase):
def setUp(self): def setUp(self):
super(TestImagesSerializer, self).setUp() super(TestImagesSerializer, self).setUp()
conf = test_utils.TestConfigOpts() schema_api = glance.schema.API(self.conf)
schema_api = glance.schema.API(conf)
self.serializer = glance.api.v2.images.ResponseSerializer(schema_api) self.serializer = glance.api.v2.images.ResponseSerializer(schema_api)
def test_index(self): def test_index(self):
@ -497,8 +493,7 @@ class TestImagesSerializerWithExtendedSchema(test_utils.BaseTestCase):
def setUp(self): def setUp(self):
super(TestImagesSerializerWithExtendedSchema, self).setUp() super(TestImagesSerializerWithExtendedSchema, self).setUp()
self.conf = test_utils.TestConfigOpts() self.config(allow_additional_image_properties=False)
self.conf.allow_additional_image_properties = False
self.schema_api = glance.schema.API(self.conf) self.schema_api = glance.schema.API(self.conf)
props = { props = {
'color': { 'color': {
@ -580,8 +575,7 @@ class TestImagesSerializerWithAdditionalProperties(test_utils.BaseTestCase):
def setUp(self): def setUp(self):
super(TestImagesSerializerWithAdditionalProperties, self).setUp() super(TestImagesSerializerWithAdditionalProperties, self).setUp()
self.conf = test_utils.TestConfigOpts() self.config(allow_additional_image_properties=True)
self.conf.allow_additional_image_properties = True
self.schema_api = glance.schema.API(self.conf) self.schema_api = glance.schema.API(self.conf)
self.fixture = { self.fixture = {
'id': unit_test_utils.UUID2, 'id': unit_test_utils.UUID2,
@ -656,7 +650,7 @@ class TestImagesSerializerWithAdditionalProperties(test_utils.BaseTestCase):
self.assertEqual(expected, json.loads(response.body)) self.assertEqual(expected, json.loads(response.body))
def test_show_with_additional_properties_disabled(self): def test_show_with_additional_properties_disabled(self):
self.conf.allow_additional_image_properties = False self.config(allow_additional_image_properties=False)
serializer = glance.api.v2.images.ResponseSerializer(self.schema_api) serializer = glance.api.v2.images.ResponseSerializer(self.schema_api)
expected = { expected = {
'image': { 'image': {

View File

@ -23,8 +23,7 @@ class TestSchemasController(test_utils.BaseTestCase):
def setUp(self): def setUp(self):
super(TestSchemasController, self).setUp() super(TestSchemasController, self).setUp()
conf = test_utils.TestConfigOpts() self.schema_api = glance.schema.API(self.conf)
self.schema_api = glance.schema.API(conf)
self.controller = schemas.Controller({}, self.schema_api) self.controller = schemas.Controller({}, self.schema_api)
def test_index(self): def test_index(self):

View File

@ -23,7 +23,6 @@ import os
import random import random
import socket import socket
import subprocess import subprocess
import tempfile
import unittest import unittest
import nose.plugins.skip import nose.plugins.skip
@ -31,8 +30,11 @@ import nose.plugins.skip
from glance.common import config from glance.common import config
from glance.common import utils from glance.common import utils
from glance.common import wsgi from glance.common import wsgi
from glance.openstack.common import cfg
from glance import store from glance import store
CONF = cfg.CONF
def get_isolated_test_env(): def get_isolated_test_env():
""" """
@ -50,79 +52,28 @@ class BaseTestCase(unittest.TestCase):
def setUp(self): def setUp(self):
super(BaseTestCase, self).setUp() super(BaseTestCase, self).setUp()
self.conf = CONF
def tearDown(self): def tearDown(self):
super(BaseTestCase, self).tearDown() super(BaseTestCase, self).tearDown()
CONF.reset()
def config(self, **kw):
"""
Override some configuration values.
class TestConfigOpts(config.GlanceConfigOpts): The keyword arguments are the names of configuration options to
""" override and their values.
Support easily controllable config for unit tests, avoiding the
need to manipulate config files directly.
Configuration values are provided as a dictionary of key-value pairs, If a group argument is supplied, the overrides are applied to
in the simplest case feeding into the DEFAULT group only. the specified configuration option group.
Non-default groups may also populated via nested dictionaries, e.g. All overrides are automatically cleared at the end of the current
test by the tearDown() method.
{'snafu': {'foo': 'bar', 'bells': 'whistles'}} """
group = kw.pop('group', None)
equates to config of form: for k, v in kw.iteritems():
CONF.set_override(k, v, group)
[snafu]
foo = bar
bells = whistles
The config so provided is dumped to a temporary file, with its path
exposed via the temp_file property.
:param test_values: dictionary of key-value pairs for the
DEFAULT group
:param groups: nested dictionary of key-value pairs for
non-default groups
:param clean: flag to trigger clean up of temporary directory
"""
def __init__(self, test_values={}, groups={}, clean=True):
super(TestConfigOpts, self).__init__()
self._test_values = test_values
self._test_groups = groups
self.clean = clean
self.temp_file = os.path.join(tempfile.mkdtemp(), 'testcfg.conf')
self()
store.create_stores(self)
def __call__(self):
self._write_tmp_config_file()
try:
super(TestConfigOpts, self).__call__(['--config-file',
self.temp_file])
finally:
if self.clean:
os.remove(self.temp_file)
os.rmdir(os.path.dirname(self.temp_file))
def _write_tmp_config_file(self):
contents = '[DEFAULT]\n'
for key, value in self._test_values.items():
contents += '%s = %s\n' % (key, value)
for group, settings in self._test_groups.items():
contents += '[%s]\n' % group
for key, value in settings.items():
contents += '%s = %s\n' % (key, value)
try:
with open(self.temp_file, 'wb') as f:
f.write(contents)
f.flush()
except Exception, e:
if self.clean:
os.remove(self.temp_file)
os.rmdir(os.path.dirname(self.temp_file))
raise e
class skip_test(object): class skip_test(object):
@ -328,15 +279,13 @@ def find_executable(cmdname):
def get_default_stores(): def get_default_stores():
# Default test stores # Default test stores
known_stores = [ return [
"glance.store.filesystem.Store", "glance.store.filesystem.Store",
"glance.store.http.Store", "glance.store.http.Store",
"glance.store.rbd.Store", "glance.store.rbd.Store",
"glance.store.s3.Store", "glance.store.s3.Store",
"glance.store.swift.Store", "glance.store.swift.Store",
] ]
# Made in a format that the config can read
return ", ".join(known_stores)
def get_unused_port(): def get_unused_port():

View File

@ -6,7 +6,7 @@ import sys
import keystoneclient.v2_0.client import keystoneclient.v2_0.client
import glance.common.context import glance.common.context
import glance.openstack.common.cfg from glance.openstack.common import cfg
import glance.registry.context import glance.registry.context
import glance.db.api as db_api import glance.db.api as db_api
@ -57,23 +57,21 @@ def update_image_owners(image_owner_map, db, context):
if __name__ == "__main__": if __name__ == "__main__":
config = glance.openstack.common.cfg.CommonConfigOpts(project='glance', config = cfg.CONF
prog='glance-registry')
extra_cli_opts = [ extra_cli_opts = [
glance.openstack.common.cfg.BoolOpt('dry-run', cfg.BoolOpt('dry-run',
help='Print output but do not make db changes.'), help='Print output but do not make db changes.'),
glance.openstack.common.cfg.StrOpt('keystone-auth-uri', cfg.StrOpt('keystone-auth-uri',
help='Authentication endpoint'), help='Authentication endpoint'),
glance.openstack.common.cfg.StrOpt('keystone-admin-tenant-name', cfg.StrOpt('keystone-admin-tenant-name',
help='Administrative user\'s tenant name'), help='Administrative user\'s tenant name'),
glance.openstack.common.cfg.StrOpt('keystone-admin-user', cfg.StrOpt('keystone-admin-user',
help='Administrative user\'s id'), help='Administrative user\'s id'),
glance.openstack.common.cfg.StrOpt('keystone-admin-password', cfg.StrOpt('keystone-admin-password',
help='Administrative user\'s password'), help='Administrative user\'s password'),
] ]
config.register_cli_opts(extra_cli_opts) config.register_cli_opts(extra_cli_opts)
config() config(project='glance', prog='glance-registry')
config.register_opts(glance.common.context.ContextMiddleware.opts)
db_api.configure_db(config) db_api.configure_db(config)