Skip to content

Commit

Permalink
Use ConfigOpts.find_file() for policy and paste
Browse files Browse the repository at this point in the history
Use cfg's new helper method to find the PasteDeploy and policy config
files. The basic behavior is "look alongside the config file" with a
fall back to the standard default config paths.

In the fairly obscure case where no --config-file is found we use an
explicit default paste file taking to account the fact that all the
glance apps have their paste config in a single file.

Add some new debug logging to make it easier to see which config files
are being loaded.

Fixes bug 992319

Change-Id: I978c4a8cb6ec6d12aaf746af511ccb572c34b7ee
  • Loading branch information
markmc authored and bcwaldon committed May 7, 2012
1 parent 6d15a2d commit db86220
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 29 deletions.
13 changes: 8 additions & 5 deletions glance/api/policy.py
Expand Up @@ -18,12 +18,15 @@
"""Policy Engine For Glance"""

import json
import logging
import os.path

from glance.common import exception
from glance.common import policy
from glance.openstack.common import cfg

logger = logging.getLogger(__name__)


class Enforcer(object):
"""Responsible for loading and enforcing rules"""
Expand Down Expand Up @@ -58,20 +61,20 @@ def _find_policy_file(conf):
if conf.policy_file:
return conf.policy_file

matches = cfg.find_config_files('glance', 'policy', '.json')

try:
return matches[0]
except IndexError:
policy_file = conf.find_file('policy.json')
if not policy_file:
raise cfg.ConfigFilesNotFoundError(('policy.json',))

return policy_file

def _read_policy_file(self):
"""Read contents of the policy file
This re-caches policy data if the file has been changed.
"""
mtime = os.path.getmtime(self.policy_path)
if not self.policy_file_contents or mtime != self.policy_file_mtime:
logger.debug(_("Loading policy from %s") % self.policy_path)
with open(self.policy_path) as fap:
raw_contents = fap.read()
self.policy_file_contents = json.loads(raw_contents)
Expand Down
17 changes: 12 additions & 5 deletions glance/common/config.py
Expand Up @@ -46,6 +46,7 @@ def __init__(self, default_config_files=None, **kwargs):
version='%%prog %s' % version.version_string(),
default_config_files=default_config_files,
**kwargs)
self.default_paste_file = self.prog + '-paste.ini'


class GlanceCacheConfigOpts(GlanceConfigOpts):
Expand All @@ -54,6 +55,7 @@ def __init__(self, **kwargs):
config_files = cfg.find_config_files(project='glance',
prog='glance-cache')
super(GlanceCacheConfigOpts, self).__init__(config_files, **kwargs)
self.default_paste_file = 'glance-cache-paste.ini'


def setup_logging(conf):
Expand Down Expand Up @@ -128,12 +130,13 @@ def _get_deployment_flavor(conf):
def _get_paste_config_path(conf):
paste_suffix = '-paste.ini'
conf_suffix = '.conf'
if conf.config_dir:
return os.path.join(conf.config_dir, conf.prog + paste_suffix)
else:
if conf.config_file:
# Assume paste config is in a paste.ini file corresponding
# to the last config file
return conf.config_file[-1].replace(conf_suffix, paste_suffix)
path = conf.config_file[-1].replace(conf_suffix, paste_suffix)
else:
path = conf.default_paste_file
return conf.find_file(os.path.basename(path))


def _get_deployment_config_file(conf):
Expand Down Expand Up @@ -174,12 +177,16 @@ def load_paste_app(conf, app_name=None):
try:
# Setup logging early
setup_logging(conf)
logger = logging.getLogger(app_name)

logger.debug(_("Loading %(app_name)s from %(conf_file)s"),
{'conf_file': conf_file, 'app_name': app_name})

app = wsgi.paste_deploy_app(conf_file, app_name, conf)

# Log the options used when starting if we're in debug mode...
if conf.debug:
conf.log_opt_values(logging.getLogger(app_name), logging.DEBUG)
conf.log_opt_values(logger, logging.DEBUG)

return app
except (LookupError, ImportError), e:
Expand Down
97 changes: 78 additions & 19 deletions glance/openstack/common/cfg.py
@@ -1,6 +1,6 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4

# Copyright 2011 Red Hat, Inc.
# Copyright 2012 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
Expand Down Expand Up @@ -325,6 +325,52 @@ class ConfigFileValueError(Error):
pass


def _get_config_dirs(project=None):
"""Return a list of directors where config files may be located.
:param project: an optional project name
If a project is specified, following directories are returned::
~/.${project}/
~/
/etc/${project}/
/etc/
Otherwise, these directories::
~/
/etc/
"""
fix_path = lambda p: os.path.abspath(os.path.expanduser(p))

cfg_dirs = [
fix_path(os.path.join('~', '.' + project)) if project else None,
fix_path('~'),
os.path.join('/etc', project) if project else None,
'/etc'
]

return filter(bool, cfg_dirs)


def _search_dirs(dirs, basename, extension=""):
"""Search a list of directories for a given filename.
Iterator over the supplied directories, returning the first file
found with the supplied name and extension.
:param dirs: a list of directories
:param basename: the filename, e.g. 'glance-api'
:param extension: the file extension, e.g. '.conf'
:returns: the path to a matching file, or None
"""
for d in dirs:
path = os.path.join(d, '%s%s' % (basename, extension))
if os.path.exists(path):
return path


def find_config_files(project=None, prog=None, extension='.conf'):
"""Return a list of default configuration files.
Expand Down Expand Up @@ -353,27 +399,12 @@ def find_config_files(project=None, prog=None, extension='.conf'):
if prog is None:
prog = os.path.basename(sys.argv[0])

fix_path = lambda p: os.path.abspath(os.path.expanduser(p))

cfg_dirs = [
fix_path(os.path.join('~', '.' + project)) if project else None,
fix_path('~'),
os.path.join('/etc', project) if project else None,
'/etc',
'etc'
]
cfg_dirs = filter(bool, cfg_dirs)

def search_dirs(dirs, basename, extension):
for d in dirs:
path = os.path.join(d, '%s%s' % (basename, extension))
if os.path.exists(path):
return path
cfg_dirs = _get_config_dirs(project)

config_files = []
if project:
config_files.append(search_dirs(cfg_dirs, project, extension))
config_files.append(search_dirs(cfg_dirs, prog, extension))
config_files.append(_search_dirs(cfg_dirs, project, extension))
config_files.append(_search_dirs(cfg_dirs, prog, extension))

return filter(bool, config_files)

Expand Down Expand Up @@ -1061,6 +1092,34 @@ def enable_interspersed_args(self):
This it the default behaviour."""
self._oparser.enable_interspersed_args()

def find_file(self, name):
"""Locate a file located alongside the config files.
Search for a file with the supplied basename in the directories
which we have already loaded config files from and other known
configuration directories.
The directory, if any, supplied by the config_dir option is
searched first. Then the config_file option is iterated over
and each of the base directories of the config_files values
are searched. Failing both of these, the standard directories
searched by the module level find_config_files() function is
used. The first matching file is returned.
:param basename: the filename, e.g. 'policy.json'
:returns: the path to a matching file, or None
"""
dirs = []
if self.config_dir:
dirs.append(self.config_dir)

for cf in reversed(self.config_file):
dirs.append(os.path.dirname(cf))

dirs.extend(_get_config_dirs(self.project))

return _search_dirs(dirs, name)

def log_opt_values(self, logger, lvl):
"""Log the value of all registered opts.
Expand Down

0 comments on commit db86220

Please sign in to comment.