Convert glance to use the new cfg module
The changes here are substantial and widespread, but in summary: - We use cfg to parse the CLI and config files, rather than optparse and PasteDeploy - A schema is defined for all configuration options close to the code which uses the option - 2 ConfigOpts sub-classes are added to config.py basically just defining how to find config files; this means we can now use e.g. glance.conf for base config values which glance-api.conf can override - load_paste_app() is changed to load the paste app from the last config file in the stack and pass the app the ConfigOpts instance - The generic app and filter factories in wsgi.py are modified to pass a ConfigOpts instance to the apps and filters - A ConfigOpts subclass is added for the unit tests which writes out config values to a temporary config file and uses cfg to parse that I've tried to keep the switch as unobtrusive as possible leaving further cleanups for later e.g. - Moving PasteDeploy config out of the config files - I think it would be good to aim for having users modify the PasteDeploy config files only in fairly rare circumstances. To achieve this, we might define a number of common pipelines in the PasteDeploy config and allow the user to choose between those pipelines in the glance config. - We should add help strings to all the opts, even just for the sake of documenting them - We should move a bunch of the options into groups - e.g. all the rabbit options - We no longer rely on config files for default values, so the default config files could contain nothing but comments - i.e. explaining each option and showing what the default for it is - making it obvious where a user has explicitly set a value There are a couple of behavioural changes which I don't think are signifcant but are worth mentioning: - We used to support passing a config file as a positional argument but don't anymore; AFAICT, it was only used by glance-manage when launching servers and I've changed that to pass --config-file - log_opt_values() doesn't log unknown opts, so won't log any values for opts which get registered at runtime later Change-Id: Iafa998a2a8d860f1ad57e2cd2afee69686ed58ba
This commit is contained in:
parent
e5925473cd
commit
57c4e9b6c6
@ -23,7 +23,6 @@ Glance API Server
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import gettext
|
import gettext
|
||||||
import optparse
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@ -37,33 +36,19 @@ if os.path.exists(os.path.join(possible_topdir, 'glance', '__init__.py')):
|
|||||||
|
|
||||||
gettext.install('glance', unicode=1)
|
gettext.install('glance', unicode=1)
|
||||||
|
|
||||||
from glance import version
|
|
||||||
from glance.common import config
|
from glance.common import config
|
||||||
from glance.common import wsgi
|
from glance.common import wsgi
|
||||||
|
|
||||||
|
|
||||||
def create_options(parser):
|
|
||||||
"""
|
|
||||||
Sets up the CLI and config-file options that may be
|
|
||||||
parsed and program commands.
|
|
||||||
|
|
||||||
:param parser: The option parser
|
|
||||||
"""
|
|
||||||
config.add_common_options(parser)
|
|
||||||
config.add_log_options(parser)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
oparser = optparse.OptionParser(version='%%prog %s'
|
|
||||||
% version.version_string())
|
|
||||||
create_options(oparser)
|
|
||||||
(options, args) = config.parse_options(oparser)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
conf, app = config.load_paste_app('glance-api', options, args)
|
conf = config.GlanceConfigOpts()
|
||||||
|
conf()
|
||||||
|
|
||||||
|
app = config.load_paste_app(conf)
|
||||||
|
|
||||||
server = wsgi.Server()
|
server = wsgi.Server()
|
||||||
server.start(app, int(conf['bind_port']), conf['bind_host'], conf)
|
server.start(app, conf, default_port=9292)
|
||||||
server.wait()
|
server.wait()
|
||||||
except RuntimeError, e:
|
except RuntimeError, e:
|
||||||
sys.exit("ERROR: %s" % e)
|
sys.exit("ERROR: %s" % e)
|
||||||
|
@ -33,7 +33,6 @@ period, we automatically sweep it up.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import gettext
|
import gettext
|
||||||
import optparse
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@ -47,31 +46,15 @@ if os.path.exists(os.path.join(possible_topdir, 'glance', '__init__.py')):
|
|||||||
|
|
||||||
gettext.install('glance', unicode=1)
|
gettext.install('glance', unicode=1)
|
||||||
|
|
||||||
from glance import version
|
|
||||||
from glance.common import config
|
from glance.common import config
|
||||||
from glance.common import wsgi
|
|
||||||
|
|
||||||
|
|
||||||
def create_options(parser):
|
|
||||||
"""
|
|
||||||
Sets up the CLI and config-file options that may be
|
|
||||||
parsed and program commands.
|
|
||||||
|
|
||||||
:param parser: The option parser
|
|
||||||
"""
|
|
||||||
config.add_common_options(parser)
|
|
||||||
config.add_log_options(parser)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
oparser = optparse.OptionParser(version='%%prog %s'
|
|
||||||
% version.version_string())
|
|
||||||
create_options(oparser)
|
|
||||||
(options, args) = config.parse_options(oparser)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
conf, app = config.load_paste_app('glance-cleaner', options, args,
|
conf = config.GlanceCacheConfigOpts()
|
||||||
'glance-cache')
|
conf()
|
||||||
|
|
||||||
|
app = config.load_paste_app(conf, 'glance-cleaner')
|
||||||
app.run()
|
app.run()
|
||||||
except RuntimeError, e:
|
except RuntimeError, e:
|
||||||
sys.exit("ERROR: %s" % e)
|
sys.exit("ERROR: %s" % e)
|
||||||
|
@ -24,7 +24,6 @@ images to be pretched.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import gettext
|
import gettext
|
||||||
import optparse
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@ -38,30 +37,15 @@ if os.path.exists(os.path.join(possible_topdir, 'glance', '__init__.py')):
|
|||||||
|
|
||||||
gettext.install('glance', unicode=1)
|
gettext.install('glance', unicode=1)
|
||||||
|
|
||||||
from glance import version
|
|
||||||
from glance.common import config
|
from glance.common import config
|
||||||
|
|
||||||
|
|
||||||
def create_options(parser):
|
|
||||||
"""
|
|
||||||
Sets up the CLI and config-file options that may be
|
|
||||||
parsed and program commands.
|
|
||||||
|
|
||||||
:param parser: The option parser
|
|
||||||
"""
|
|
||||||
config.add_common_options(parser)
|
|
||||||
config.add_log_options(parser)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
oparser = optparse.OptionParser(version='%%prog %s'
|
|
||||||
% version.version_string())
|
|
||||||
create_options(oparser)
|
|
||||||
(options, args) = config.parse_options(oparser)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
conf, app = config.load_paste_app('glance-prefetcher', options, args,
|
conf = config.GlanceCacheConfigOpts()
|
||||||
'glance-cache')
|
conf()
|
||||||
|
|
||||||
|
app = config.load_paste_app(conf, 'glance-prefetcher')
|
||||||
app.run()
|
app.run()
|
||||||
except RuntimeError, e:
|
except RuntimeError, e:
|
||||||
sys.exit("ERROR: %s" % e)
|
sys.exit("ERROR: %s" % e)
|
||||||
|
@ -25,7 +25,6 @@ This is meant to be run as a periodic task, perhaps every half-hour.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import gettext
|
import gettext
|
||||||
import optparse
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@ -39,31 +38,15 @@ if os.path.exists(os.path.join(possible_topdir, 'glance', '__init__.py')):
|
|||||||
|
|
||||||
gettext.install('glance', unicode=1)
|
gettext.install('glance', unicode=1)
|
||||||
|
|
||||||
from glance import version
|
|
||||||
from glance.common import config
|
from glance.common import config
|
||||||
from glance.common import wsgi
|
|
||||||
|
|
||||||
|
|
||||||
def create_options(parser):
|
|
||||||
"""
|
|
||||||
Sets up the CLI and config-file options that may be
|
|
||||||
parsed and program commands.
|
|
||||||
|
|
||||||
:param parser: The option parser
|
|
||||||
"""
|
|
||||||
config.add_common_options(parser)
|
|
||||||
config.add_log_options(parser)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
oparser = optparse.OptionParser(version='%%prog %s'
|
|
||||||
% version.version_string())
|
|
||||||
create_options(oparser)
|
|
||||||
(options, args) = config.parse_options(oparser)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
conf, app = config.load_paste_app('glance-pruner', options, args,
|
conf = config.GlanceCacheConfigOpts()
|
||||||
'glance-cache')
|
conf()
|
||||||
|
|
||||||
|
app = config.load_paste_app(conf, 'glance-pruner')
|
||||||
app.run()
|
app.run()
|
||||||
except RuntimeError, e:
|
except RuntimeError, e:
|
||||||
sys.exit("ERROR: %s" % e)
|
sys.exit("ERROR: %s" % e)
|
||||||
|
@ -21,7 +21,6 @@ CLI Utility to queue one or more images for prefetching into the image cache
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import gettext
|
import gettext
|
||||||
import optparse
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@ -35,7 +34,6 @@ if os.path.exists(os.path.join(possible_topdir, 'glance', '__init__.py')):
|
|||||||
|
|
||||||
gettext.install('glance', unicode=1)
|
gettext.install('glance', unicode=1)
|
||||||
|
|
||||||
from glance import version
|
|
||||||
from glance.common import config
|
from glance.common import config
|
||||||
|
|
||||||
USAGE = """
|
USAGE = """
|
||||||
@ -44,13 +42,11 @@ USAGE = """
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
oparser = optparse.OptionParser(version='%%prog %s'
|
|
||||||
% version.version_string(),
|
|
||||||
usage=USAGE)
|
|
||||||
(options, args) = config.parse_options(oparser)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
conf, app = config.load_paste_app('glance-queue-image', options, args)
|
conf = config.GlanceCacheConfigOpts(usage=USAGE)
|
||||||
|
args = conf()
|
||||||
|
|
||||||
|
app = config.load_paste_app(conf, 'glance-queue-image')
|
||||||
app.run(args)
|
app.run(args)
|
||||||
except RuntimeError, e:
|
except RuntimeError, e:
|
||||||
sys.exit("ERROR: %s" % e)
|
sys.exit("ERROR: %s" % e)
|
||||||
|
@ -43,6 +43,7 @@ if os.path.exists(os.path.join(possible_topdir, 'glance', '__init__.py')):
|
|||||||
gettext.install('glance', unicode=1)
|
gettext.install('glance', unicode=1)
|
||||||
|
|
||||||
from glance import version
|
from glance import version
|
||||||
|
from glance.common import cfg
|
||||||
from glance.common import config
|
from glance.common import config
|
||||||
|
|
||||||
ALL_COMMANDS = ['start', 'stop', 'shutdown', 'restart',
|
ALL_COMMANDS = ['start', 'stop', 'shutdown', 'restart',
|
||||||
@ -65,11 +66,11 @@ And command is one of:
|
|||||||
And CONFPATH is the optional configuration file to use."""
|
And CONFPATH is the optional configuration file to use."""
|
||||||
|
|
||||||
|
|
||||||
def pid_files(server, options):
|
def pid_files(server, conf):
|
||||||
pid_files = []
|
pid_files = []
|
||||||
if options['pid_file']:
|
if conf.pid_file:
|
||||||
if os.path.exists(os.path.abspath(options['pid_file'])):
|
if os.path.exists(os.path.abspath(conf.pid_file)):
|
||||||
pid_files = [os.path.abspath(options['pid_file'])]
|
pid_files = [os.path.abspath(conf.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]
|
||||||
@ -78,10 +79,10 @@ def pid_files(server, options):
|
|||||||
yield pid_file, pid
|
yield pid_file, pid
|
||||||
|
|
||||||
|
|
||||||
def do_start(server, options, args):
|
def do_start(server, conf, args):
|
||||||
server_type = '-'.join(server.split('-')[:-1])
|
server_type = '-'.join(server.split('-')[:-1])
|
||||||
|
|
||||||
for pid_file, pid in pid_files(server, options):
|
for pid_file, pid in pid_files(server, conf):
|
||||||
if os.path.exists('/proc/%s' % pid):
|
if os.path.exists('/proc/%s' % pid):
|
||||||
print "%s appears to already be running: %s" % (server, pid_file)
|
print "%s appears to already be running: %s" % (server, pid_file)
|
||||||
return
|
return
|
||||||
@ -112,7 +113,6 @@ def do_start(server, options, args):
|
|||||||
fp.close()
|
fp.close()
|
||||||
|
|
||||||
def launch(ini_file, pid_file):
|
def launch(ini_file, pid_file):
|
||||||
args = [server, ini_file]
|
|
||||||
print 'Starting %s with %s' % (server, ini_file)
|
print 'Starting %s with %s' % (server, ini_file)
|
||||||
|
|
||||||
pid = os.fork()
|
pid = os.fork()
|
||||||
@ -125,7 +125,7 @@ def do_start(server, options, args):
|
|||||||
except OSError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
os.execlp('%s' % server, server, ini_file)
|
os.execlp('%s' % server, server, '--config-file', ini_file)
|
||||||
except OSError, e:
|
except OSError, e:
|
||||||
sys.exit('unable to launch %s. Got error: %s'
|
sys.exit('unable to launch %s. Got error: %s'
|
||||||
% (server, "%s" % e))
|
% (server, "%s" % e))
|
||||||
@ -133,31 +133,31 @@ def do_start(server, options, args):
|
|||||||
else:
|
else:
|
||||||
write_pid_file(pid_file, pid)
|
write_pid_file(pid_file, pid)
|
||||||
|
|
||||||
if not options['pid_file']:
|
if not conf.pid_file:
|
||||||
pid_file = '/var/run/glance/%s.pid' % server
|
pid_file = '/var/run/glance/%s.pid' % server
|
||||||
else:
|
else:
|
||||||
pid_file = os.path.abspath(options['pid_file'])
|
pid_file = os.path.abspath(conf.pid_file)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
conf_file = config.find_config_file(server, options, args)
|
if args and os.path.exists(args[0]):
|
||||||
|
conf_file = os.path.abspath(os.path.expanduser(args[0]))
|
||||||
|
else:
|
||||||
|
# Assume paste config is in the last config file
|
||||||
|
conf_file = conf.config_file[-1]
|
||||||
except RuntimeError, err:
|
except RuntimeError, err:
|
||||||
sys.exit("Could not find any configuration file to use: %s" % err)
|
sys.exit("Could not find any configuration file to use: %s" % err)
|
||||||
|
|
||||||
launch_args = [(conf_file, pid_file)]
|
|
||||||
|
|
||||||
# start all servers
|
|
||||||
for conf_file, pid_file in launch_args:
|
|
||||||
launch(conf_file, pid_file)
|
launch(conf_file, pid_file)
|
||||||
|
|
||||||
|
|
||||||
def do_stop(server, options, args, graceful=False):
|
def do_stop(server, conf, 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, options)
|
pfiles = pid_files(server, conf)
|
||||||
for pid_file, pid in pfiles:
|
for pid_file, pid in pfiles:
|
||||||
did_anything = True
|
did_anything = True
|
||||||
try:
|
try:
|
||||||
@ -182,13 +182,12 @@ def do_stop(server, options, args, graceful=False):
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
oparser = optparse.OptionParser(usage=USAGE, version='%%prog %s'
|
conf = config.GlanceConfigOpts(usage=USAGE)
|
||||||
% version.version_string())
|
conf.register_cli_opt(cfg.StrOpt('pid-file',
|
||||||
oparser.add_option('--pid-file', default=None, metavar="PATH",
|
metavar='PATH',
|
||||||
help="File to use as pid file. Default: "
|
help='File to use as pid file. Default: '
|
||||||
"/var/run/glance/$server.pid")
|
'/var/run/glance/$server.pid'))
|
||||||
config.add_common_options(oparser)
|
args = conf()
|
||||||
(options, args) = config.parse_options(oparser)
|
|
||||||
|
|
||||||
if len(args) < 2:
|
if len(args) < 2:
|
||||||
oparser.print_usage()
|
oparser.print_usage()
|
||||||
@ -217,23 +216,23 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
if command == 'start':
|
if command == 'start':
|
||||||
for server in servers:
|
for server in servers:
|
||||||
do_start(server, options, args)
|
do_start(server, conf, args)
|
||||||
|
|
||||||
if command == 'stop':
|
if command == 'stop':
|
||||||
for server in servers:
|
for server in servers:
|
||||||
do_stop(server, options, args)
|
do_stop(server, conf, args)
|
||||||
|
|
||||||
if command == 'shutdown':
|
if command == 'shutdown':
|
||||||
for server in servers:
|
for server in servers:
|
||||||
do_stop(server, options, args, graceful=True)
|
do_stop(server, conf, args, graceful=True)
|
||||||
|
|
||||||
if command == 'restart':
|
if command == 'restart':
|
||||||
for server in servers:
|
for server in servers:
|
||||||
do_stop(server, options, args)
|
do_stop(server, conf, args)
|
||||||
for server in servers:
|
for server in servers:
|
||||||
do_start(server, options, args)
|
do_start(server, conf, 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, options, args, graceful=True)
|
do_stop(server, conf, args, graceful=True)
|
||||||
do_start(server, options, args)
|
do_start(server, conf, args)
|
||||||
|
@ -27,7 +27,6 @@ Glance Management Utility
|
|||||||
# glance-manage (or the other way around)
|
# glance-manage (or the other way around)
|
||||||
|
|
||||||
import gettext
|
import gettext
|
||||||
import optparse
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@ -41,41 +40,29 @@ if os.path.exists(os.path.join(possible_topdir, 'glance', '__init__.py')):
|
|||||||
|
|
||||||
gettext.install('glance', unicode=1)
|
gettext.install('glance', unicode=1)
|
||||||
|
|
||||||
from glance import version as glance_version
|
from glance.common import cfg
|
||||||
from glance.common import config
|
from glance.common import config
|
||||||
from glance.common import exception
|
from glance.common import exception
|
||||||
import glance.registry.db
|
import glance.registry.db
|
||||||
import glance.registry.db.migration
|
import glance.registry.db.migration
|
||||||
|
|
||||||
|
|
||||||
def create_options(parser):
|
def do_db_version(conf, args):
|
||||||
"""
|
|
||||||
Sets up the CLI and config-file options that may be
|
|
||||||
parsed and program commands.
|
|
||||||
|
|
||||||
:param parser: The option parser
|
|
||||||
"""
|
|
||||||
config.add_common_options(parser)
|
|
||||||
config.add_log_options(parser)
|
|
||||||
glance.registry.db.add_options(parser)
|
|
||||||
|
|
||||||
|
|
||||||
def do_db_version(options, args):
|
|
||||||
"""Print database's current migration level"""
|
"""Print database's current migration level"""
|
||||||
print glance.registry.db.migration.db_version(options)
|
print glance.registry.db.migration.db_version(conf)
|
||||||
|
|
||||||
|
|
||||||
def do_upgrade(options, args):
|
def do_upgrade(conf, args):
|
||||||
"""Upgrade the database's migration level"""
|
"""Upgrade the database's migration level"""
|
||||||
try:
|
try:
|
||||||
db_version = args[1]
|
db_version = args[1]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
db_version = None
|
db_version = None
|
||||||
|
|
||||||
glance.registry.db.migration.upgrade(options, version=db_version)
|
glance.registry.db.migration.upgrade(conf, version=db_version)
|
||||||
|
|
||||||
|
|
||||||
def do_downgrade(options, args):
|
def do_downgrade(conf, args):
|
||||||
"""Downgrade the database's migration level"""
|
"""Downgrade the database's migration level"""
|
||||||
try:
|
try:
|
||||||
db_version = args[1]
|
db_version = args[1]
|
||||||
@ -83,24 +70,24 @@ def do_downgrade(options, args):
|
|||||||
raise exception.MissingArgumentError(
|
raise exception.MissingArgumentError(
|
||||||
"downgrade requires a version argument")
|
"downgrade requires a version argument")
|
||||||
|
|
||||||
glance.registry.db.migration.downgrade(options, version=db_version)
|
glance.registry.db.migration.downgrade(conf, version=db_version)
|
||||||
|
|
||||||
|
|
||||||
def do_version_control(options, args):
|
def do_version_control(conf, args):
|
||||||
"""Place a database under migration control"""
|
"""Place a database under migration control"""
|
||||||
glance.registry.db.migration.version_control(options)
|
glance.registry.db.migration.version_control(conf)
|
||||||
|
|
||||||
|
|
||||||
def do_db_sync(options, args):
|
def do_db_sync(conf, args):
|
||||||
"""Place a database under migration control and upgrade"""
|
"""Place a database under migration control and upgrade"""
|
||||||
try:
|
try:
|
||||||
db_version = args[1]
|
db_version = args[1]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
db_version = None
|
db_version = None
|
||||||
glance.registry.db.migration.db_sync(options, version=db_version)
|
glance.registry.db.migration.db_sync(conf, version=db_version)
|
||||||
|
|
||||||
|
|
||||||
def dispatch_cmd(options, args):
|
def dispatch_cmd(conf, 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[0]
|
cmd = args[0]
|
||||||
try:
|
try:
|
||||||
@ -109,35 +96,32 @@ def dispatch_cmd(options, args):
|
|||||||
sys.exit("ERROR: unrecognized command '%s'" % cmd)
|
sys.exit("ERROR: unrecognized command '%s'" % cmd)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
cmd_func(options, args)
|
cmd_func(conf, args)
|
||||||
except exception.GlanceException, e:
|
except exception.GlanceException, e:
|
||||||
sys.exit("ERROR: %s" % e)
|
sys.exit("ERROR: %s" % e)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
version = '%%prog %s' % glance_version.version_string()
|
|
||||||
usage = "%prog [options] <cmd>"
|
|
||||||
oparser = optparse.OptionParser(usage, version=version)
|
|
||||||
create_options(oparser)
|
|
||||||
(options, args) = config.parse_options(oparser)
|
|
||||||
|
|
||||||
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.
|
||||||
conf_file = config.find_config_file('glance-registry', options, args)
|
default_config_files = \
|
||||||
conf = config.load_paste_config(conf_file, 'glance-registry')
|
cfg.find_config_files(project='glance', prog='glance-registry')
|
||||||
config.setup_logging(options, conf)
|
|
||||||
|
conf = \
|
||||||
|
config.GlanceConfigOpts(default_config_files=default_config_files,
|
||||||
|
usage="%prog [options] <cmd>")
|
||||||
|
glance.registry.db.add_options(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:
|
||||||
oparser.print_usage()
|
conf.print_usage()
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if conf.get('sql_connection') and not options['sql_connection']:
|
dispatch_cmd(conf, args)
|
||||||
options['sql_connection'] = conf.get('sql_connection')
|
|
||||||
|
|
||||||
dispatch_cmd(options, args)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
@ -23,7 +23,6 @@ Reference implementation server for Glance Registry
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import gettext
|
import gettext
|
||||||
import optparse
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@ -37,33 +36,19 @@ if os.path.exists(os.path.join(possible_topdir, 'glance', '__init__.py')):
|
|||||||
|
|
||||||
gettext.install('glance', unicode=1)
|
gettext.install('glance', unicode=1)
|
||||||
|
|
||||||
from glance import version
|
|
||||||
from glance.common import config
|
from glance.common import config
|
||||||
from glance.common import wsgi
|
from glance.common import wsgi
|
||||||
|
|
||||||
|
|
||||||
def create_options(parser):
|
|
||||||
"""
|
|
||||||
Sets up the CLI and config-file options that may be
|
|
||||||
parsed and program commands.
|
|
||||||
|
|
||||||
:param parser: The option parser
|
|
||||||
"""
|
|
||||||
config.add_common_options(parser)
|
|
||||||
config.add_log_options(parser)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
oparser = optparse.OptionParser(version='%%prog %s'
|
|
||||||
% version.version_string())
|
|
||||||
create_options(oparser)
|
|
||||||
(options, args) = config.parse_options(oparser)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
conf, app = config.load_paste_app('glance-registry', options, args)
|
conf = config.GlanceConfigOpts()
|
||||||
|
conf()
|
||||||
|
|
||||||
|
app = config.load_paste_app(conf)
|
||||||
|
|
||||||
server = wsgi.Server()
|
server = wsgi.Server()
|
||||||
server.start(app, int(conf['bind_port']), conf['bind_host'], conf)
|
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)
|
||||||
|
@ -21,7 +21,6 @@ Glance Scrub Service
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import gettext
|
import gettext
|
||||||
import optparse
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@ -35,44 +34,30 @@ if os.path.exists(os.path.join(possible_topdir, 'glance', '__init__.py')):
|
|||||||
|
|
||||||
gettext.install('glance', unicode=1)
|
gettext.install('glance', unicode=1)
|
||||||
|
|
||||||
from glance import version
|
from glance.common import cfg
|
||||||
from glance.common import config
|
from glance.common import config
|
||||||
from glance.store import scrubber
|
from glance.store import scrubber
|
||||||
|
|
||||||
|
|
||||||
def create_options(parser):
|
|
||||||
"""
|
|
||||||
Sets up the CLI and config-file options that may be
|
|
||||||
parsed and program commands.
|
|
||||||
|
|
||||||
:param parser: The option parser
|
|
||||||
"""
|
|
||||||
config.add_common_options(parser)
|
|
||||||
config.add_log_options(parser)
|
|
||||||
parser.add_option("-D", "--daemon", default=False, dest="daemon",
|
|
||||||
action="store_true",
|
|
||||||
help="Run as a long-running process. When not "
|
|
||||||
"specified (the default) run the scrub "
|
|
||||||
"operation once and then exits. When specified "
|
|
||||||
"do not exit and run scrub on wakeup_time "
|
|
||||||
"interval as specified in the config file.")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
oparser = optparse.OptionParser(version='%%prog %s'
|
|
||||||
% version.version_string())
|
|
||||||
create_options(oparser)
|
|
||||||
(options, args) = config.parse_options(oparser)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
conf, app = config.load_paste_app('glance-scrubber', options, args)
|
conf = config.GlanceConfigOpts()
|
||||||
daemon = options.get('daemon') or \
|
conf.register_cli_opt(
|
||||||
config.get_option(conf, 'daemon', type='bool',
|
cfg.BoolOpt('daemon',
|
||||||
default=False)
|
short='D',
|
||||||
|
default=False,
|
||||||
|
help='Run as a long-running process. When not '
|
||||||
|
'specified (the default) run the scrub operation '
|
||||||
|
'once and then exits. When specified do not exit '
|
||||||
|
'and run scrub on wakeup_time interval as '
|
||||||
|
'specified in the config.'))
|
||||||
|
conf.register_opt(cfg.IntOpt('wakeup_time', default=300))
|
||||||
|
conf()
|
||||||
|
|
||||||
if daemon:
|
app = config.load_paste_app(conf, 'glance-scrubber')
|
||||||
wakeup_time = int(conf.get('wakeup_time', 300))
|
|
||||||
server = scrubber.Daemon(wakeup_time)
|
if conf.daemon:
|
||||||
|
server = scrubber.Daemon(conf.wakeup_time)
|
||||||
server.start(app)
|
server.start(app)
|
||||||
server.wait()
|
server.wait()
|
||||||
else:
|
else:
|
||||||
|
@ -43,7 +43,7 @@ get_images_re = re.compile(r'^(/v\d+)*/images/(.+)$')
|
|||||||
|
|
||||||
class CacheFilter(wsgi.Middleware):
|
class CacheFilter(wsgi.Middleware):
|
||||||
|
|
||||||
def __init__(self, app, conf):
|
def __init__(self, app, conf, **local_conf):
|
||||||
self.conf = conf
|
self.conf = conf
|
||||||
self.cache = image_cache.ImageCache(conf)
|
self.cache = image_cache.ImageCache(conf)
|
||||||
self.serializer = images.ImageSerializer()
|
self.serializer = images.ImageSerializer()
|
||||||
|
@ -28,8 +28,7 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class CacheManageFilter(wsgi.Middleware):
|
class CacheManageFilter(wsgi.Middleware):
|
||||||
def __init__(self, app, conf):
|
def __init__(self, app, conf, **local_conf):
|
||||||
|
|
||||||
map = app.map
|
map = app.map
|
||||||
resource = cached_images.create_resource(conf)
|
resource = cached_images.create_resource(conf)
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ logger = logging.getLogger('glance.api.middleware.version_negotiation')
|
|||||||
|
|
||||||
class VersionNegotiationFilter(wsgi.Middleware):
|
class VersionNegotiationFilter(wsgi.Middleware):
|
||||||
|
|
||||||
def __init__(self, app, conf):
|
def __init__(self, app, conf, **local_conf):
|
||||||
self.versions_app = versions.Controller(conf)
|
self.versions_app = versions.Controller(conf)
|
||||||
self.version_uri_regex = re.compile(r"^v(\d+)\.?(\d+)?")
|
self.version_uri_regex = re.compile(r"^v(\d+)\.?(\d+)?")
|
||||||
self.conf = conf
|
self.conf = conf
|
||||||
|
@ -34,6 +34,7 @@ from webob.exc import (HTTPNotFound,
|
|||||||
import glance.api.v1
|
import glance.api.v1
|
||||||
from glance.api.v1 import controller
|
from glance.api.v1 import controller
|
||||||
from glance import image_cache
|
from glance import image_cache
|
||||||
|
from glance.common import cfg
|
||||||
from glance.common import exception
|
from glance.common import exception
|
||||||
from glance.common import notifier
|
from glance.common import notifier
|
||||||
from glance.common import wsgi
|
from glance.common import wsgi
|
||||||
@ -76,8 +77,11 @@ class Controller(controller.BaseController):
|
|||||||
DELETE /images/<ID> -- Delete the image with id <ID>
|
DELETE /images/<ID> -- Delete the image with id <ID>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
default_store_opt = cfg.StrOpt('default_store', default='file')
|
||||||
|
|
||||||
def __init__(self, conf):
|
def __init__(self, conf):
|
||||||
self.conf = conf
|
self.conf = conf
|
||||||
|
self.conf.register_opt(self.default_store_opt)
|
||||||
glance.store.create_stores(conf)
|
glance.store.create_stores(conf)
|
||||||
self.notifier = notifier.Notifier(conf)
|
self.notifier = notifier.Notifier(conf)
|
||||||
registry.configure_registry_client(conf)
|
registry.configure_registry_client(conf)
|
||||||
@ -290,7 +294,7 @@ class Controller(controller.BaseController):
|
|||||||
raise HTTPBadRequest(explanation=msg)
|
raise HTTPBadRequest(explanation=msg)
|
||||||
|
|
||||||
store_name = req.headers.get('x-image-meta-store',
|
store_name = req.headers.get('x-image-meta-store',
|
||||||
self.conf['default_store'])
|
self.conf.default_store)
|
||||||
|
|
||||||
store = self.get_store_or_400(req, store_name)
|
store = self.get_store_or_400(req, store_name)
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ class API(wsgi.Router):
|
|||||||
|
|
||||||
"""WSGI router for Glance v1 API requests."""
|
"""WSGI router for Glance v1 API requests."""
|
||||||
|
|
||||||
def __init__(self, conf):
|
def __init__(self, conf, **local_conf):
|
||||||
self.conf = conf
|
self.conf = conf
|
||||||
mapper = routes.Mapper()
|
mapper = routes.Mapper()
|
||||||
|
|
||||||
|
@ -24,6 +24,8 @@ import json
|
|||||||
|
|
||||||
import webob.dec
|
import webob.dec
|
||||||
|
|
||||||
|
from glance.common import wsgi
|
||||||
|
|
||||||
|
|
||||||
class Controller(object):
|
class Controller(object):
|
||||||
|
|
||||||
@ -63,5 +65,4 @@ class Controller(object):
|
|||||||
return response
|
return response
|
||||||
|
|
||||||
def get_href(self):
|
def get_href(self):
|
||||||
return "http://%s:%s/v1/" % (self.conf['bind_host'],
|
return "http://%s:%s/v1/" % wsgi.get_bind_addr(self.conf, 9292)
|
||||||
self.conf['bind_port'])
|
|
||||||
|
@ -20,159 +20,68 @@
|
|||||||
Routines for configuring Glance
|
Routines for configuring Glance
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import ConfigParser
|
|
||||||
import logging
|
import logging
|
||||||
import logging.config
|
import logging.config
|
||||||
import logging.handlers
|
import logging.handlers
|
||||||
import optparse
|
|
||||||
import os
|
import os
|
||||||
import re
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from paste import deploy
|
from glance import version
|
||||||
|
from glance.common import cfg
|
||||||
import glance.common.exception as exception
|
from glance.common import utils
|
||||||
|
from glance.common import wsgi
|
||||||
DEFAULT_LOG_FORMAT = "%(asctime)s %(levelname)8s [%(name)s] %(message)s"
|
|
||||||
DEFAULT_LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
|
|
||||||
|
|
||||||
|
|
||||||
def parse_options(parser, cli_args=None):
|
class GlanceConfigOpts(cfg.CommonConfigOpts):
|
||||||
"""
|
|
||||||
Returns the parsed CLI options, command to run and its arguments, merged
|
|
||||||
with any same-named options found in a configuration file.
|
|
||||||
|
|
||||||
The function returns a tuple of (options, args), where options is a
|
def __init__(self, default_config_files=None, **kwargs):
|
||||||
mapping of option key/str(value) pairs, and args is the set of arguments
|
super(GlanceConfigOpts, self).__init__(
|
||||||
(not options) supplied on the command-line.
|
project='glance',
|
||||||
|
version='%%prog %s' % version.version_string(),
|
||||||
The reason that the option values are returned as strings only is that
|
default_config_files=default_config_files,
|
||||||
ConfigParser and paste.deploy only accept string values...
|
**kwargs)
|
||||||
|
|
||||||
:param parser: The option parser
|
|
||||||
:param cli_args: (Optional) Set of arguments to process. If not present,
|
|
||||||
sys.argv[1:] is used.
|
|
||||||
:retval tuple of (options, args)
|
|
||||||
"""
|
|
||||||
|
|
||||||
(options, args) = parser.parse_args(cli_args)
|
|
||||||
|
|
||||||
return (vars(options), args)
|
|
||||||
|
|
||||||
|
|
||||||
def add_common_options(parser):
|
class GlanceCacheConfigOpts(GlanceConfigOpts):
|
||||||
"""
|
|
||||||
Given a supplied optparse.OptionParser, adds an OptionGroup that
|
|
||||||
represents all common configuration options.
|
|
||||||
|
|
||||||
:param parser: optparse.OptionParser
|
def __init__(self, **kwargs):
|
||||||
"""
|
config_files = cfg.find_config_files(project='glance',
|
||||||
help_text = "The following configuration options are common to "\
|
prog='glance-cache')
|
||||||
"all glance programs."
|
super(GlanceCacheConfigOpts, self).__init__(config_files, **kwargs)
|
||||||
|
|
||||||
group = optparse.OptionGroup(parser, "Common Options", help_text)
|
|
||||||
group.add_option('-v', '--verbose', default=False, dest="verbose",
|
|
||||||
action="store_true",
|
|
||||||
help="Print more verbose output")
|
|
||||||
group.add_option('-d', '--debug', default=False, dest="debug",
|
|
||||||
action="store_true",
|
|
||||||
help="Print debugging output")
|
|
||||||
group.add_option('--config-file', default=None, metavar="PATH",
|
|
||||||
help="Path to the config file to use. When not specified "
|
|
||||||
"(the default), we generally look at the first "
|
|
||||||
"argument specified to be a config file, and if "
|
|
||||||
"that is also missing, we search standard "
|
|
||||||
"directories for a config file.")
|
|
||||||
parser.add_option_group(group)
|
|
||||||
|
|
||||||
|
|
||||||
def add_log_options(parser):
|
def setup_logging(conf):
|
||||||
"""
|
|
||||||
Given a supplied optparse.OptionParser, adds an OptionGroup that
|
|
||||||
represents all the configuration options around logging.
|
|
||||||
|
|
||||||
:param parser: optparse.OptionParser
|
|
||||||
"""
|
|
||||||
help_text = "The following configuration options are specific to logging "\
|
|
||||||
"functionality for this program."
|
|
||||||
|
|
||||||
group = optparse.OptionGroup(parser, "Logging Options", help_text)
|
|
||||||
group.add_option('--log-config', default=None, metavar="PATH",
|
|
||||||
help="If this option is specified, the logging "
|
|
||||||
"configuration file specified is used and overrides "
|
|
||||||
"any other logging options specified. Please see "
|
|
||||||
"the Python logging module documentation for "
|
|
||||||
"details on logging configuration files.")
|
|
||||||
group.add_option('--log-date-format', metavar="FORMAT",
|
|
||||||
default=DEFAULT_LOG_DATE_FORMAT,
|
|
||||||
help="Format string for %(asctime)s in log records. "
|
|
||||||
"Default: %default")
|
|
||||||
group.add_option('--log-file', default=None, metavar="PATH",
|
|
||||||
help="(Optional) Name of log file to output to. "
|
|
||||||
"If not set, logging will go to stdout.")
|
|
||||||
group.add_option("--log-dir", default=None,
|
|
||||||
help="(Optional) The directory to keep log files in "
|
|
||||||
"(will be prepended to --logfile)")
|
|
||||||
group.add_option('--use-syslog', default=False, dest="use_syslog",
|
|
||||||
action="store_true",
|
|
||||||
help="Use syslog for logging.")
|
|
||||||
parser.add_option_group(group)
|
|
||||||
|
|
||||||
|
|
||||||
def setup_logging(options, conf):
|
|
||||||
"""
|
"""
|
||||||
Sets up the logging options for a log with supplied name
|
Sets up the logging options for a log with supplied name
|
||||||
|
|
||||||
:param options: Mapping of typed option key/values
|
:param conf: a cfg.ConfOpts object
|
||||||
:param conf: Mapping of untyped key/values from config file
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if options.get('log_config', None):
|
if conf.log_config:
|
||||||
# Use a logging configuration file for all settings...
|
# Use a logging configuration file for all settings...
|
||||||
if os.path.exists(options['log_config']):
|
if os.path.exists(conf.log_config):
|
||||||
logging.config.fileConfig(options['log_config'])
|
logging.config.fileConfig(conf.log_config)
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("Unable to locate specified logging "
|
raise RuntimeError("Unable to locate specified logging "
|
||||||
"config file: %s" % options['log_config'])
|
"config file: %s" % conf.log_config)
|
||||||
|
|
||||||
# If either the CLI option or the conf value
|
|
||||||
# is True, we set to True
|
|
||||||
debug = options.get('debug') or \
|
|
||||||
get_option(conf, 'debug', type='bool', default=False)
|
|
||||||
verbose = options.get('verbose') or \
|
|
||||||
get_option(conf, 'verbose', type='bool', default=False)
|
|
||||||
root_logger = logging.root
|
root_logger = logging.root
|
||||||
if debug:
|
if conf.debug:
|
||||||
root_logger.setLevel(logging.DEBUG)
|
root_logger.setLevel(logging.DEBUG)
|
||||||
elif verbose:
|
elif conf.verbose:
|
||||||
root_logger.setLevel(logging.INFO)
|
root_logger.setLevel(logging.INFO)
|
||||||
else:
|
else:
|
||||||
root_logger.setLevel(logging.WARNING)
|
root_logger.setLevel(logging.WARNING)
|
||||||
|
|
||||||
# Set log configuration from options...
|
formatter = logging.Formatter(conf.log_format, conf.log_date_format)
|
||||||
# Note that we use a hard-coded log format in the options
|
|
||||||
# because of Paste.Deploy bug #379
|
|
||||||
# http://trac.pythonpaste.org/pythonpaste/ticket/379
|
|
||||||
log_format = options.get('log_format', DEFAULT_LOG_FORMAT)
|
|
||||||
log_date_format = options.get('log_date_format', DEFAULT_LOG_DATE_FORMAT)
|
|
||||||
formatter = logging.Formatter(log_format, log_date_format)
|
|
||||||
|
|
||||||
logfile = options.get('log_file')
|
if conf.use_syslog:
|
||||||
if not logfile:
|
|
||||||
logfile = conf.get('log_file')
|
|
||||||
|
|
||||||
use_syslog = options.get('use_syslog') or \
|
|
||||||
get_option(conf, 'use_syslog', type='bool', default=False)
|
|
||||||
|
|
||||||
if use_syslog:
|
|
||||||
handler = logging.handlers.SysLogHandler(address='/dev/log')
|
handler = logging.handlers.SysLogHandler(address='/dev/log')
|
||||||
elif logfile:
|
elif conf.log_file:
|
||||||
logdir = options.get('log_dir')
|
logfile = conf.log_file
|
||||||
if not logdir:
|
if conf.log_dir:
|
||||||
logdir = conf.get('log_dir')
|
logfile = os.path.join(conf.log_dir, logfile)
|
||||||
if logdir:
|
|
||||||
logfile = os.path.join(logdir, logfile)
|
|
||||||
handler = logging.handlers.WatchedFileHandler(logfile)
|
handler = logging.handlers.WatchedFileHandler(logfile)
|
||||||
else:
|
else:
|
||||||
handler = logging.StreamHandler(sys.stdout)
|
handler = logging.StreamHandler(sys.stdout)
|
||||||
@ -181,143 +90,39 @@ def setup_logging(options, conf):
|
|||||||
root_logger.addHandler(handler)
|
root_logger.addHandler(handler)
|
||||||
|
|
||||||
|
|
||||||
def find_config_file(conf_name, options, args):
|
def load_paste_app(conf, app_name=None):
|
||||||
"""
|
|
||||||
Return the first config file found for an application.
|
|
||||||
|
|
||||||
We search for the paste config file in the following order:
|
|
||||||
* If --config-file option is used, use that
|
|
||||||
* If args[0] is a file, use that
|
|
||||||
* Search for $conf_name.conf in standard directories:
|
|
||||||
* ~.glance/
|
|
||||||
* ~
|
|
||||||
* /etc/glance
|
|
||||||
* /etc
|
|
||||||
|
|
||||||
:retval Full path to config file.
|
|
||||||
|
|
||||||
:raises RuntimeError if the config file cannot be found.
|
|
||||||
"""
|
|
||||||
|
|
||||||
fix_path = lambda p: os.path.abspath(os.path.expanduser(p))
|
|
||||||
if options.get('config_file'):
|
|
||||||
if os.path.exists(options['config_file']):
|
|
||||||
return fix_path(options['config_file'])
|
|
||||||
elif args:
|
|
||||||
if os.path.exists(args[0]):
|
|
||||||
return fix_path(args[0])
|
|
||||||
|
|
||||||
# Handle standard directory search for $conf_name.conf
|
|
||||||
config_file_dirs = [fix_path(os.path.join('~', '.glance')),
|
|
||||||
fix_path('~'),
|
|
||||||
'/etc/glance/',
|
|
||||||
'/etc']
|
|
||||||
|
|
||||||
for cfg_dir in config_file_dirs:
|
|
||||||
cfg_file = os.path.join(cfg_dir, '%s.conf' % conf_name)
|
|
||||||
if os.path.exists(cfg_file):
|
|
||||||
return cfg_file
|
|
||||||
|
|
||||||
raise RuntimeError("Unable to locate %s configuration file." % conf_name)
|
|
||||||
|
|
||||||
|
|
||||||
def load_paste_config(conf_file, app_name):
|
|
||||||
"""
|
|
||||||
Load the configuration mapping from a paste config file.
|
|
||||||
|
|
||||||
:param conf_file: The path to the paste config file.
|
|
||||||
:param app_name: Name of the application to load config for, or None.
|
|
||||||
None signifies to only load the [DEFAULT] section of
|
|
||||||
the config file.
|
|
||||||
:retval The configuration mapping.
|
|
||||||
|
|
||||||
:raises RuntimeError when there was a problem loading the configuration
|
|
||||||
file.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
return deploy.appconfig("config:%s" % conf_file, name=app_name)
|
|
||||||
except Exception, e:
|
|
||||||
raise RuntimeError("Error trying to load config %s: %s"
|
|
||||||
% (conf_file, e))
|
|
||||||
|
|
||||||
|
|
||||||
def load_paste_app(app_name, options, args, conf_name=None):
|
|
||||||
"""
|
"""
|
||||||
Builds and returns a WSGI app from a paste config file.
|
Builds and returns a WSGI app from a paste config file.
|
||||||
|
|
||||||
We search for the paste config file in the following order:
|
We assume the last config file specified in the supplied ConfigOpts
|
||||||
* If --config-file option is used, use that
|
object is the paste config file.
|
||||||
* If args[0] is a file, use that
|
|
||||||
* Search for $conf_name.conf in standard directories:
|
|
||||||
* ~.glance/
|
|
||||||
* ~
|
|
||||||
* /etc/glance
|
|
||||||
* /etc
|
|
||||||
|
|
||||||
:param app_name: Name of the application to load
|
:param conf: a cfg.ConfigOpts object
|
||||||
:param options: Set of typed options returned from parse_options()
|
:param app_name: name of the application to load
|
||||||
:param args: Command line arguments from argv[1:]
|
|
||||||
:param conf_name: Name of config file to load, defaults to app_name
|
|
||||||
|
|
||||||
:raises RuntimeError when config file cannot be located or application
|
:raises RuntimeError when config file cannot be located or application
|
||||||
cannot be loaded from config file
|
cannot be loaded from config file
|
||||||
"""
|
"""
|
||||||
if conf_name is None:
|
if app_name is None:
|
||||||
conf_name = app_name
|
app_name = conf.prog
|
||||||
conf_file = find_config_file(conf_name, options, args)
|
|
||||||
|
|
||||||
conf = load_paste_config(conf_file, app_name)
|
# Assume paste config is in the last config file
|
||||||
|
conf_file = os.path.abspath(conf.config_file[-1])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Setup logging early, supplying both the CLI options and the
|
# Setup logging early
|
||||||
# configuration mapping from the config file
|
setup_logging(conf)
|
||||||
setup_logging(options, conf)
|
|
||||||
|
|
||||||
# We only update the conf dict for the verbose and debug
|
logger = logging.getLogger(app_name)
|
||||||
# flags. Everything else must be set up in the conf file...
|
|
||||||
debug = options.get('debug') or \
|
app = wsgi.paste_deploy_app(conf_file, app_name, conf)
|
||||||
get_option(conf, 'debug', type='bool', default=False)
|
|
||||||
verbose = options.get('verbose') or \
|
|
||||||
get_option(conf, 'verbose', type='bool', default=False)
|
|
||||||
conf['debug'] = debug
|
|
||||||
conf['verbose'] = verbose
|
|
||||||
|
|
||||||
# Log the options used when starting if we're in debug mode...
|
# Log the options used when starting if we're in debug mode...
|
||||||
if debug:
|
if conf.debug:
|
||||||
logger = logging.getLogger(app_name)
|
conf.log_opt_values(logging.getLogger(app_name), logging.DEBUG)
|
||||||
logger.debug("*" * 80)
|
|
||||||
logger.debug("Configuration options gathered from config file:")
|
return app
|
||||||
logger.debug(conf_file)
|
|
||||||
logger.debug("================================================")
|
|
||||||
items = dict([(k, v) for k, v in conf.items()
|
|
||||||
if k not in ('__file__', 'here')])
|
|
||||||
for key, value in sorted(items.items()):
|
|
||||||
logger.debug("%(key)-30s %(value)s" % locals())
|
|
||||||
logger.debug("*" * 80)
|
|
||||||
app = deploy.loadapp("config:%s" % conf_file, name=app_name)
|
|
||||||
except (LookupError, ImportError), e:
|
except (LookupError, ImportError), e:
|
||||||
raise RuntimeError("Unable to load %(app_name)s from "
|
raise RuntimeError("Unable to load %(app_name)s from "
|
||||||
"configuration file %(conf_file)s."
|
"configuration file %(conf_file)s."
|
||||||
"\nGot: %(e)r" % locals())
|
"\nGot: %(e)r" % locals())
|
||||||
return conf, app
|
|
||||||
|
|
||||||
|
|
||||||
def get_option(options, option, **kwargs):
|
|
||||||
if option in options:
|
|
||||||
value = options[option]
|
|
||||||
type_ = kwargs.get('type', 'str')
|
|
||||||
if type_ == 'bool':
|
|
||||||
if hasattr(value, 'lower'):
|
|
||||||
return value.lower() == 'true'
|
|
||||||
else:
|
|
||||||
return value
|
|
||||||
elif type_ == 'int':
|
|
||||||
return int(value)
|
|
||||||
elif type_ == 'float':
|
|
||||||
return float(value)
|
|
||||||
else:
|
|
||||||
return value
|
|
||||||
elif 'default' in kwargs:
|
|
||||||
return kwargs['default']
|
|
||||||
else:
|
|
||||||
raise KeyError("option '%s' not found" % option)
|
|
||||||
|
@ -14,7 +14,8 @@
|
|||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
from glance.common import config
|
|
||||||
|
from glance.common import cfg
|
||||||
from glance.common import exception
|
from glance.common import exception
|
||||||
from glance.common import utils
|
from glance.common import utils
|
||||||
from glance.common import wsgi
|
from glance.common import wsgi
|
||||||
@ -53,26 +54,29 @@ class RequestContext(object):
|
|||||||
|
|
||||||
|
|
||||||
class ContextMiddleware(wsgi.Middleware):
|
class ContextMiddleware(wsgi.Middleware):
|
||||||
def __init__(self, app, conf):
|
|
||||||
|
opts = [
|
||||||
|
cfg.BoolOpt('owner_is_tenant', default=True),
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, app, conf, **local_conf):
|
||||||
self.conf = conf
|
self.conf = conf
|
||||||
|
self.conf.register_opts(self.opts)
|
||||||
|
|
||||||
|
# Determine the context class to use
|
||||||
|
self.ctxcls = RequestContext
|
||||||
|
if 'context_class' in local_conf:
|
||||||
|
self.ctxcls = utils.import_class(local_conf['context_class'])
|
||||||
|
|
||||||
super(ContextMiddleware, self).__init__(app)
|
super(ContextMiddleware, self).__init__(app)
|
||||||
|
|
||||||
def make_context(self, *args, **kwargs):
|
def make_context(self, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Create a context with the given arguments.
|
Create a context with the given arguments.
|
||||||
"""
|
"""
|
||||||
|
kwargs.setdefault('owner_is_tenant', self.conf.owner_is_tenant)
|
||||||
|
|
||||||
# Determine the context class to use
|
return self.ctxcls(*args, **kwargs)
|
||||||
ctxcls = RequestContext
|
|
||||||
if 'context_class' in self.conf:
|
|
||||||
ctxcls = utils.import_class(self.conf['context_class'])
|
|
||||||
|
|
||||||
# Determine whether to use tenant or owner
|
|
||||||
owner_is_tenant = config.get_option(self.conf, 'owner_is_tenant',
|
|
||||||
type='bool', default=True)
|
|
||||||
kwargs.setdefault('owner_is_tenant', owner_is_tenant)
|
|
||||||
|
|
||||||
return ctxcls(*args, **kwargs)
|
|
||||||
|
|
||||||
def process_request(self, req):
|
def process_request(self, req):
|
||||||
"""
|
"""
|
||||||
|
@ -22,7 +22,7 @@ import uuid
|
|||||||
|
|
||||||
import kombu.connection
|
import kombu.connection
|
||||||
|
|
||||||
from glance.common import config
|
from glance.common import cfg
|
||||||
from glance.common import exception
|
from glance.common import exception
|
||||||
|
|
||||||
|
|
||||||
@ -61,33 +61,29 @@ class LoggingStrategy(object):
|
|||||||
class RabbitStrategy(object):
|
class RabbitStrategy(object):
|
||||||
"""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_topic', default='glance_notifications')
|
||||||
|
]
|
||||||
|
|
||||||
def __init__(self, conf):
|
def __init__(self, conf):
|
||||||
"""Initialize the rabbit notification strategy."""
|
"""Initialize the rabbit notification strategy."""
|
||||||
self._conf = conf
|
self._conf = conf
|
||||||
host = self._get_option('rabbit_host', 'str', 'localhost')
|
self._conf.register_opts(self.opts)
|
||||||
port = self._get_option('rabbit_port', 'int', 5672)
|
|
||||||
use_ssl = self._get_option('rabbit_use_ssl', 'bool', False)
|
|
||||||
userid = self._get_option('rabbit_userid', 'str', 'guest')
|
|
||||||
password = self._get_option('rabbit_password', 'str', 'guest')
|
|
||||||
virtual_host = self._get_option('rabbit_virtual_host', 'str', '/')
|
|
||||||
|
|
||||||
self.connection = kombu.connection.BrokerConnection(
|
self.connection = kombu.connection.BrokerConnection(
|
||||||
hostname=host,
|
hostname=self._conf.rabbit_host,
|
||||||
userid=userid,
|
userid=self._conf.rabbit_userid,
|
||||||
password=password,
|
password=self._conf.rabbit_password,
|
||||||
virtual_host=virtual_host,
|
virtual_host=self._conf.rabbit_virtual_host,
|
||||||
ssl=use_ssl)
|
ssl=self._conf.rabbit_use_ssl)
|
||||||
|
|
||||||
self.topic = self._get_option('rabbit_notification_topic',
|
self.topic = self._conf.rabbit_notification_topic
|
||||||
'str',
|
|
||||||
'glance_notifications')
|
|
||||||
|
|
||||||
def _get_option(self, name, datatype, default):
|
|
||||||
"""Retrieve a configuration option."""
|
|
||||||
return config.get_option(self._conf,
|
|
||||||
name,
|
|
||||||
type=datatype,
|
|
||||||
default=default)
|
|
||||||
|
|
||||||
def _send_message(self, message, priority):
|
def _send_message(self, message, priority):
|
||||||
topic = "%s.%s" % (self.topic, priority)
|
topic = "%s.%s" % (self.topic, priority)
|
||||||
@ -115,9 +111,13 @@ class Notifier(object):
|
|||||||
"default": NoopStrategy,
|
"default": NoopStrategy,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
opts = [
|
||||||
|
cfg.StrOpt('notifier_strategy', default='default')
|
||||||
|
]
|
||||||
|
|
||||||
def __init__(self, conf, strategy=None):
|
def __init__(self, conf, strategy=None):
|
||||||
strategy = config.get_option(conf, "notifier_strategy",
|
conf.register_opts(self.opts)
|
||||||
type="str", default="default")
|
strategy = conf.notifier_strategy
|
||||||
try:
|
try:
|
||||||
self.strategy = self.STRATEGIES[strategy](conf)
|
self.strategy = self.STRATEGIES[strategy](conf)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -31,15 +31,29 @@ import time
|
|||||||
import eventlet
|
import eventlet
|
||||||
from eventlet.green import socket, ssl
|
from eventlet.green import socket, ssl
|
||||||
import eventlet.wsgi
|
import eventlet.wsgi
|
||||||
|
from paste import deploy
|
||||||
import routes
|
import routes
|
||||||
import routes.middleware
|
import routes.middleware
|
||||||
import webob.dec
|
import webob.dec
|
||||||
import webob.exc
|
import webob.exc
|
||||||
|
|
||||||
|
from glance.common import cfg
|
||||||
from glance.common import exception
|
from glance.common import exception
|
||||||
from glance.common import utils
|
from glance.common import utils
|
||||||
|
|
||||||
|
|
||||||
|
bind_opts = [
|
||||||
|
cfg.StrOpt('bind_host', default='0.0.0.0'),
|
||||||
|
cfg.IntOpt('bind_port'),
|
||||||
|
]
|
||||||
|
|
||||||
|
socket_opts = [
|
||||||
|
cfg.IntOpt('backlog', default=4096),
|
||||||
|
cfg.StrOpt('cert_file'),
|
||||||
|
cfg.StrOpt('key_file'),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class WritableLogger(object):
|
class WritableLogger(object):
|
||||||
"""A thin wrapper that responds to `write` and logs."""
|
"""A thin wrapper that responds to `write` and logs."""
|
||||||
|
|
||||||
@ -51,30 +65,37 @@ class WritableLogger(object):
|
|||||||
self.logger.log(self.level, msg.strip("\n"))
|
self.logger.log(self.level, msg.strip("\n"))
|
||||||
|
|
||||||
|
|
||||||
def get_socket(host, port, conf):
|
def get_bind_addr(conf, default_port=None):
|
||||||
|
"""Return the host and port to bind to."""
|
||||||
|
conf.register_opts(bind_opts)
|
||||||
|
return (conf.bind_host, conf.bind_port or default_port)
|
||||||
|
|
||||||
|
|
||||||
|
def get_socket(conf, default_port):
|
||||||
"""
|
"""
|
||||||
Bind socket to bind ip:port in conf
|
Bind socket to bind ip:port in conf
|
||||||
|
|
||||||
note: Mostly comes from Swift with a few small changes...
|
note: Mostly comes from Swift with a few small changes...
|
||||||
|
|
||||||
:param host: Host to bind to
|
:param conf: a cfg.ConfigOpts object
|
||||||
:param port: Port to bind to
|
:param default_port: port to bind to if none is specified in conf
|
||||||
:param conf: Configuration dict to read settings from
|
|
||||||
|
|
||||||
:returns : a socket object as returned from socket.listen or
|
:returns : a socket object as returned from socket.listen or
|
||||||
ssl.wrap_socket if conf specifies cert_file
|
ssl.wrap_socket if conf specifies cert_file
|
||||||
"""
|
"""
|
||||||
bind_addr = (host, port)
|
bind_addr = get_bind_addr(conf, default_port)
|
||||||
|
|
||||||
# TODO(jaypipes): eventlet's greened socket module does not actually
|
# TODO(jaypipes): eventlet's greened socket module does not actually
|
||||||
# support IPv6 in getaddrinfo(). We need to get around this in the
|
# support IPv6 in getaddrinfo(). We need to get around this in the
|
||||||
# future or monitor upstream for a fix
|
# future or monitor upstream for a fix
|
||||||
address_family = [addr[0] for addr in socket.getaddrinfo(bind_addr[0],
|
address_family = [addr[0] for addr in socket.getaddrinfo(bind_addr[0],
|
||||||
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]
|
||||||
backlog = int(conf.get('backlog', 4096))
|
|
||||||
|
|
||||||
cert_file = conf.get('cert_file')
|
conf.register_opts(socket_opts)
|
||||||
key_file = conf.get('key_file')
|
|
||||||
|
cert_file = conf.cert_file
|
||||||
|
key_file = conf.key_file
|
||||||
use_ssl = cert_file or key_file
|
use_ssl = cert_file or key_file
|
||||||
if use_ssl and (not cert_file or not key_file):
|
if use_ssl and (not cert_file or not key_file):
|
||||||
raise RuntimeError(_("When running server in SSL mode, you must "
|
raise RuntimeError(_("When running server in SSL mode, you must "
|
||||||
@ -85,7 +106,7 @@ def get_socket(host, port, conf):
|
|||||||
retry_until = time.time() + 30
|
retry_until = time.time() + 30
|
||||||
while not sock and time.time() < retry_until:
|
while not sock and time.time() < retry_until:
|
||||||
try:
|
try:
|
||||||
sock = eventlet.listen(bind_addr, backlog=backlog,
|
sock = eventlet.listen(bind_addr, backlog=conf.backlog,
|
||||||
family=address_family)
|
family=address_family)
|
||||||
if use_ssl:
|
if use_ssl:
|
||||||
sock = ssl.wrap_socket(sock, certfile=cert_file,
|
sock = ssl.wrap_socket(sock, certfile=cert_file,
|
||||||
@ -114,17 +135,15 @@ class Server(object):
|
|||||||
def __init__(self, threads=1000):
|
def __init__(self, threads=1000):
|
||||||
self.pool = eventlet.GreenPool(threads)
|
self.pool = eventlet.GreenPool(threads)
|
||||||
|
|
||||||
def start(self, application, port, host='0.0.0.0', conf=None):
|
def start(self, application, conf, default_port):
|
||||||
"""
|
"""
|
||||||
Run a WSGI server with the given application.
|
Run a WSGI server with the given application.
|
||||||
|
|
||||||
:param application: The application to run in the WSGI server
|
:param application: The application to run in the WSGI server
|
||||||
:param port: Port to bind to
|
:param conf: a cfg.ConfigOpts object
|
||||||
:param host: Host to bind to
|
:param default_port: Port to bind to if none is specified in conf
|
||||||
:param conf: Mapping of configuration options
|
|
||||||
"""
|
"""
|
||||||
conf = conf or {}
|
socket = get_socket(conf, default_port)
|
||||||
socket = get_socket(host, port, conf)
|
|
||||||
self.pool.spawn_n(self._run, application, socket)
|
self.pool.spawn_n(self._run, application, socket)
|
||||||
|
|
||||||
def wait(self):
|
def wait(self):
|
||||||
@ -409,11 +428,45 @@ class Resource(object):
|
|||||||
return args
|
return args
|
||||||
|
|
||||||
|
|
||||||
def _import_factory(conf, key):
|
class BasePasteFactory(object):
|
||||||
return utils.import_class(conf[key].replace(':', '.').strip())
|
|
||||||
|
"""A base class for paste app and filter factories.
|
||||||
|
|
||||||
|
Sub-classes must override the KEY class attribute and provide
|
||||||
|
a __call__ method.
|
||||||
|
"""
|
||||||
|
|
||||||
|
KEY = None
|
||||||
|
|
||||||
|
def __init__(self, conf):
|
||||||
|
self.conf = conf
|
||||||
|
|
||||||
|
def __call__(self, global_conf, **local_conf):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def _import_factory(self, local_conf):
|
||||||
|
"""Import an app/filter class.
|
||||||
|
|
||||||
|
Lookup the KEY from the PasteDeploy local conf and import the
|
||||||
|
class named there. This class can then be used as an app or
|
||||||
|
filter factory.
|
||||||
|
|
||||||
|
Note we support the <module>:<class> format.
|
||||||
|
|
||||||
|
Note also that if you do e.g.
|
||||||
|
|
||||||
|
key =
|
||||||
|
value
|
||||||
|
|
||||||
|
then ConfigParser returns a value with a leading newline, so
|
||||||
|
we strip() the value before using it.
|
||||||
|
"""
|
||||||
|
class_name = local_conf[self.KEY].replace(':', '.').strip()
|
||||||
|
return utils.import_class(class_name)
|
||||||
|
|
||||||
|
|
||||||
def app_factory(global_conf, **local_conf):
|
class AppFactory(BasePasteFactory):
|
||||||
|
|
||||||
"""A Generic paste.deploy app factory.
|
"""A Generic paste.deploy app factory.
|
||||||
|
|
||||||
This requires glance.app_factory to be set to a callable which returns a
|
This requires glance.app_factory to be set to a callable which returns a
|
||||||
@ -423,18 +476,20 @@ def app_factory(global_conf, **local_conf):
|
|||||||
paste.app_factory = glance.common.wsgi:app_factory
|
paste.app_factory = glance.common.wsgi:app_factory
|
||||||
glance.app_factory = glance.api.v1:API
|
glance.app_factory = glance.api.v1:API
|
||||||
|
|
||||||
The WSGI app constructor must accept a configuration dict as its only
|
The WSGI app constructor must accept a ConfigOpts object and a local config
|
||||||
argument.
|
dict as its two arguments.
|
||||||
"""
|
"""
|
||||||
factory = _import_factory(local_conf, 'glance.app_factory')
|
|
||||||
|
|
||||||
conf = global_conf.copy()
|
KEY = 'glance.app_factory'
|
||||||
conf.update(local_conf)
|
|
||||||
|
|
||||||
return factory(conf)
|
def __call__(self, global_conf, **local_conf):
|
||||||
|
"""The actual paste.app_factory protocol method."""
|
||||||
|
factory = self._import_factory(local_conf)
|
||||||
|
return factory(self.conf, **local_conf)
|
||||||
|
|
||||||
|
|
||||||
def filter_factory(global_conf, **local_conf):
|
class FilterFactory(AppFactory):
|
||||||
|
|
||||||
"""A Generic paste.deploy filter factory.
|
"""A Generic paste.deploy filter factory.
|
||||||
|
|
||||||
This requires glance.filter_factory to be set to a callable which returns a
|
This requires glance.filter_factory to be set to a callable which returns a
|
||||||
@ -444,15 +499,66 @@ def filter_factory(global_conf, **local_conf):
|
|||||||
paste.filter_factory = glance.common.wsgi:filter_factory
|
paste.filter_factory = glance.common.wsgi:filter_factory
|
||||||
glance.filter_factory = glance.api.middleware.cache:CacheFilter
|
glance.filter_factory = glance.api.middleware.cache:CacheFilter
|
||||||
|
|
||||||
The WSGI filter constructor must accept a WSGI app and a configuration dict
|
The WSGI filter constructor must accept a WSGI app, a ConfigOpts object and
|
||||||
as its only two arguments.
|
a local config dict as its three arguments.
|
||||||
"""
|
"""
|
||||||
factory = _import_factory(local_conf, 'glance.filter_factory')
|
|
||||||
|
|
||||||
conf = global_conf.copy()
|
KEY = 'glance.filter_factory'
|
||||||
conf.update(local_conf)
|
|
||||||
|
def __call__(self, global_conf, **local_conf):
|
||||||
|
"""The actual paste.filter_factory protocol method."""
|
||||||
|
factory = self._import_factory(local_conf)
|
||||||
|
|
||||||
def filter(app):
|
def filter(app):
|
||||||
return factory(app, conf)
|
return factory(app, self.conf, **local_conf)
|
||||||
|
|
||||||
return filter
|
return filter
|
||||||
|
|
||||||
|
|
||||||
|
def setup_paste_factories(conf):
|
||||||
|
"""Set up the generic paste app and filter factories.
|
||||||
|
|
||||||
|
Set things up so that:
|
||||||
|
|
||||||
|
paste.app_factory = glance.common.wsgi:app_factory
|
||||||
|
|
||||||
|
and
|
||||||
|
|
||||||
|
paste.filter_factory = glance.common.wsgi:filter_factory
|
||||||
|
|
||||||
|
work correctly while loading PasteDeploy configuration.
|
||||||
|
|
||||||
|
The app factories are constructed at runtime to allow us to pass a
|
||||||
|
ConfigOpts object to the WSGI classes.
|
||||||
|
|
||||||
|
:param conf: a ConfigOpts object
|
||||||
|
"""
|
||||||
|
global app_factory, filter_factory
|
||||||
|
app_factory = AppFactory(conf)
|
||||||
|
filter_factory = FilterFactory(conf)
|
||||||
|
|
||||||
|
|
||||||
|
def teardown_paste_factories():
|
||||||
|
"""Reverse the effect of setup_paste_factories()."""
|
||||||
|
global app_factory, filter_factory
|
||||||
|
del app_factory
|
||||||
|
del filter_factory
|
||||||
|
|
||||||
|
|
||||||
|
def paste_deploy_app(paste_config_file, app_name, conf):
|
||||||
|
"""Load a WSGI app from a PasteDeploy configuration.
|
||||||
|
|
||||||
|
Use deploy.loadapp() to load the app from the PasteDeploy configuration,
|
||||||
|
ensuring that the supplied ConfigOpts object is passed to the app and
|
||||||
|
filter constructors.
|
||||||
|
|
||||||
|
:param paste_config_file: a PasteDeploy config file
|
||||||
|
:param app_name: the name of the app/pipeline to load from the file
|
||||||
|
:param conf: a ConfigOpts object to supply to the app and its filters
|
||||||
|
:returns: the WSGI app
|
||||||
|
"""
|
||||||
|
setup_paste_factories(conf)
|
||||||
|
try:
|
||||||
|
return deploy.loadapp("config:%s" % paste_config_file, name=app_name)
|
||||||
|
finally:
|
||||||
|
teardown_paste_factories()
|
||||||
|
@ -22,7 +22,7 @@ LRU Cache for Image Data
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from glance.common import config
|
from glance.common import cfg
|
||||||
from glance.common import exception
|
from glance.common import exception
|
||||||
from glance.common import utils
|
from glance.common import utils
|
||||||
|
|
||||||
@ -34,15 +34,23 @@ 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):
|
||||||
"""
|
"""
|
||||||
Create the driver for the cache
|
Create the driver for the cache
|
||||||
"""
|
"""
|
||||||
driver_name = self.conf.get('image_cache_driver', 'sqlite')
|
driver_name = self.conf.image_cache_driver
|
||||||
driver_module = (__name__ + '.drivers.' + driver_name + '.Driver')
|
driver_module = (__name__ + '.drivers.' + driver_name + '.Driver')
|
||||||
try:
|
try:
|
||||||
self.driver_class = utils.import_class(driver_module)
|
self.driver_class = utils.import_class(driver_module)
|
||||||
@ -150,8 +158,7 @@ class ImageCache(object):
|
|||||||
size. Returns a tuple containing the total number of cached
|
size. Returns a tuple containing the total number of cached
|
||||||
files removed and the total size of all pruned image files.
|
files removed and the total size of all pruned image files.
|
||||||
"""
|
"""
|
||||||
max_size = int(self.conf.get('image_cache_max_size',
|
max_size = self.conf.image_cache_max_size
|
||||||
DEFAULT_MAX_CACHE_SIZE))
|
|
||||||
current_size = self.driver.get_cache_size()
|
current_size = self.driver.get_cache_size()
|
||||||
if max_size > current_size:
|
if max_size > current_size:
|
||||||
logger.debug(_("Image cache has free space, skipping prune..."))
|
logger.debug(_("Image cache has free space, skipping prune..."))
|
||||||
@ -180,12 +187,12 @@ class ImageCache(object):
|
|||||||
"%(total_bytes_pruned)d.") % locals())
|
"%(total_bytes_pruned)d.") % locals())
|
||||||
return total_files_pruned, total_bytes_pruned
|
return total_files_pruned, total_bytes_pruned
|
||||||
|
|
||||||
def clean(self):
|
def clean(self, stall_time=None):
|
||||||
"""
|
"""
|
||||||
Cleans up any invalid or incomplete cached images. The cache driver
|
Cleans up any invalid or incomplete cached images. The cache driver
|
||||||
decides what that means...
|
decides what that means...
|
||||||
"""
|
"""
|
||||||
self.driver.clean()
|
self.driver.clean(stall_time)
|
||||||
|
|
||||||
def queue_image(self, image_id):
|
def queue_image(self, image_id):
|
||||||
"""
|
"""
|
||||||
|
@ -27,7 +27,7 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class Cleaner(object):
|
class Cleaner(object):
|
||||||
def __init__(self, conf):
|
def __init__(self, conf, **local_conf):
|
||||||
self.conf = conf
|
self.conf = conf
|
||||||
self.cache = ImageCache(conf)
|
self.cache = ImageCache(conf)
|
||||||
|
|
||||||
|
@ -60,11 +60,9 @@ class Driver(object):
|
|||||||
Creates all necessary directories under the base cache directory
|
Creates all necessary directories under the base cache directory
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
self.base_dir = self.conf.image_cache_dir
|
||||||
key = 'image_cache_dir'
|
if self.base_dir is None:
|
||||||
self.base_dir = self.conf[key]
|
msg = _('Failed to read %s from config') % 'image_cache_dir'
|
||||||
except KeyError:
|
|
||||||
msg = _('Failed to read %s from config') % key
|
|
||||||
logger.error(msg)
|
logger.error(msg)
|
||||||
driver = self.__class__.__module__
|
driver = self.__class__.__module__
|
||||||
raise exception.BadDriverConfiguration(driver_name=driver,
|
raise exception.BadDriverConfiguration(driver_name=driver,
|
||||||
@ -168,7 +166,7 @@ class Driver(object):
|
|||||||
:param image_id: Image ID
|
:param image_id: Image ID
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def clean(self):
|
def clean(self, stall_time=None):
|
||||||
"""
|
"""
|
||||||
Dependent on the driver, clean up and destroy any invalid or incomplete
|
Dependent on the driver, clean up and destroy any invalid or incomplete
|
||||||
cached images
|
cached images
|
||||||
|
@ -31,13 +31,12 @@ import time
|
|||||||
from eventlet import sleep, timeout
|
from eventlet import sleep, timeout
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
|
||||||
|
from glance.common import cfg
|
||||||
from glance.common import exception
|
from glance.common import exception
|
||||||
from glance.image_cache.drivers import base
|
from glance.image_cache.drivers import base
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
DEFAULT_SQL_CALL_TIMEOUT = 2
|
DEFAULT_SQL_CALL_TIMEOUT = 2
|
||||||
DEFAULT_STALL_TIME = 86400 # 24 hours
|
|
||||||
DEFAULT_SQLITE_DB = 'cache.db'
|
|
||||||
|
|
||||||
|
|
||||||
class SqliteConnection(sqlite3.Connection):
|
class SqliteConnection(sqlite3.Connection):
|
||||||
@ -82,6 +81,10 @@ 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
|
||||||
@ -91,11 +94,13 @@ 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()
|
||||||
|
|
||||||
def initialize_db(self):
|
def initialize_db(self):
|
||||||
db = self.conf.get('image_cache_sqlite_db', DEFAULT_SQLITE_DB)
|
db = self.conf.image_cache_sqlite_db
|
||||||
self.db_path = os.path.join(self.base_dir, db)
|
self.db_path = os.path.join(self.base_dir, db)
|
||||||
try:
|
try:
|
||||||
conn = sqlite3.connect(self.db_path, check_same_thread=False,
|
conn = sqlite3.connect(self.db_path, check_same_thread=False,
|
||||||
@ -244,7 +249,7 @@ class Driver(base.Driver):
|
|||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
os.unlink(path)
|
os.unlink(path)
|
||||||
|
|
||||||
def clean(self):
|
def clean(self, stall_time=None):
|
||||||
"""
|
"""
|
||||||
Delete any image files in the invalid directory and any
|
Delete any image files in the invalid directory and any
|
||||||
files in the incomplete directory that are older than a
|
files in the incomplete directory that are older than a
|
||||||
@ -252,10 +257,11 @@ class Driver(base.Driver):
|
|||||||
"""
|
"""
|
||||||
self.delete_invalid_files()
|
self.delete_invalid_files()
|
||||||
|
|
||||||
incomplete_stall_time = int(self.conf.get('image_cache_stall_time',
|
if stall_time is None:
|
||||||
DEFAULT_STALL_TIME))
|
stall_time = self.conf.image_cache_stall_time
|
||||||
|
|
||||||
now = time.time()
|
now = time.time()
|
||||||
older_than = now - incomplete_stall_time
|
older_than = now - stall_time
|
||||||
self.delete_stalled_files(older_than)
|
self.delete_stalled_files(older_than)
|
||||||
|
|
||||||
def get_least_recently_accessed(self):
|
def get_least_recently_accessed(self):
|
||||||
|
@ -70,8 +70,6 @@ from glance.image_cache.drivers import base
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
DEFAULT_STALL_TIME = 86400 # 24 hours
|
|
||||||
|
|
||||||
|
|
||||||
class Driver(base.Driver):
|
class Driver(base.Driver):
|
||||||
|
|
||||||
@ -416,7 +414,7 @@ class Driver(base.Driver):
|
|||||||
return self._reap_old_files(self.incomplete_dir, 'stalled',
|
return self._reap_old_files(self.incomplete_dir, 'stalled',
|
||||||
grace=grace)
|
grace=grace)
|
||||||
|
|
||||||
def clean(self):
|
def clean(self, stall_time=None):
|
||||||
"""
|
"""
|
||||||
Delete any image files in the invalid directory and any
|
Delete any image files in the invalid directory and any
|
||||||
files in the incomplete directory that are older than a
|
files in the incomplete directory that are older than a
|
||||||
@ -424,9 +422,10 @@ class Driver(base.Driver):
|
|||||||
"""
|
"""
|
||||||
self.reap_invalid()
|
self.reap_invalid()
|
||||||
|
|
||||||
incomplete_stall_time = int(self.conf.get('image_cache_stall_time',
|
if stall_time is None:
|
||||||
DEFAULT_STALL_TIME))
|
stall_time = self.conf.image_cache_stall_time
|
||||||
self.reap_stalled(incomplete_stall_time)
|
|
||||||
|
self.reap_stalled(stall_time)
|
||||||
|
|
||||||
|
|
||||||
def get_all_regular_files(basepath):
|
def get_all_regular_files(basepath):
|
||||||
|
@ -23,8 +23,6 @@ import logging
|
|||||||
|
|
||||||
import eventlet
|
import eventlet
|
||||||
|
|
||||||
from glance.common import config
|
|
||||||
from glance.common import context
|
|
||||||
from glance.common import exception
|
from glance.common import exception
|
||||||
from glance.image_cache import ImageCache
|
from glance.image_cache import ImageCache
|
||||||
from glance import registry
|
from glance import registry
|
||||||
@ -42,16 +40,15 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
class Prefetcher(object):
|
class Prefetcher(object):
|
||||||
|
|
||||||
def __init__(self, conf):
|
def __init__(self, conf, **local_conf):
|
||||||
self.conf = conf
|
self.conf = conf
|
||||||
glance.store.create_stores(conf)
|
glance.store.create_stores(conf)
|
||||||
self.cache = ImageCache(conf)
|
self.cache = ImageCache(conf)
|
||||||
registry.configure_registry_client(conf)
|
registry.configure_registry_client(conf)
|
||||||
|
|
||||||
def fetch_image_into_cache(self, image_id):
|
def fetch_image_into_cache(self, image_id):
|
||||||
auth_tok = self.conf.get('admin_token')
|
ctx = registry.get_client_context(self.conf,
|
||||||
ctx = context.RequestContext(is_admin=True, show_deleted=True,
|
is_admin=True, show_deleted=True)
|
||||||
auth_tok=auth_tok)
|
|
||||||
try:
|
try:
|
||||||
image_meta = registry.get_image_metadata(ctx, image_id)
|
image_meta = registry.get_image_metadata(ctx, image_id)
|
||||||
if image_meta['status'] != 'active':
|
if image_meta['status'] != 'active':
|
||||||
|
@ -27,7 +27,7 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class Pruner(object):
|
class Pruner(object):
|
||||||
def __init__(self, conf):
|
def __init__(self, conf, **local_conf):
|
||||||
self.conf = conf
|
self.conf = conf
|
||||||
self.cache = ImageCache(conf)
|
self.cache = ImageCache(conf)
|
||||||
|
|
||||||
|
@ -23,8 +23,6 @@ import logging
|
|||||||
|
|
||||||
import eventlet
|
import eventlet
|
||||||
|
|
||||||
from glance.common import config
|
|
||||||
from glance.common import context
|
|
||||||
from glance.common import exception
|
from glance.common import exception
|
||||||
from glance.image_cache import ImageCache
|
from glance.image_cache import ImageCache
|
||||||
from glance import registry
|
from glance import registry
|
||||||
@ -35,15 +33,14 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
class Queuer(object):
|
class Queuer(object):
|
||||||
|
|
||||||
def __init__(self, conf):
|
def __init__(self, conf, **local_conf):
|
||||||
self.conf = conf
|
self.conf = conf
|
||||||
self.cache = ImageCache(conf)
|
self.cache = ImageCache(conf)
|
||||||
registry.configure_registry_client(conf)
|
registry.configure_registry_client(conf)
|
||||||
|
|
||||||
def queue_image(self, image_id):
|
def queue_image(self, image_id):
|
||||||
auth_tok = self.conf.get('admin_token')
|
ctx = \
|
||||||
ctx = context.RequestContext(is_admin=True, show_deleted=True,
|
registry.get_client_context(conf, is_admin=True, show_deleted=True)
|
||||||
auth_tok=auth_tok)
|
|
||||||
try:
|
try:
|
||||||
image_meta = registry.get_image_metadata(ctx, image_id)
|
image_meta = registry.get_image_metadata(ctx, image_id)
|
||||||
if image_meta['status'] != 'active':
|
if image_meta['status'] != 'active':
|
||||||
|
@ -21,7 +21,7 @@ Registry API
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from glance.common import config
|
from glance.common import cfg
|
||||||
from glance.common import exception
|
from glance.common import exception
|
||||||
from glance.registry import client
|
from glance.registry import client
|
||||||
|
|
||||||
@ -34,6 +34,25 @@ _CLIENT_KWARGS = {}
|
|||||||
_METADATA_ENCRYPTION_KEY = None
|
_METADATA_ENCRYPTION_KEY = None
|
||||||
|
|
||||||
|
|
||||||
|
registry_addr_opts = [
|
||||||
|
cfg.StrOpt('registry_host', default='0.0.0.0'),
|
||||||
|
cfg.IntOpt('registry_port', default=9191),
|
||||||
|
]
|
||||||
|
registry_client_opts = [
|
||||||
|
cfg.StrOpt('registry_client_protocol', default='http'),
|
||||||
|
cfg.StrOpt('registry_client_key_file'),
|
||||||
|
cfg.StrOpt('registry_client_cert_file'),
|
||||||
|
cfg.StrOpt('registry_client_ca_file'),
|
||||||
|
cfg.StrOpt('metadata_encryption_key'),
|
||||||
|
]
|
||||||
|
admin_token_opt = cfg.StrOpt('admin_token')
|
||||||
|
|
||||||
|
|
||||||
|
def get_registry_addr(conf):
|
||||||
|
conf.register_opts(registry_addr_opts)
|
||||||
|
return (conf.registry_host, conf.registry_port)
|
||||||
|
|
||||||
|
|
||||||
def configure_registry_client(conf):
|
def configure_registry_client(conf):
|
||||||
"""
|
"""
|
||||||
Sets up a registry client for use in registry lookups
|
Sets up a registry client for use in registry lookups
|
||||||
@ -42,9 +61,8 @@ def configure_registry_client(conf):
|
|||||||
"""
|
"""
|
||||||
global _CLIENT_KWARGS, _CLIENT_HOST, _CLIENT_PORT, _METADATA_ENCRYPTION_KEY
|
global _CLIENT_KWARGS, _CLIENT_HOST, _CLIENT_PORT, _METADATA_ENCRYPTION_KEY
|
||||||
try:
|
try:
|
||||||
host = conf['registry_host']
|
host, port = get_registry_addr(conf)
|
||||||
port = int(conf['registry_port'])
|
except cfg.ConfigFileValueError:
|
||||||
except (TypeError, ValueError):
|
|
||||||
msg = _("Configuration option was not valid")
|
msg = _("Configuration option was not valid")
|
||||||
logger.error(msg)
|
logger.error(msg)
|
||||||
raise exception.BadRegistryConnectionConfiguration(msg)
|
raise exception.BadRegistryConnectionConfiguration(msg)
|
||||||
@ -53,18 +71,23 @@ def configure_registry_client(conf):
|
|||||||
logger.error(msg)
|
logger.error(msg)
|
||||||
raise exception.BadRegistryConnectionConfiguration(msg)
|
raise exception.BadRegistryConnectionConfiguration(msg)
|
||||||
|
|
||||||
use_ssl = config.get_option(conf, 'registry_client_protocol',
|
conf.register_opts(registry_client_opts)
|
||||||
default='http').lower() == 'https'
|
|
||||||
key_file = conf.get('registry_client_key_file')
|
|
||||||
cert_file = conf.get('registry_client_cert_file')
|
|
||||||
ca_file = conf.get('registry_client_ca_file')
|
|
||||||
_METADATA_ENCRYPTION_KEY = conf.get('metadata_encryption_key')
|
|
||||||
_CLIENT_HOST = host
|
_CLIENT_HOST = host
|
||||||
_CLIENT_PORT = port
|
_CLIENT_PORT = port
|
||||||
_CLIENT_KWARGS = {'use_ssl': use_ssl,
|
_METADATA_ENCRYPTION_KEY = conf.metadata_encryption_key
|
||||||
'key_file': key_file,
|
_CLIENT_KWARGS = {
|
||||||
'cert_file': cert_file,
|
'use_ssl': conf.registry_client_protocol.lower() == 'https',
|
||||||
'ca_file': ca_file}
|
'key_file': conf.registry_client_key_file,
|
||||||
|
'cert_file': conf.registry_client_cert_file,
|
||||||
|
'ca_file': conf.registry_client_ca_file
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_client_context(conf, **kwargs):
|
||||||
|
conf.register_opt(admin_token_opt)
|
||||||
|
from glance.common import context
|
||||||
|
return context.RequestContext(auth_tok=conf.admin_token, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def get_registry_client(cxt):
|
def get_registry_client(cxt):
|
||||||
|
@ -25,7 +25,7 @@ from glance.common import wsgi
|
|||||||
class API(wsgi.Router):
|
class API(wsgi.Router):
|
||||||
"""WSGI entry point for all Registry requests."""
|
"""WSGI entry point for all Registry requests."""
|
||||||
|
|
||||||
def __init__(self, conf):
|
def __init__(self, conf, **local_conf):
|
||||||
mapper = routes.Mapper()
|
mapper = routes.Mapper()
|
||||||
|
|
||||||
images_resource = images.create_resource(conf)
|
images_resource = images.create_resource(conf)
|
||||||
|
@ -23,6 +23,7 @@ import logging
|
|||||||
|
|
||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
|
from glance.common import cfg
|
||||||
from glance.common import exception
|
from glance.common import exception
|
||||||
from glance.common import utils
|
from glance.common import utils
|
||||||
from glance.common import wsgi
|
from glance.common import wsgi
|
||||||
@ -49,8 +50,14 @@ 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):
|
||||||
@ -181,31 +188,15 @@ class Controller(object):
|
|||||||
def _get_limit(self, req):
|
def _get_limit(self, req):
|
||||||
"""Parse a limit query param into something usable."""
|
"""Parse a limit query param into something usable."""
|
||||||
try:
|
try:
|
||||||
default = self.conf['limit_param_default']
|
limit = int(req.str_params.get('limit',
|
||||||
except KeyError:
|
self.conf.limit_param_default))
|
||||||
# if no value is configured, provide a sane default
|
|
||||||
default = 25
|
|
||||||
msg = _("Failed to read limit_param_default from config. "
|
|
||||||
"Defaulting to %s") % default
|
|
||||||
logger.debug(msg)
|
|
||||||
|
|
||||||
try:
|
|
||||||
limit = int(req.str_params.get('limit', default))
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise exc.HTTPBadRequest(_("limit param must be an integer"))
|
raise exc.HTTPBadRequest(_("limit param must be an integer"))
|
||||||
|
|
||||||
if limit < 0:
|
if limit < 0:
|
||||||
raise exc.HTTPBadRequest(_("limit param must be positive"))
|
raise exc.HTTPBadRequest(_("limit param must be positive"))
|
||||||
|
|
||||||
try:
|
return min(self.conf.api_limit_max, limit)
|
||||||
api_limit_max = int(self.conf['api_limit_max'])
|
|
||||||
except (KeyError, ValueError):
|
|
||||||
api_limit_max = 1000
|
|
||||||
msg = _("Failed to read api_limit_max from config. "
|
|
||||||
"Defaulting to %s") % api_limit_max
|
|
||||||
logger.debug(msg)
|
|
||||||
|
|
||||||
return min(api_limit_max, limit)
|
|
||||||
|
|
||||||
def _get_marker(self, req):
|
def _get_marker(self, req):
|
||||||
"""Parse a marker query param into something usable."""
|
"""Parse a marker query param into something usable."""
|
||||||
|
@ -17,23 +17,24 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import optparse
|
from glance.common import cfg
|
||||||
|
|
||||||
|
|
||||||
def add_conf(parser):
|
def add_options(conf):
|
||||||
"""
|
"""
|
||||||
Adds any configuration options that the db layer might have.
|
Adds any configuration options that the db layer might have.
|
||||||
|
|
||||||
:param parser: An optparse.OptionParser object
|
:param conf: A ConfigOpts object
|
||||||
:retval None
|
:retval None
|
||||||
"""
|
"""
|
||||||
help_text = "The following configuration options are specific to the "\
|
conf.add_group(cfg.OptGroup('registrydb',
|
||||||
"Glance image registry database."
|
title='Registry Database Options',
|
||||||
|
help='The following configuration options '
|
||||||
group = optparse.OptionGroup(parser, "Registry Database Options",
|
'are specific to the Glance image '
|
||||||
help_text)
|
'registry database.'))
|
||||||
group.add_option('--sql-connection', metavar="CONNECTION",
|
conf.register_cli_opt(cfg.StrOpt('sql-connection',
|
||||||
default=None,
|
group='registrydb',
|
||||||
help="A valid SQLAlchemy connection string for the "
|
metavar='CONNECTION',
|
||||||
"registry database. Default: %default")
|
help='A valid SQLAlchemy connection '
|
||||||
parser.add_option_group(group)
|
'string for the registry database. '
|
||||||
|
'Default: %default'))
|
||||||
|
@ -31,7 +31,7 @@ from sqlalchemy.orm import joinedload
|
|||||||
from sqlalchemy.orm import sessionmaker
|
from sqlalchemy.orm import sessionmaker
|
||||||
from sqlalchemy.sql import or_, and_
|
from sqlalchemy.sql import or_, and_
|
||||||
|
|
||||||
from glance.common import config
|
from glance.common import cfg
|
||||||
from glance.common import exception
|
from glance.common import exception
|
||||||
from glance.common import utils
|
from glance.common import utils
|
||||||
from glance.registry.db import models
|
from glance.registry.db import models
|
||||||
@ -57,6 +57,11 @@ DISK_FORMATS = ['ami', 'ari', 'aki', 'vhd', 'vmdk', 'raw', 'qcow2', 'vdi',
|
|||||||
STATUSES = ['active', 'saving', 'queued', 'killed', 'pending_delete',
|
STATUSES = ['active', 'saving', 'queued', 'killed', 'pending_delete',
|
||||||
'deleted']
|
'deleted']
|
||||||
|
|
||||||
|
db_opts = [
|
||||||
|
cfg.IntOpt('sql_idle_timeout', default=3600),
|
||||||
|
cfg.StrOpt('sql_connection', default='sqlite:///glance.sqlite'),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def configure_db(conf):
|
def configure_db(conf):
|
||||||
"""
|
"""
|
||||||
@ -67,13 +72,9 @@ def configure_db(conf):
|
|||||||
"""
|
"""
|
||||||
global _ENGINE, sa_logger, logger
|
global _ENGINE, sa_logger, logger
|
||||||
if not _ENGINE:
|
if not _ENGINE:
|
||||||
debug = config.get_option(
|
conf.register_opts(db_opts)
|
||||||
conf, 'debug', type='bool', default=False)
|
timeout = conf.sql_idle_timeout
|
||||||
verbose = config.get_option(
|
sql_connection = conf.sql_connection
|
||||||
conf, 'verbose', type='bool', default=False)
|
|
||||||
timeout = config.get_option(
|
|
||||||
conf, 'sql_idle_timeout', type='int', default=3600)
|
|
||||||
sql_connection = config.get_option(conf, 'sql_connection')
|
|
||||||
try:
|
try:
|
||||||
_ENGINE = create_engine(sql_connection, pool_recycle=timeout)
|
_ENGINE = create_engine(sql_connection, pool_recycle=timeout)
|
||||||
except Exception, err:
|
except Exception, err:
|
||||||
@ -84,9 +85,9 @@ def configure_db(conf):
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
sa_logger = logging.getLogger('sqlalchemy.engine')
|
sa_logger = logging.getLogger('sqlalchemy.engine')
|
||||||
if debug:
|
if conf.debug:
|
||||||
sa_logger.setLevel(logging.DEBUG)
|
sa_logger.setLevel(logging.DEBUG)
|
||||||
elif verbose:
|
elif conf.verbose:
|
||||||
sa_logger.setLevel(logging.INFO)
|
sa_logger.setLevel(logging.INFO)
|
||||||
|
|
||||||
models.register_models(_ENGINE)
|
models.register_models(_ENGINE)
|
||||||
|
@ -40,7 +40,7 @@ def db_version(conf):
|
|||||||
:retval version number
|
:retval version number
|
||||||
"""
|
"""
|
||||||
repo_path = get_migrate_repo_path()
|
repo_path = get_migrate_repo_path()
|
||||||
sql_connection = conf['sql_connection']
|
sql_connection = conf.sql_connection
|
||||||
try:
|
try:
|
||||||
return versioning_api.db_version(sql_connection, repo_path)
|
return versioning_api.db_version(sql_connection, repo_path)
|
||||||
except versioning_exceptions.DatabaseNotControlledError, e:
|
except versioning_exceptions.DatabaseNotControlledError, e:
|
||||||
@ -59,7 +59,7 @@ def upgrade(conf, version=None):
|
|||||||
"""
|
"""
|
||||||
db_version(conf) # Ensure db is under migration control
|
db_version(conf) # Ensure db is under migration control
|
||||||
repo_path = get_migrate_repo_path()
|
repo_path = get_migrate_repo_path()
|
||||||
sql_connection = conf['sql_connection']
|
sql_connection = conf.sql_connection
|
||||||
version_str = version or 'latest'
|
version_str = version or 'latest'
|
||||||
logger.info(_("Upgrading %(sql_connection)s to version %(version_str)s") %
|
logger.info(_("Upgrading %(sql_connection)s to version %(version_str)s") %
|
||||||
locals())
|
locals())
|
||||||
@ -76,7 +76,7 @@ def downgrade(conf, version):
|
|||||||
"""
|
"""
|
||||||
db_version(conf) # Ensure db is under migration control
|
db_version(conf) # Ensure db is under migration control
|
||||||
repo_path = get_migrate_repo_path()
|
repo_path = get_migrate_repo_path()
|
||||||
sql_connection = conf['sql_connection']
|
sql_connection = conf.sql_connection
|
||||||
logger.info(_("Downgrading %(sql_connection)s to version %(version)s") %
|
logger.info(_("Downgrading %(sql_connection)s to version %(version)s") %
|
||||||
locals())
|
locals())
|
||||||
return versioning_api.downgrade(sql_connection, repo_path, version)
|
return versioning_api.downgrade(sql_connection, repo_path, version)
|
||||||
@ -88,7 +88,7 @@ def version_control(conf):
|
|||||||
|
|
||||||
:param conf: conf dict
|
:param conf: conf dict
|
||||||
"""
|
"""
|
||||||
sql_connection = conf['sql_connection']
|
sql_connection = conf.sql_connection
|
||||||
try:
|
try:
|
||||||
_version_control(conf)
|
_version_control(conf)
|
||||||
except versioning_exceptions.DatabaseAlreadyControlledError, e:
|
except versioning_exceptions.DatabaseAlreadyControlledError, e:
|
||||||
@ -104,7 +104,7 @@ def _version_control(conf):
|
|||||||
:param conf: conf dict
|
:param conf: conf dict
|
||||||
"""
|
"""
|
||||||
repo_path = get_migrate_repo_path()
|
repo_path = get_migrate_repo_path()
|
||||||
sql_connection = conf['sql_connection']
|
sql_connection = conf.sql_connection
|
||||||
return versioning_api.version_control(sql_connection, repo_path)
|
return versioning_api.version_control(sql_connection, repo_path)
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ import time
|
|||||||
import urlparse
|
import urlparse
|
||||||
|
|
||||||
from glance import registry
|
from glance import registry
|
||||||
from glance.common import config
|
from glance.common import cfg
|
||||||
from glance.common import exception
|
from glance.common import exception
|
||||||
from glance.common import utils
|
from glance.common import utils
|
||||||
from glance.store import location
|
from glance.store import location
|
||||||
@ -154,13 +154,27 @@ 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):
|
||||||
|
conf.register_opt(scrubber_datadir_opt)
|
||||||
|
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.
|
||||||
"""
|
"""
|
||||||
use_delay = config.get_option(conf, 'delayed_delete', type='bool',
|
conf.register_opts(delete_opts)
|
||||||
default=False)
|
if not conf.delayed_delete:
|
||||||
if not use_delay:
|
|
||||||
registry.update_image_metadata(context, image_id,
|
registry.update_image_metadata(context, image_id,
|
||||||
{'status': 'deleted'})
|
{'status': 'deleted'})
|
||||||
try:
|
try:
|
||||||
@ -169,10 +183,8 @@ def schedule_delete_from_backend(uri, conf, context, image_id, **kwargs):
|
|||||||
msg = _("Failed to delete image from store (%(uri)s).") % locals()
|
msg = _("Failed to delete image from store (%(uri)s).") % locals()
|
||||||
logger.error(msg)
|
logger.error(msg)
|
||||||
|
|
||||||
datadir = config.get_option(conf, 'scrubber_datadir')
|
datadir = get_scrubber_datadir(conf)
|
||||||
scrub_time = config.get_option(conf, 'scrub_time', type='int',
|
delete_time = time.time() + conf.scrub_time
|
||||||
default=0)
|
|
||||||
delete_time = time.time() + scrub_time
|
|
||||||
file_path = os.path.join(datadir, str(image_id))
|
file_path = os.path.join(datadir, str(image_id))
|
||||||
utils.safe_mkdirs(datadir)
|
utils.safe_mkdirs(datadir)
|
||||||
|
|
||||||
|
@ -28,13 +28,13 @@ class Store(object):
|
|||||||
|
|
||||||
CHUNKSIZE = (16 * 1024 * 1024) # 16M
|
CHUNKSIZE = (16 * 1024 * 1024) # 16M
|
||||||
|
|
||||||
def __init__(self, conf=None):
|
def __init__(self, conf):
|
||||||
"""
|
"""
|
||||||
Initialize the Store
|
Initialize the Store
|
||||||
|
|
||||||
:param conf: Optional dictionary of configuration options
|
:param conf: Optional dictionary of configuration options
|
||||||
"""
|
"""
|
||||||
self.conf = conf or {}
|
self.conf = conf
|
||||||
|
|
||||||
self.configure()
|
self.configure()
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ import logging
|
|||||||
import os
|
import os
|
||||||
import urlparse
|
import urlparse
|
||||||
|
|
||||||
|
from glance.common import cfg
|
||||||
from glance.common import exception
|
from glance.common import exception
|
||||||
import glance.store
|
import glance.store
|
||||||
import glance.store.base
|
import glance.store.base
|
||||||
@ -93,6 +94,8 @@ class ChunkedFile(object):
|
|||||||
|
|
||||||
class Store(glance.store.base.Store):
|
class Store(glance.store.base.Store):
|
||||||
|
|
||||||
|
datadir_opt = cfg.StrOpt('filesystem_store_datadir')
|
||||||
|
|
||||||
def configure_add(self):
|
def configure_add(self):
|
||||||
"""
|
"""
|
||||||
Configure the Store to use the stored configuration options
|
Configure the Store to use the stored configuration options
|
||||||
@ -100,7 +103,15 @@ 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.datadir = self._option_get('filesystem_store_datadir')
|
self.conf.register_opt(self.datadir_opt)
|
||||||
|
|
||||||
|
self.datadir = self.conf.filesystem_store_datadir
|
||||||
|
if self.datadir is None:
|
||||||
|
reason = _("Could not find %s in configuration options.") % \
|
||||||
|
'filesystem_store_datadir'
|
||||||
|
logger.error(reason)
|
||||||
|
raise exception.BadStoreConfiguration(store_name="filesystem",
|
||||||
|
reason=reason)
|
||||||
|
|
||||||
if not os.path.exists(self.datadir):
|
if not os.path.exists(self.datadir):
|
||||||
msg = _("Directory to write image files does not exist "
|
msg = _("Directory to write image files does not exist "
|
||||||
@ -114,15 +125,6 @@ class Store(glance.store.base.Store):
|
|||||||
raise exception.BadStoreConfiguration(store_name="filesystem",
|
raise exception.BadStoreConfiguration(store_name="filesystem",
|
||||||
reason=reason)
|
reason=reason)
|
||||||
|
|
||||||
def _option_get(self, param):
|
|
||||||
result = self.conf.get(param)
|
|
||||||
if not result:
|
|
||||||
reason = _("Could not find %s in configuration options.") % param
|
|
||||||
logger.error(reason)
|
|
||||||
raise exception.BadStoreConfiguration(store_name="filesystem",
|
|
||||||
reason=reason)
|
|
||||||
return result
|
|
||||||
|
|
||||||
def get(self, location):
|
def get(self, location):
|
||||||
"""
|
"""
|
||||||
Takes a `glance.store.location.Location` object that indicates
|
Takes a `glance.store.location.Location` object that indicates
|
||||||
|
@ -24,6 +24,7 @@ import hashlib
|
|||||||
import logging
|
import logging
|
||||||
import math
|
import math
|
||||||
|
|
||||||
|
from glance.common import cfg
|
||||||
from glance.common import exception
|
from glance.common import exception
|
||||||
import glance.store
|
import glance.store
|
||||||
import glance.store.base
|
import glance.store.base
|
||||||
@ -100,6 +101,13 @@ 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 configure_add(self):
|
def configure_add(self):
|
||||||
"""
|
"""
|
||||||
Configure the Store to use the stored configuration options
|
Configure the Store to use the stored configuration options
|
||||||
@ -107,20 +115,16 @@ 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 = int(
|
self.chunk_size = self.conf.rbd_store_chunk_size * 1024 * 1024
|
||||||
self.conf.get(
|
|
||||||
'rbd_store_chunk_size',
|
|
||||||
DEFAULT_CHUNKSIZE)) * 1024 * 1024
|
|
||||||
# these must not be unicode since they will be passed to a
|
# these must not be unicode since they will be passed to a
|
||||||
# non-unicode-aware C library
|
# non-unicode-aware C library
|
||||||
self.pool = str(self.conf.get('rbd_store_pool',
|
self.pool = str(self.conf.rbd_store_pool)
|
||||||
DEFAULT_POOL))
|
self.user = str(self.conf.rbd_store_user)
|
||||||
self.user = str(self.conf.get('rbd_store_user',
|
self.conf_file = str(self.conf.rbd_store_ceph_conf)
|
||||||
DEFAULT_USER))
|
except cfg.ConfigFileValueError, e:
|
||||||
self.conf_file = str(self.conf.get('rbd_store_ceph_conf',
|
|
||||||
DEFAULT_CONFFILE))
|
|
||||||
except Exception, e:
|
|
||||||
reason = _("Error in store configuration: %s") % e
|
reason = _("Error in store configuration: %s") % e
|
||||||
logger.error(reason)
|
logger.error(reason)
|
||||||
raise exception.BadStoreConfiguration(store_name='rbd',
|
raise exception.BadStoreConfiguration(store_name='rbd',
|
||||||
|
@ -23,7 +23,7 @@ import httplib
|
|||||||
import tempfile
|
import tempfile
|
||||||
import urlparse
|
import urlparse
|
||||||
|
|
||||||
from glance.common import config
|
from glance.common import cfg
|
||||||
from glance.common import exception
|
from glance.common import exception
|
||||||
import glance.store
|
import glance.store
|
||||||
import glance.store.base
|
import glance.store.base
|
||||||
@ -183,6 +183,15 @@ 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'),
|
||||||
|
cfg.StrOpt('s3_store_secret_key'),
|
||||||
|
cfg.StrOpt('s3_store_bucket'),
|
||||||
|
cfg.StrOpt('s3_store_object_buffer_dir'),
|
||||||
|
cfg.BoolOpt('s3_store_create_bucket_on_put', default=False),
|
||||||
|
]
|
||||||
|
|
||||||
def configure_add(self):
|
def configure_add(self):
|
||||||
"""
|
"""
|
||||||
Configure the Store to use the stored configuration options
|
Configure the Store to use the stored configuration options
|
||||||
@ -190,6 +199,7 @@ 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')
|
||||||
@ -210,14 +220,11 @@ class Store(glance.store.base.Store):
|
|||||||
else: # Defaults http
|
else: # Defaults http
|
||||||
self.full_s3_host = 'http://' + self.s3_host
|
self.full_s3_host = 'http://' + self.s3_host
|
||||||
|
|
||||||
if self.conf.get('s3_store_object_buffer_dir'):
|
self.s3_store_object_buffer_dir = \
|
||||||
self.s3_store_object_buffer_dir = self.conf.get(
|
self.conf.s3_store_object_buffer_dir
|
||||||
's3_store_object_buffer_dir')
|
|
||||||
else:
|
|
||||||
self.s3_store_object_buffer_dir = None
|
|
||||||
|
|
||||||
def _option_get(self, param):
|
def _option_get(self, param):
|
||||||
result = self.conf.get(param)
|
result = getattr(self.conf, param)
|
||||||
if not result:
|
if not result:
|
||||||
reason = _("Could not find %(param)s in configuration "
|
reason = _("Could not find %(param)s in configuration "
|
||||||
"options.") % locals()
|
"options.") % locals()
|
||||||
@ -417,10 +424,7 @@ def create_bucket_if_missing(bucket, s3_conn, conf):
|
|||||||
s3_conn.get_bucket(bucket)
|
s3_conn.get_bucket(bucket)
|
||||||
except S3ResponseError, e:
|
except S3ResponseError, e:
|
||||||
if e.status == httplib.NOT_FOUND:
|
if e.status == httplib.NOT_FOUND:
|
||||||
add_bucket = config.get_option(conf,
|
if conf.s3_store_create_bucket_on_put:
|
||||||
's3_store_create_bucket_on_put',
|
|
||||||
type='bool', default=False)
|
|
||||||
if add_bucket:
|
|
||||||
try:
|
try:
|
||||||
s3_conn.create_bucket(bucket)
|
s3_conn.create_bucket(bucket)
|
||||||
except S3ResponseError, e:
|
except S3ResponseError, e:
|
||||||
|
@ -27,7 +27,7 @@ import glance.store.s3
|
|||||||
import glance.store.swift
|
import glance.store.swift
|
||||||
from glance import registry
|
from glance import registry
|
||||||
from glance import store
|
from glance import store
|
||||||
from glance.common import config
|
from glance.common import cfg
|
||||||
from glance.common import utils
|
from glance.common import utils
|
||||||
from glance.common import exception
|
from glance.common import exception
|
||||||
from glance.registry import context
|
from glance.registry import context
|
||||||
@ -65,22 +65,30 @@ class Daemon(object):
|
|||||||
class Scrubber(object):
|
class Scrubber(object):
|
||||||
CLEANUP_FILE = ".cleanup"
|
CLEANUP_FILE = ".cleanup"
|
||||||
|
|
||||||
def __init__(self, conf):
|
opts = [
|
||||||
logger.info(_("Initializing scrubber with conf: %s") % conf)
|
cfg.BoolOpt('cleanup_scrubber', default=False),
|
||||||
|
cfg.IntOpt('cleanup_scrubber_time', default=86400)
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, conf, **local_conf):
|
||||||
self.conf = conf
|
self.conf = conf
|
||||||
self.datadir = config.get_option(conf, 'scrubber_datadir')
|
self.conf.register_opts(self.opts)
|
||||||
self.cleanup = config.get_option(conf, 'cleanup_scrubber',
|
|
||||||
type='bool', default=False)
|
self.datadir = store.get_scrubber_datadir(conf)
|
||||||
host = config.get_option(conf, 'registry_host')
|
self.cleanup = self.conf.cleanup_scrubber
|
||||||
port = config.get_option(conf, 'registry_port', type='int')
|
self.cleanup_time = self.conf.cleanup_scrubber_time
|
||||||
|
|
||||||
|
host, port = registry.get_registry_addr(conf)
|
||||||
|
|
||||||
|
logger.info(_("Initializing scrubber with conf: %s") %
|
||||||
|
{'datadir': self.datadir, 'cleanup': self.cleanup,
|
||||||
|
'cleanup_time': self.cleanup_time,
|
||||||
|
'registry_host': host, 'registry_port': port})
|
||||||
|
|
||||||
self.registry = client.RegistryClient(host, port)
|
self.registry = client.RegistryClient(host, port)
|
||||||
|
|
||||||
utils.safe_mkdirs(self.datadir)
|
utils.safe_mkdirs(self.datadir)
|
||||||
|
|
||||||
if self.cleanup:
|
|
||||||
self.cleanup_time = config.get_option(conf,
|
|
||||||
'cleanup_scrubber_time',
|
|
||||||
type='int', default=86400)
|
|
||||||
store.create_stores(conf)
|
store.create_stores(conf)
|
||||||
|
|
||||||
def run(self, pool, event=None):
|
def run(self, pool, event=None):
|
||||||
|
@ -26,7 +26,7 @@ import math
|
|||||||
import tempfile
|
import tempfile
|
||||||
import urlparse
|
import urlparse
|
||||||
|
|
||||||
from glance.common import config
|
from glance.common import cfg
|
||||||
from glance.common import exception
|
from glance.common import exception
|
||||||
import glance.store
|
import glance.store
|
||||||
import glance.store.base
|
import glance.store.base
|
||||||
@ -38,8 +38,8 @@ except ImportError:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
DEFAULT_CONTAINER = 'glance'
|
DEFAULT_CONTAINER = 'glance'
|
||||||
DEFAULT_LARGE_OBJECT_SIZE = 5 * 1024 * 1024 * 1024 # 5GB
|
DEFAULT_LARGE_OBJECT_SIZE = 5 * 1024 # 5GB
|
||||||
DEFAULT_LARGE_OBJECT_CHUNK_SIZE = 200 * 1024 * 1024 # 200M
|
DEFAULT_LARGE_OBJECT_CHUNK_SIZE = 200 # 200M
|
||||||
|
|
||||||
logger = logging.getLogger('glance.store.swift')
|
logger = logging.getLogger('glance.store.swift')
|
||||||
|
|
||||||
@ -185,9 +185,24 @@ 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'),
|
||||||
|
cfg.StrOpt('swift_store_key'),
|
||||||
|
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.StrOpt('swift_store_object_buffer_dir'),
|
||||||
|
cfg.BoolOpt('swift_store_create_container_on_put', default=False),
|
||||||
|
]
|
||||||
|
|
||||||
def configure(self):
|
def configure(self):
|
||||||
self.snet = config.get_option(
|
self.conf.register_opts(self.opts)
|
||||||
self.conf, 'swift_enable_snet', type='bool', default=False)
|
self.snet = self.conf.swift_enable_snet
|
||||||
|
|
||||||
def configure_add(self):
|
def configure_add(self):
|
||||||
"""
|
"""
|
||||||
@ -199,29 +214,14 @@ class Store(glance.store.base.Store):
|
|||||||
self.auth_address = self._option_get('swift_store_auth_address')
|
self.auth_address = self._option_get('swift_store_auth_address')
|
||||||
self.user = self._option_get('swift_store_user')
|
self.user = self._option_get('swift_store_user')
|
||||||
self.key = self._option_get('swift_store_key')
|
self.key = self._option_get('swift_store_key')
|
||||||
self.container = self.conf.get('swift_store_container',
|
self.container = self.conf.swift_store_container
|
||||||
DEFAULT_CONTAINER)
|
|
||||||
try:
|
try:
|
||||||
if self.conf.get('swift_store_large_object_size'):
|
self.large_object_size = self.conf.swift_store_large_object_size
|
||||||
self.large_object_size = int(
|
self.large_object_chunk_size = \
|
||||||
self.conf.get('swift_store_large_object_size')
|
self.conf.swift_store_large_object_chunk_size
|
||||||
) * (1024 * 1024) # Size specified in MB in conf files
|
self.swift_store_object_buffer_dir = \
|
||||||
else:
|
self.conf.swift_store_object_buffer_dir
|
||||||
self.large_object_size = DEFAULT_LARGE_OBJECT_SIZE
|
except cfg.ConfigFileValueError, e:
|
||||||
|
|
||||||
if self.conf.get('swift_store_large_object_chunk_size'):
|
|
||||||
self.large_object_chunk_size = int(
|
|
||||||
self.conf.get('swift_store_large_object_chunk_size')
|
|
||||||
) * (1024 * 1024) # Size specified in MB in conf files
|
|
||||||
else:
|
|
||||||
self.large_object_chunk_size = DEFAULT_LARGE_OBJECT_CHUNK_SIZE
|
|
||||||
|
|
||||||
if self.conf.get('swift_store_object_buffer_dir'):
|
|
||||||
self.swift_store_object_buffer_dir = (
|
|
||||||
self.conf.get('swift_store_object_buffer_dir'))
|
|
||||||
else:
|
|
||||||
self.swift_store_object_buffer_dir = None
|
|
||||||
except Exception, e:
|
|
||||||
reason = _("Error in configuration conf: %s") % e
|
reason = _("Error in configuration conf: %s") % e
|
||||||
logger.error(reason)
|
logger.error(reason)
|
||||||
raise exception.BadStoreConfiguration(store_name="swift",
|
raise exception.BadStoreConfiguration(store_name="swift",
|
||||||
@ -283,7 +283,7 @@ class Store(glance.store.base.Store):
|
|||||||
authurl=auth_url, user=user, key=key, snet=snet)
|
authurl=auth_url, user=user, key=key, snet=snet)
|
||||||
|
|
||||||
def _option_get(self, param):
|
def _option_get(self, param):
|
||||||
result = self.conf.get(param)
|
result = getattr(self.conf, param)
|
||||||
if not result:
|
if not result:
|
||||||
reason = (_("Could not find %(param)s in configuration "
|
reason = (_("Could not find %(param)s in configuration "
|
||||||
"options.") % locals())
|
"options.") % locals())
|
||||||
@ -495,10 +495,7 @@ def create_container_if_missing(container, swift_conn, conf):
|
|||||||
swift_conn.head_container(container)
|
swift_conn.head_container(container)
|
||||||
except swift_client.ClientException, e:
|
except swift_client.ClientException, e:
|
||||||
if e.http_status == httplib.NOT_FOUND:
|
if e.http_status == httplib.NOT_FOUND:
|
||||||
add_container = config.get_option(conf,
|
if conf.swift_store_create_container_on_put:
|
||||||
'swift_store_create_container_on_put',
|
|
||||||
type='bool', default=False)
|
|
||||||
if add_container:
|
|
||||||
try:
|
try:
|
||||||
swift_conn.put_container(container)
|
swift_conn.put_container(container)
|
||||||
except ClientException, e:
|
except ClientException, e:
|
||||||
|
@ -226,7 +226,8 @@ glance.app_factory = glance.image_cache.queue_image:Queuer
|
|||||||
""" % cache_file_options)
|
""" % cache_file_options)
|
||||||
cache_file.flush()
|
cache_file.flush()
|
||||||
|
|
||||||
cmd = "bin/glance-cache-prefetcher %s" % cache_config_filepath
|
cmd = "bin/glance-cache-prefetcher --config-file %s" % \
|
||||||
|
cache_config_filepath
|
||||||
|
|
||||||
exitcode, out, err = execute(cmd)
|
exitcode, out, err = execute(cmd)
|
||||||
|
|
||||||
|
@ -374,7 +374,8 @@ glance.app_factory = glance.image_cache.queue_image:Queuer
|
|||||||
|
|
||||||
self.verify_no_cached_images()
|
self.verify_no_cached_images()
|
||||||
|
|
||||||
cmd = "bin/glance-cache-prefetcher %s" % cache_config_filepath
|
cmd = "bin/glance-cache-prefetcher --config-file %s" % \
|
||||||
|
cache_config_filepath
|
||||||
|
|
||||||
exitcode, out, err = execute(cmd)
|
exitcode, out, err = execute(cmd)
|
||||||
|
|
||||||
|
@ -86,8 +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()
|
||||||
server_one.start(RedirectTestApp("one"), self.port_one, "127.0.0.1")
|
conf = utils.TestConfigOpts({'bind_host': '127.0.0.1'})
|
||||||
server_two.start(RedirectTestApp("two"), self.port_two, "127.0.0.1")
|
server_one.start(RedirectTestApp("one"), conf, self.port_one)
|
||||||
|
server_two.start(RedirectTestApp("two"), 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):
|
||||||
|
@ -28,6 +28,7 @@ import glance.common.client
|
|||||||
from glance.common import context
|
from glance.common import context
|
||||||
from glance.common import exception
|
from glance.common import exception
|
||||||
from glance.registry.api import v1 as rserver
|
from glance.registry.api import v1 as rserver
|
||||||
|
from glance.tests import utils
|
||||||
|
|
||||||
|
|
||||||
FAKE_FILESYSTEM_ROOTDIR = os.path.join('/tmp', 'glance-tests')
|
FAKE_FILESYSTEM_ROOTDIR = os.path.join('/tmp', 'glance-tests')
|
||||||
@ -97,9 +98,13 @@ def stub_out_registry_and_store_server(stubs):
|
|||||||
sql_connection = os.environ.get('GLANCE_SQL_CONNECTION',
|
sql_connection = os.environ.get('GLANCE_SQL_CONNECTION',
|
||||||
"sqlite://")
|
"sqlite://")
|
||||||
context_class = 'glance.registry.context.RequestContext'
|
context_class = 'glance.registry.context.RequestContext'
|
||||||
conf = {'sql_connection': sql_connection, 'verbose': VERBOSE,
|
conf = utils.TestConfigOpts({
|
||||||
'debug': DEBUG, 'context_class': context_class}
|
'sql_connection': sql_connection,
|
||||||
api = context.ContextMiddleware(rserver.API(conf), conf)
|
'verbose': VERBOSE,
|
||||||
|
'debug': DEBUG
|
||||||
|
})
|
||||||
|
api = context.ContextMiddleware(rserver.API(conf),
|
||||||
|
conf, context_class=context_class)
|
||||||
res = self.req.get_response(api)
|
res = self.req.get_response(api)
|
||||||
|
|
||||||
# httplib.Response has a read() method...fake it out
|
# httplib.Response has a read() method...fake it out
|
||||||
@ -145,14 +150,16 @@ def stub_out_registry_and_store_server(stubs):
|
|||||||
self.req.body = body
|
self.req.body = body
|
||||||
|
|
||||||
def getresponse(self):
|
def getresponse(self):
|
||||||
conf = {'verbose': VERBOSE,
|
conf = utils.TestConfigOpts({
|
||||||
|
'verbose': VERBOSE,
|
||||||
'debug': DEBUG,
|
'debug': DEBUG,
|
||||||
'bind_host': '0.0.0.0',
|
'bind_host': '0.0.0.0',
|
||||||
'bind_port': '9999999',
|
'bind_port': '9999999',
|
||||||
'registry_host': '0.0.0.0',
|
'registry_host': '0.0.0.0',
|
||||||
'registry_port': '9191',
|
'registry_port': '9191',
|
||||||
'default_store': 'file',
|
'default_store': 'file',
|
||||||
'filesystem_store_datadir': FAKE_FILESYSTEM_ROOTDIR}
|
'filesystem_store_datadir': FAKE_FILESYSTEM_ROOTDIR
|
||||||
|
})
|
||||||
api = version_negotiation.VersionNegotiationFilter(
|
api = version_negotiation.VersionNegotiationFilter(
|
||||||
context.ContextMiddleware(router.API(conf), conf),
|
context.ContextMiddleware(router.API(conf), conf),
|
||||||
conf)
|
conf)
|
||||||
@ -218,9 +225,13 @@ def stub_out_registry_server(stubs, **kwargs):
|
|||||||
def getresponse(self):
|
def getresponse(self):
|
||||||
sql_connection = kwargs.get('sql_connection', "sqlite:///")
|
sql_connection = kwargs.get('sql_connection', "sqlite:///")
|
||||||
context_class = 'glance.registry.context.RequestContext'
|
context_class = 'glance.registry.context.RequestContext'
|
||||||
conf = {'sql_connection': sql_connection, 'verbose': VERBOSE,
|
conf = utils.TestConfigOpts({
|
||||||
'debug': DEBUG, 'context_class': context_class}
|
'sql_connection': sql_connection,
|
||||||
api = context.ContextMiddleware(rserver.API(conf), conf)
|
'verbose': VERBOSE,
|
||||||
|
'debug': DEBUG
|
||||||
|
})
|
||||||
|
api = context.ContextMiddleware(rserver.API(conf),
|
||||||
|
conf, context_class=context_class)
|
||||||
res = self.req.get_response(api)
|
res = self.req.get_response(api)
|
||||||
|
|
||||||
# httplib.Response has a read() method...fake it out
|
# httplib.Response has a read() method...fake it out
|
||||||
|
@ -34,6 +34,7 @@ from glance.registry.api import v1 as rserver
|
|||||||
from glance.registry.db import api as db_api
|
from glance.registry.db import api as db_api
|
||||||
from glance.registry.db import models as db_models
|
from glance.registry.db import models as db_models
|
||||||
from glance.tests import stubs
|
from glance.tests import stubs
|
||||||
|
from glance.tests import utils as test_utils
|
||||||
|
|
||||||
|
|
||||||
_gen_uuid = utils.generate_uuid
|
_gen_uuid = utils.generate_uuid
|
||||||
@ -48,8 +49,7 @@ CONF = {'sql_connection': 'sqlite://',
|
|||||||
'registry_host': '0.0.0.0',
|
'registry_host': '0.0.0.0',
|
||||||
'registry_port': '9191',
|
'registry_port': '9191',
|
||||||
'default_store': 'file',
|
'default_store': 'file',
|
||||||
'filesystem_store_datadir': stubs.FAKE_FILESYSTEM_ROOTDIR,
|
'filesystem_store_datadir': stubs.FAKE_FILESYSTEM_ROOTDIR}
|
||||||
'context_class': 'glance.registry.context.RequestContext'}
|
|
||||||
|
|
||||||
|
|
||||||
class TestRegistryDb(unittest.TestCase):
|
class TestRegistryDb(unittest.TestCase):
|
||||||
@ -64,9 +64,11 @@ class TestRegistryDb(unittest.TestCase):
|
|||||||
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 = {'verbose': True,
|
bad_conf = test_utils.TestConfigOpts({
|
||||||
|
'verbose': True,
|
||||||
'debug': True,
|
'debug': True,
|
||||||
'sql_connection': 'baddriver:///'}
|
'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
|
||||||
orig_engine = db_api._ENGINE
|
orig_engine = db_api._ENGINE
|
||||||
@ -101,7 +103,10 @@ class TestRegistryAPI(unittest.TestCase):
|
|||||||
self.stubs = stubout.StubOutForTesting()
|
self.stubs = stubout.StubOutForTesting()
|
||||||
stubs.stub_out_registry_and_store_server(self.stubs)
|
stubs.stub_out_registry_and_store_server(self.stubs)
|
||||||
stubs.stub_out_filesystem_backend()
|
stubs.stub_out_filesystem_backend()
|
||||||
self.api = context.ContextMiddleware(rserver.API(CONF), CONF)
|
conf = test_utils.TestConfigOpts(CONF)
|
||||||
|
context_class = 'glance.registry.context.RequestContext'
|
||||||
|
self.api = context.ContextMiddleware(rserver.API(conf),
|
||||||
|
conf, context_class=context_class)
|
||||||
self.FIXTURES = [
|
self.FIXTURES = [
|
||||||
{'id': UUID1,
|
{'id': UUID1,
|
||||||
'name': 'fake image #1',
|
'name': 'fake image #1',
|
||||||
@ -136,7 +141,7 @@ class TestRegistryAPI(unittest.TestCase):
|
|||||||
'location': "file:///tmp/glance-tests/2",
|
'location': "file:///tmp/glance-tests/2",
|
||||||
'properties': {}}]
|
'properties': {}}]
|
||||||
self.context = rcontext.RequestContext(is_admin=True)
|
self.context = rcontext.RequestContext(is_admin=True)
|
||||||
db_api.configure_db(CONF)
|
db_api.configure_db(conf)
|
||||||
self.destroy_fixtures()
|
self.destroy_fixtures()
|
||||||
self.create_fixtures()
|
self.create_fixtures()
|
||||||
|
|
||||||
@ -1935,7 +1940,8 @@ class TestGlanceAPI(unittest.TestCase):
|
|||||||
stubs.stub_out_registry_and_store_server(self.stubs)
|
stubs.stub_out_registry_and_store_server(self.stubs)
|
||||||
stubs.stub_out_filesystem_backend()
|
stubs.stub_out_filesystem_backend()
|
||||||
sql_connection = os.environ.get('GLANCE_SQL_CONNECTION', "sqlite://")
|
sql_connection = os.environ.get('GLANCE_SQL_CONNECTION', "sqlite://")
|
||||||
self.api = context.ContextMiddleware(router.API(CONF), CONF)
|
conf = test_utils.TestConfigOpts(CONF)
|
||||||
|
self.api = context.ContextMiddleware(router.API(conf), conf)
|
||||||
self.FIXTURES = [
|
self.FIXTURES = [
|
||||||
{'id': UUID1,
|
{'id': UUID1,
|
||||||
'name': 'fake image #1',
|
'name': 'fake image #1',
|
||||||
@ -1966,7 +1972,7 @@ class TestGlanceAPI(unittest.TestCase):
|
|||||||
'location': "file:///tmp/glance-tests/2",
|
'location': "file:///tmp/glance-tests/2",
|
||||||
'properties': {}}]
|
'properties': {}}]
|
||||||
self.context = rcontext.RequestContext(is_admin=True)
|
self.context = rcontext.RequestContext(is_admin=True)
|
||||||
db_api.configure_db(CONF)
|
db_api.configure_db(conf)
|
||||||
self.destroy_fixtures()
|
self.destroy_fixtures()
|
||||||
self.create_fixtures()
|
self.create_fixtures()
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ from glance.registry.db import models as db_models
|
|||||||
from glance.registry import client as rclient
|
from glance.registry import client as rclient
|
||||||
from glance.registry import context as rcontext
|
from glance.registry import context as rcontext
|
||||||
from glance.tests import stubs
|
from glance.tests import stubs
|
||||||
|
from glance.tests import utils as test_utils
|
||||||
|
|
||||||
CONF = {'sql_connection': 'sqlite://'}
|
CONF = {'sql_connection': 'sqlite://'}
|
||||||
|
|
||||||
@ -138,7 +139,8 @@ class TestRegistryClient(unittest.TestCase):
|
|||||||
"""Establish a clean test environment"""
|
"""Establish a clean test environment"""
|
||||||
self.stubs = stubout.StubOutForTesting()
|
self.stubs = stubout.StubOutForTesting()
|
||||||
stubs.stub_out_registry_and_store_server(self.stubs)
|
stubs.stub_out_registry_and_store_server(self.stubs)
|
||||||
db_api.configure_db(CONF)
|
conf = test_utils.TestConfigOpts(CONF)
|
||||||
|
db_api.configure_db(conf)
|
||||||
self.context = rcontext.RequestContext(is_admin=True)
|
self.context = rcontext.RequestContext(is_admin=True)
|
||||||
self.FIXTURES = [
|
self.FIXTURES = [
|
||||||
{'id': UUID1,
|
{'id': UUID1,
|
||||||
@ -1138,7 +1140,8 @@ class TestClient(unittest.TestCase):
|
|||||||
self.stubs = stubout.StubOutForTesting()
|
self.stubs = stubout.StubOutForTesting()
|
||||||
stubs.stub_out_registry_and_store_server(self.stubs)
|
stubs.stub_out_registry_and_store_server(self.stubs)
|
||||||
stubs.stub_out_filesystem_backend()
|
stubs.stub_out_filesystem_backend()
|
||||||
db_api.configure_db(CONF)
|
conf = test_utils.TestConfigOpts(CONF)
|
||||||
|
db_api.configure_db(conf)
|
||||||
self.client = client.Client("0.0.0.0")
|
self.client = client.Client("0.0.0.0")
|
||||||
self.FIXTURES = [
|
self.FIXTURES = [
|
||||||
{'id': UUID1,
|
{'id': UUID1,
|
||||||
|
@ -16,8 +16,6 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
import optparse
|
|
||||||
import tempfile
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import stubout
|
import stubout
|
||||||
@ -26,125 +24,9 @@ from glance.api.middleware import version_negotiation
|
|||||||
from glance.api.v1 import images
|
from glance.api.v1 import images
|
||||||
from glance.api.v1 import members
|
from glance.api.v1 import members
|
||||||
from glance.common import config
|
from glance.common import config
|
||||||
from glance.common import wsgi
|
|
||||||
from glance.image_cache import pruner
|
from glance.image_cache import pruner
|
||||||
|
|
||||||
|
|
||||||
class TestOptionParsing(unittest.TestCase):
|
|
||||||
|
|
||||||
def test_common_options(self):
|
|
||||||
parser = optparse.OptionParser()
|
|
||||||
self.assertEquals(0, len(parser.option_groups))
|
|
||||||
config.add_common_options(parser)
|
|
||||||
self.assertEquals(1, len(parser.option_groups))
|
|
||||||
|
|
||||||
expected_options = ['--verbose', '--debug', '--config-file']
|
|
||||||
for e in expected_options:
|
|
||||||
self.assertTrue(parser.option_groups[0].get_option(e),
|
|
||||||
"Missing required common option: %s" % e)
|
|
||||||
|
|
||||||
def test_parse_options(self):
|
|
||||||
# test empty args and that parse_options() returns a mapping
|
|
||||||
# of typed values
|
|
||||||
parser = optparse.OptionParser()
|
|
||||||
config.add_common_options(parser)
|
|
||||||
parsed_conf, args = config.parse_options(parser, [])
|
|
||||||
|
|
||||||
expected_conf = {'verbose': False, 'debug': False,
|
|
||||||
'config_file': None}
|
|
||||||
self.assertEquals(expected_conf, parsed_conf)
|
|
||||||
|
|
||||||
# test non-empty args and that parse_options() returns a mapping
|
|
||||||
# of typed values matching supplied args
|
|
||||||
parser = optparse.OptionParser()
|
|
||||||
config.add_common_options(parser)
|
|
||||||
parsed_conf, args = config.parse_options(parser, ['--verbose'])
|
|
||||||
|
|
||||||
expected_conf = {'verbose': True, 'debug': False,
|
|
||||||
'config_file': None}
|
|
||||||
self.assertEquals(expected_conf, parsed_conf)
|
|
||||||
|
|
||||||
# test non-empty args that contain unknown options raises
|
|
||||||
# a SystemExit exception. Not ideal, but unfortunately optparse
|
|
||||||
# raises a sys.exit() when it runs into an error instead of raising
|
|
||||||
# something a bit more useful for libraries. optparse must have been
|
|
||||||
# written by the same group that wrote unittest ;)
|
|
||||||
parser = optparse.OptionParser()
|
|
||||||
config.add_common_options(parser)
|
|
||||||
self.assertRaises(SystemExit, config.parse_options,
|
|
||||||
parser, ['--unknown'])
|
|
||||||
|
|
||||||
|
|
||||||
class TestConfigFiles(unittest.TestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.stubs = stubout.StubOutForTesting()
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
self.stubs.UnsetAll()
|
|
||||||
|
|
||||||
def test_config_file_default(self):
|
|
||||||
expected_path = '/etc/glance/glance-api.conf'
|
|
||||||
|
|
||||||
self.stubs.Set(os.path, 'exists', lambda p: p == expected_path)
|
|
||||||
|
|
||||||
path = config.find_config_file('glance-api', {}, [])
|
|
||||||
|
|
||||||
self.assertEquals(expected_path, path)
|
|
||||||
|
|
||||||
def test_config_file_option(self):
|
|
||||||
expected_path = '/etc/glance/my-glance-api.conf'
|
|
||||||
|
|
||||||
self.stubs.Set(os.path, 'exists', lambda p: p == expected_path)
|
|
||||||
|
|
||||||
path = config.find_config_file('glance-api',
|
|
||||||
{'config_file': expected_path}, [])
|
|
||||||
|
|
||||||
self.assertEquals(expected_path, path)
|
|
||||||
|
|
||||||
def test_config_file_arg(self):
|
|
||||||
expected_path = '/etc/glance/my-glance-api.conf'
|
|
||||||
|
|
||||||
self.stubs.Set(os.path, 'exists', lambda p: p == expected_path)
|
|
||||||
|
|
||||||
path = config.find_config_file('glance-api', {}, [expected_path])
|
|
||||||
|
|
||||||
self.assertEquals(expected_path, path)
|
|
||||||
|
|
||||||
def test_config_file_tilde_arg(self):
|
|
||||||
supplied_path = '~/my-glance-api.conf'
|
|
||||||
expected_path = '/tmp/my-glance-api.conf'
|
|
||||||
|
|
||||||
def fake_expanduser(p):
|
|
||||||
if p[0] == '~':
|
|
||||||
p = '/tmp' + p[1:]
|
|
||||||
return p
|
|
||||||
|
|
||||||
self.stubs.Set(os.path, 'expanduser', fake_expanduser)
|
|
||||||
self.stubs.Set(os.path, 'exists', lambda p: p == supplied_path)
|
|
||||||
|
|
||||||
path = config.find_config_file('glance-api', {}, [supplied_path])
|
|
||||||
|
|
||||||
self.assertEquals(expected_path, path)
|
|
||||||
|
|
||||||
def test_config_file_not_found(self):
|
|
||||||
self.stubs.Set(os.path, 'exists', lambda p: False)
|
|
||||||
|
|
||||||
self.assertRaises(RuntimeError,
|
|
||||||
config.find_config_file,
|
|
||||||
'glance-foo', {}, [])
|
|
||||||
|
|
||||||
|
|
||||||
class TestPasteConfig(unittest.TestCase):
|
|
||||||
|
|
||||||
def test_load_paste_config(self):
|
|
||||||
path = os.path.join(os.getcwd(), 'etc/glance-api.conf')
|
|
||||||
|
|
||||||
conf = config.load_paste_config(path, 'glance-api')
|
|
||||||
|
|
||||||
self.assertEquals('file', conf['default_store'])
|
|
||||||
|
|
||||||
|
|
||||||
class TestPasteApp(unittest.TestCase):
|
class TestPasteApp(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -154,15 +36,16 @@ class TestPasteApp(unittest.TestCase):
|
|||||||
self.stubs.UnsetAll()
|
self.stubs.UnsetAll()
|
||||||
|
|
||||||
def test_load_paste_app(self):
|
def test_load_paste_app(self):
|
||||||
path = os.path.join(os.getcwd(), 'etc/glance-api.conf')
|
conf = config.GlanceConfigOpts()
|
||||||
|
conf(['--config-file',
|
||||||
|
os.path.join(os.getcwd(), 'etc/glance-api.conf')])
|
||||||
|
|
||||||
self.stubs.Set(config, 'setup_logging', lambda *a: None)
|
self.stubs.Set(config, 'setup_logging', lambda *a: None)
|
||||||
self.stubs.Set(images, 'create_resource', lambda *a: None)
|
self.stubs.Set(images, 'create_resource', lambda *a: None)
|
||||||
self.stubs.Set(members, 'create_resource', lambda *a: None)
|
self.stubs.Set(members, 'create_resource', lambda *a: None)
|
||||||
|
|
||||||
conf, app = config.load_paste_app('glance-api', {}, [path])
|
app = config.load_paste_app(conf, 'glance-api')
|
||||||
|
|
||||||
self.assertEquals('file', conf['default_store'])
|
|
||||||
self.assertEquals(version_negotiation.VersionNegotiationFilter,
|
self.assertEquals(version_negotiation.VersionNegotiationFilter,
|
||||||
type(app))
|
type(app))
|
||||||
|
|
||||||
@ -178,11 +61,12 @@ class TestPasteApp(unittest.TestCase):
|
|||||||
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()
|
||||||
|
conf([])
|
||||||
|
|
||||||
self.stubs.Set(config, 'setup_logging', lambda *a: None)
|
self.stubs.Set(config, 'setup_logging', lambda *a: None)
|
||||||
self.stubs.Set(wsgi, 'app_factory', lambda *a, **kw: 'pruner')
|
self.stubs.Set(pruner, 'Pruner', lambda conf, **lc: 'pruner')
|
||||||
|
|
||||||
conf, app = config.load_paste_app('glance-pruner', {}, [],
|
app = config.load_paste_app(conf, 'glance-pruner')
|
||||||
'glance-cache')
|
|
||||||
|
|
||||||
self.assertEquals('86400', conf['image_cache_stall_time'])
|
|
||||||
self.assertEquals('pruner', app)
|
self.assertEquals('pruner', app)
|
||||||
|
@ -28,6 +28,7 @@ from glance.common import utils
|
|||||||
from glance.store.location import get_location_from_uri
|
from glance.store.location import get_location_from_uri
|
||||||
from glance.store.filesystem import Store, ChunkedFile
|
from glance.store.filesystem import Store, ChunkedFile
|
||||||
from glance.tests import stubs
|
from glance.tests import stubs
|
||||||
|
from glance.tests import utils as test_utils
|
||||||
|
|
||||||
FILESYSTEM_CONF = {
|
FILESYSTEM_CONF = {
|
||||||
'verbose': True,
|
'verbose': True,
|
||||||
@ -43,7 +44,7 @@ class TestStore(unittest.TestCase):
|
|||||||
stubs.stub_out_filesystem_backend()
|
stubs.stub_out_filesystem_backend()
|
||||||
self.orig_chunksize = ChunkedFile.CHUNKSIZE
|
self.orig_chunksize = ChunkedFile.CHUNKSIZE
|
||||||
ChunkedFile.CHUNKSIZE = 10
|
ChunkedFile.CHUNKSIZE = 10
|
||||||
self.store = Store(FILESYSTEM_CONF)
|
self.store = Store(test_utils.TestConfigOpts(FILESYSTEM_CONF))
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
"""Clear the test environment"""
|
"""Clear the test environment"""
|
||||||
|
@ -24,6 +24,7 @@ from glance.common import exception
|
|||||||
from glance.store import create_stores, delete_from_backend
|
from glance.store import create_stores, delete_from_backend
|
||||||
from glance.store.http import Store
|
from glance.store.http import Store
|
||||||
from glance.store.location import get_location_from_uri
|
from glance.store.location import get_location_from_uri
|
||||||
|
from glance.tests import utils
|
||||||
|
|
||||||
|
|
||||||
def stub_out_http_backend(stubs):
|
def stub_out_http_backend(stubs):
|
||||||
@ -104,6 +105,6 @@ class TestHttpStore(unittest.TestCase):
|
|||||||
loc = get_location_from_uri(uri)
|
loc = get_location_from_uri(uri)
|
||||||
self.assertRaises(NotImplementedError, self.store.delete, loc)
|
self.assertRaises(NotImplementedError, self.store.delete, loc)
|
||||||
|
|
||||||
create_stores({})
|
create_stores(utils.TestConfigOpts({}))
|
||||||
self.assertRaises(exception.StoreDeleteNotSupported,
|
self.assertRaises(exception.StoreDeleteNotSupported,
|
||||||
delete_from_backend, uri)
|
delete_from_backend, uri)
|
||||||
|
@ -26,6 +26,7 @@ import stubout
|
|||||||
from glance import image_cache
|
from glance import image_cache
|
||||||
from glance.common import exception
|
from glance.common import exception
|
||||||
from glance.common import utils
|
from glance.common import utils
|
||||||
|
from glance.tests import utils as test_utils
|
||||||
from glance.tests.utils import skip_if_disabled, xattr_writes_supported
|
from glance.tests.utils import skip_if_disabled, xattr_writes_supported
|
||||||
|
|
||||||
FIXTURE_DATA = '*' * 1024
|
FIXTURE_DATA = '*' * 1024
|
||||||
@ -136,8 +137,7 @@ class ImageCacheTestCase(object):
|
|||||||
|
|
||||||
self.assertTrue(os.path.exists(incomplete_file_path))
|
self.assertTrue(os.path.exists(incomplete_file_path))
|
||||||
|
|
||||||
self.cache.conf['image_cache_stall_time'] = 0
|
self.cache.clean(stall_time=0)
|
||||||
self.cache.clean()
|
|
||||||
|
|
||||||
self.assertFalse(os.path.exists(incomplete_file_path))
|
self.assertFalse(os.path.exists(incomplete_file_path))
|
||||||
|
|
||||||
@ -250,11 +250,12 @@ class TestImageCacheXattr(unittest.TestCase,
|
|||||||
|
|
||||||
self.inited = True
|
self.inited = True
|
||||||
self.disabled = False
|
self.disabled = False
|
||||||
self.conf = {'image_cache_dir': self.cache_dir,
|
self.conf = test_utils.TestConfigOpts({
|
||||||
|
'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):
|
||||||
@ -294,11 +295,12 @@ class TestImageCacheSqlite(unittest.TestCase,
|
|||||||
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 = {'image_cache_dir': self.cache_dir,
|
self.conf = test_utils.TestConfigOpts({
|
||||||
|
'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):
|
||||||
|
@ -34,9 +34,10 @@ from migrate.versioning.repository import Repository
|
|||||||
from sqlalchemy import *
|
from sqlalchemy import *
|
||||||
from sqlalchemy.pool import NullPool
|
from sqlalchemy.pool import NullPool
|
||||||
|
|
||||||
|
from glance.common import cfg
|
||||||
from glance.common import exception
|
from glance.common import exception
|
||||||
import glance.registry.db.migration as migration_api
|
import glance.registry.db.migration as migration_api
|
||||||
from glance.tests.utils import execute
|
from glance.tests import utils
|
||||||
|
|
||||||
|
|
||||||
class TestMigrations(unittest.TestCase):
|
class TestMigrations(unittest.TestCase):
|
||||||
@ -115,7 +116,7 @@ class TestMigrations(unittest.TestCase):
|
|||||||
"create database %(database)s;") % locals()
|
"create database %(database)s;") % locals()
|
||||||
cmd = ("mysql -u%(user)s %(password)s -h%(host)s "
|
cmd = ("mysql -u%(user)s %(password)s -h%(host)s "
|
||||||
"-e\"%(sql)s\"") % locals()
|
"-e\"%(sql)s\"") % locals()
|
||||||
exitcode, out, err = execute(cmd)
|
exitcode, out, err = utils.execute(cmd)
|
||||||
self.assertEqual(0, exitcode)
|
self.assertEqual(0, exitcode)
|
||||||
|
|
||||||
def test_walk_versions(self):
|
def test_walk_versions(self):
|
||||||
@ -124,7 +125,9 @@ class TestMigrations(unittest.TestCase):
|
|||||||
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 = {'sql_connection': TestMigrations.TEST_DATABASES[key]}
|
conf = utils.TestConfigOpts({
|
||||||
|
'sql_connection': TestMigrations.TEST_DATABASES[key]})
|
||||||
|
conf.register_opt(cfg.StrOpt('sql_connection'))
|
||||||
self._walk_versions(conf)
|
self._walk_versions(conf)
|
||||||
|
|
||||||
def _walk_versions(self, conf):
|
def _walk_versions(self, conf):
|
||||||
@ -165,7 +168,9 @@ class TestMigrations(unittest.TestCase):
|
|||||||
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 = {'sql_connection': TestMigrations.TEST_DATABASES[key]}
|
conf = utils.TestConfigOpts({
|
||||||
|
'sql_connection': TestMigrations.TEST_DATABASES[key]})
|
||||||
|
conf.register_opt(cfg.StrOpt('sql_connection'))
|
||||||
self._no_data_loss_2_to_3_to_2(engine, conf)
|
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):
|
||||||
|
@ -111,9 +111,9 @@ class UtilsTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
# Try importing an object by supplying a class and
|
# Try importing an object by supplying a class and
|
||||||
# verify the object's class name is the same as that supplied
|
# verify the object's class name is the same as that supplied
|
||||||
store_obj = utils.import_object('glance.store.s3.Store')
|
ex_obj = utils.import_object('glance.common.exception.GlanceException')
|
||||||
|
|
||||||
self.assertTrue(store_obj.__class__.__name__ == 'Store')
|
self.assertTrue(ex_obj.__class__.__name__ == 'GlanceException')
|
||||||
|
|
||||||
# Try importing a module itself
|
# Try importing a module itself
|
||||||
module_obj = utils.import_object('glance.registry')
|
module_obj = utils.import_object('glance.registry')
|
||||||
|
@ -20,13 +20,14 @@ import unittest
|
|||||||
|
|
||||||
from glance.common import exception
|
from glance.common import exception
|
||||||
from glance.common import notifier
|
from glance.common import notifier
|
||||||
|
from glance.tests import utils
|
||||||
|
|
||||||
|
|
||||||
class TestInvalidNotifier(unittest.TestCase):
|
class TestInvalidNotifier(unittest.TestCase):
|
||||||
"""Test that notifications are generated appropriately"""
|
"""Test that notifications are generated appropriately"""
|
||||||
|
|
||||||
def test_cannot_create(self):
|
def test_cannot_create(self):
|
||||||
conf = {"notifier_strategy": "invalid_notifier"}
|
conf = utils.TestConfigOpts({"notifier_strategy": "invalid_notifier"})
|
||||||
self.assertRaises(exception.InvalidNotifierStrategy,
|
self.assertRaises(exception.InvalidNotifierStrategy,
|
||||||
notifier.Notifier,
|
notifier.Notifier,
|
||||||
conf)
|
conf)
|
||||||
@ -36,7 +37,7 @@ class TestLoggingNotifier(unittest.TestCase):
|
|||||||
"""Test the logging notifier is selected and works properly."""
|
"""Test the logging notifier is selected and works properly."""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
conf = {"notifier_strategy": "logging"}
|
conf = utils.TestConfigOpts({"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(conf)
|
||||||
@ -67,7 +68,7 @@ class TestNoopNotifier(unittest.TestCase):
|
|||||||
"""Test that the noop notifier works...and does nothing?"""
|
"""Test that the noop notifier works...and does nothing?"""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
conf = {"notifier_strategy": "noop"}
|
conf = utils.TestConfigOpts({"notifier_strategy": "noop"})
|
||||||
self.notifier = notifier.Notifier(conf)
|
self.notifier = notifier.Notifier(conf)
|
||||||
|
|
||||||
def test_warn(self):
|
def test_warn(self):
|
||||||
@ -86,7 +87,7 @@ class TestRabbitNotifier(unittest.TestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
notifier.RabbitStrategy._send_message = self._send_message
|
notifier.RabbitStrategy._send_message = self._send_message
|
||||||
self.called = False
|
self.called = False
|
||||||
conf = {"notifier_strategy": "rabbit"}
|
conf = utils.TestConfigOpts({"notifier_strategy": "rabbit"})
|
||||||
self.notifier = notifier.Notifier(conf)
|
self.notifier = notifier.Notifier(conf)
|
||||||
|
|
||||||
def _send_message(self, message, priority):
|
def _send_message(self, message, priority):
|
||||||
|
@ -32,6 +32,7 @@ from glance.common import utils
|
|||||||
from glance.store import BackendException, UnsupportedBackend
|
from glance.store import BackendException, 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
|
from glance.store.s3 import Store
|
||||||
|
from glance.tests import utils as test_utils
|
||||||
|
|
||||||
|
|
||||||
FAKE_UUID = utils.generate_uuid()
|
FAKE_UUID = utils.generate_uuid()
|
||||||
@ -163,7 +164,7 @@ class TestStore(unittest.TestCase):
|
|||||||
"""Establish a clean test environment"""
|
"""Establish a clean test environment"""
|
||||||
self.stubs = stubout.StubOutForTesting()
|
self.stubs = stubout.StubOutForTesting()
|
||||||
stub_out_s3(self.stubs)
|
stub_out_s3(self.stubs)
|
||||||
self.store = Store(S3_CONF)
|
self.store = Store(test_utils.TestConfigOpts(S3_CONF))
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
"""Clear the test environment"""
|
"""Clear the test environment"""
|
||||||
@ -260,7 +261,7 @@ class TestStore(unittest.TestCase):
|
|||||||
expected_image_id)
|
expected_image_id)
|
||||||
image_s3 = StringIO.StringIO(expected_s3_contents)
|
image_s3 = StringIO.StringIO(expected_s3_contents)
|
||||||
|
|
||||||
self.store = Store(new_conf)
|
self.store = Store(test_utils.TestConfigOpts(new_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)
|
||||||
@ -292,7 +293,7 @@ class TestStore(unittest.TestCase):
|
|||||||
del conf[key]
|
del conf[key]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.store = Store(conf)
|
self.store = Store(test_utils.TestConfigOpts(conf))
|
||||||
return self.store.add == self.store.add_disabled
|
return self.store.add == self.store.add_disabled
|
||||||
except:
|
except:
|
||||||
return False
|
return False
|
||||||
|
@ -24,8 +24,9 @@ import glance.store.http
|
|||||||
import glance.store.filesystem
|
import glance.store.filesystem
|
||||||
import glance.store.swift
|
import glance.store.swift
|
||||||
import glance.store.s3
|
import glance.store.s3
|
||||||
|
from glance.tests import utils
|
||||||
|
|
||||||
glance.store.create_stores({})
|
glance.store.create_stores(utils.TestConfigOpts({}))
|
||||||
|
|
||||||
|
|
||||||
class TestStoreLocation(unittest.TestCase):
|
class TestStoreLocation(unittest.TestCase):
|
||||||
|
@ -30,6 +30,7 @@ from glance.common import utils
|
|||||||
from glance.store import BackendException
|
from glance.store import BackendException
|
||||||
import glance.store.swift
|
import glance.store.swift
|
||||||
from glance.store.location import get_location_from_uri
|
from glance.store.location import get_location_from_uri
|
||||||
|
from glance.tests import utils as test_utils
|
||||||
|
|
||||||
|
|
||||||
FAKE_UUID = utils.generate_uuid
|
FAKE_UUID = utils.generate_uuid
|
||||||
@ -182,7 +183,7 @@ class TestStore(unittest.TestCase):
|
|||||||
"""Establish a clean test environment"""
|
"""Establish a clean test environment"""
|
||||||
self.stubs = stubout.StubOutForTesting()
|
self.stubs = stubout.StubOutForTesting()
|
||||||
stub_out_swift_common_client(self.stubs)
|
stub_out_swift_common_client(self.stubs)
|
||||||
self.store = Store(SWIFT_CONF)
|
self.store = Store(test_utils.TestConfigOpts(SWIFT_CONF))
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
"""Clear the test environment"""
|
"""Clear the test environment"""
|
||||||
@ -293,7 +294,7 @@ class TestStore(unittest.TestCase):
|
|||||||
|
|
||||||
image_swift = StringIO.StringIO(expected_swift_contents)
|
image_swift = StringIO.StringIO(expected_swift_contents)
|
||||||
|
|
||||||
self.store = Store(new_conf)
|
self.store = Store(test_utils.TestConfigOpts(new_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)
|
||||||
|
|
||||||
@ -318,7 +319,7 @@ class TestStore(unittest.TestCase):
|
|||||||
conf['swift_store_create_container_on_put'] = 'False'
|
conf['swift_store_create_container_on_put'] = 'False'
|
||||||
conf['swift_store_container'] = 'noexist'
|
conf['swift_store_container'] = 'noexist'
|
||||||
image_swift = StringIO.StringIO("nevergonnamakeit")
|
image_swift = StringIO.StringIO("nevergonnamakeit")
|
||||||
self.store = Store(conf)
|
self.store = Store(test_utils.TestConfigOpts(conf))
|
||||||
|
|
||||||
# We check the exception text to ensure the container
|
# We check the exception text to ensure the container
|
||||||
# missing text is found in it, otherwise, we would have
|
# missing text is found in it, otherwise, we would have
|
||||||
@ -348,7 +349,7 @@ class TestStore(unittest.TestCase):
|
|||||||
'/noexist/%s' % expected_image_id
|
'/noexist/%s' % expected_image_id
|
||||||
image_swift = StringIO.StringIO(expected_swift_contents)
|
image_swift = StringIO.StringIO(expected_swift_contents)
|
||||||
|
|
||||||
self.store = Store(conf)
|
self.store = Store(test_utils.TestConfigOpts(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)
|
||||||
@ -387,7 +388,7 @@ class TestStore(unittest.TestCase):
|
|||||||
try:
|
try:
|
||||||
glance.store.swift.DEFAULT_LARGE_OBJECT_SIZE = 1024
|
glance.store.swift.DEFAULT_LARGE_OBJECT_SIZE = 1024
|
||||||
glance.store.swift.DEFAULT_LARGE_OBJECT_CHUNK_SIZE = 1024
|
glance.store.swift.DEFAULT_LARGE_OBJECT_CHUNK_SIZE = 1024
|
||||||
self.store = Store(conf)
|
self.store = Store(test_utils.TestConfigOpts(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)
|
||||||
@ -440,7 +441,7 @@ class TestStore(unittest.TestCase):
|
|||||||
MAX_SWIFT_OBJECT_SIZE = 1024
|
MAX_SWIFT_OBJECT_SIZE = 1024
|
||||||
glance.store.swift.DEFAULT_LARGE_OBJECT_SIZE = 1024
|
glance.store.swift.DEFAULT_LARGE_OBJECT_SIZE = 1024
|
||||||
glance.store.swift.DEFAULT_LARGE_OBJECT_CHUNK_SIZE = 1024
|
glance.store.swift.DEFAULT_LARGE_OBJECT_CHUNK_SIZE = 1024
|
||||||
self.store = Store(conf)
|
self.store = Store(test_utils.TestConfigOpts(conf))
|
||||||
location, size, checksum = self.store.add(expected_image_id,
|
location, size, checksum = self.store.add(expected_image_id,
|
||||||
image_swift, 0)
|
image_swift, 0)
|
||||||
finally:
|
finally:
|
||||||
@ -475,7 +476,7 @@ class TestStore(unittest.TestCase):
|
|||||||
del conf[key]
|
del conf[key]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.store = Store(conf)
|
self.store = Store(test_utils.TestConfigOpts(conf))
|
||||||
return self.store.add == self.store.add_disabled
|
return self.store.add == self.store.add_disabled
|
||||||
except:
|
except:
|
||||||
return False
|
return False
|
||||||
|
@ -22,9 +22,11 @@ import stubout
|
|||||||
import webob
|
import webob
|
||||||
|
|
||||||
from glance import client
|
from glance import client
|
||||||
|
from glance.common import config
|
||||||
from glance.common import exception
|
from glance.common import exception
|
||||||
from glance.api import versions
|
from glance.api import versions
|
||||||
from glance.tests import stubs
|
from glance.tests import stubs
|
||||||
|
from glance.tests import utils
|
||||||
|
|
||||||
|
|
||||||
class VersionsTest(unittest.TestCase):
|
class VersionsTest(unittest.TestCase):
|
||||||
@ -46,8 +48,10 @@ class VersionsTest(unittest.TestCase):
|
|||||||
def test_get_version_list(self):
|
def test_get_version_list(self):
|
||||||
req = webob.Request.blank('/')
|
req = webob.Request.blank('/')
|
||||||
req.accept = "application/json"
|
req.accept = "application/json"
|
||||||
conf = {'bind_host': '0.0.0.0',
|
conf = utils.TestConfigOpts({
|
||||||
'bind_port': 9292}
|
'bind_host': '0.0.0.0',
|
||||||
|
'bind_port': 9292
|
||||||
|
})
|
||||||
res = req.get_response(versions.Controller(conf))
|
res = req.get_response(versions.Controller(conf))
|
||||||
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")
|
||||||
|
@ -22,9 +22,44 @@ import functools
|
|||||||
import os
|
import os
|
||||||
import socket
|
import socket
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
|
||||||
import nose.plugins.skip
|
import nose.plugins.skip
|
||||||
|
|
||||||
|
from glance.common import config
|
||||||
|
|
||||||
|
|
||||||
|
class TestConfigOpts(config.GlanceConfigOpts):
|
||||||
|
|
||||||
|
def __init__(self, test_values):
|
||||||
|
super(TestConfigOpts, self).__init__()
|
||||||
|
self._test_values = test_values
|
||||||
|
self()
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
config_file = self._write_tmp_config_file()
|
||||||
|
try:
|
||||||
|
super(TestConfigOpts, self).\
|
||||||
|
__call__(['--config-file', config_file])
|
||||||
|
finally:
|
||||||
|
os.remove(config_file)
|
||||||
|
|
||||||
|
def _write_tmp_config_file(self):
|
||||||
|
contents = '[DEFAULT]\n'
|
||||||
|
for key, value in self._test_values.items():
|
||||||
|
contents += '%s = %s\n' % (key, value)
|
||||||
|
|
||||||
|
(fd, path) = tempfile.mkstemp(prefix='testcfg')
|
||||||
|
try:
|
||||||
|
os.write(fd, contents)
|
||||||
|
except Exception, e:
|
||||||
|
os.close(fd)
|
||||||
|
os.remove(path)
|
||||||
|
raise e
|
||||||
|
|
||||||
|
os.close(fd)
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
class skip_test(object):
|
class skip_test(object):
|
||||||
"""Decorator that skips a test."""
|
"""Decorator that skips a test."""
|
||||||
|
Loading…
Reference in New Issue
Block a user