1
# Copyright 2016 Canonical Limited.
3
# This file is part of charm-helpers.
5
# charm-helpers is free software: you can redistribute it and/or modify
6
# it under the terms of the GNU Lesser General Public License version 3 as
7
# published by the Free Software Foundation.
9
# charm-helpers is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
# GNU Lesser General Public License for more details.
14
# You should have received a copy of the GNU Lesser General Public License
15
# along with charm-helpers. If not, see <http://www.gnu.org/licenses/>.
24
from charmhelpers.core.hookenv import (
33
# Global settings cache. Since each hook fire entails a fresh module import it
34
# is safe to hold this in memory and not risk missing config changes (since
35
# they will result in a new hook fire and thus re-import).
39
def _get_defaults(modules):
40
"""Load the default config for the provided modules.
42
:param modules: stack modules config defaults to lookup.
43
:returns: modules default config dictionary.
45
default = os.path.join(os.path.dirname(__file__),
46
'defaults/%s.yaml' % (modules))
47
return yaml.safe_load(open(default))
50
def _get_schema(modules):
51
"""Load the config schema for the provided modules.
53
NOTE: this schema is intended to have 1-1 relationship with they keys in
54
the default config and is used a means to verify valid overrides provided
57
:param modules: stack modules config schema to lookup.
58
:returns: modules default schema dictionary.
60
schema = os.path.join(os.path.dirname(__file__),
61
'defaults/%s.yaml.schema' % (modules))
62
return yaml.safe_load(open(schema))
65
def _get_user_provided_overrides(modules):
66
"""Load user-provided config overrides.
68
:param modules: stack modules to lookup in user overrides yaml file.
69
:returns: overrides dictionary.
71
overrides = os.path.join(os.environ['JUJU_CHARM_DIR'],
73
if os.path.exists(overrides):
74
log("Found user-provided config overrides file '%s'" %
75
(overrides), level=DEBUG)
76
settings = yaml.safe_load(open(overrides))
77
if settings and settings.get(modules):
78
log("Applying '%s' overrides" % (modules), level=DEBUG)
79
return settings.get(modules)
81
log("No overrides found for '%s'" % (modules), level=DEBUG)
83
log("No hardening config overrides file '%s' found in charm "
84
"root dir" % (overrides), level=DEBUG)
89
def _apply_overrides(settings, overrides, schema):
90
"""Get overrides config overlayed onto modules defaults.
92
:param modules: require stack modules config.
93
:returns: dictionary of modules config with user overrides applied.
96
for k, v in six.iteritems(overrides):
100
elif type(schema[k]) is dict:
101
settings[k] = _apply_overrides(settings[k], overrides[k],
104
raise Exception("Unexpected type found in schema '%s'" %
105
type(schema[k]), level=ERROR)
107
log("Unknown override key '%s' - ignoring" % (k), level=INFO)
112
def get_settings(modules):
114
if modules in __SETTINGS__:
115
return __SETTINGS__[modules]
117
schema = _get_schema(modules)
118
settings = _get_defaults(modules)
119
overrides = _get_user_provided_overrides(modules)
120
__SETTINGS__[modules] = _apply_overrides(settings, overrides, schema)
121
return __SETTINGS__[modules]
124
def ensure_permissions(path, user, group, permissions, maxdepth=-1):
125
"""Ensure permissions for path.
127
If path is a file, apply to file and return. If path is a directory,
128
apply recursively (if required) to directory contents and return.
130
:param user: user name
131
:param group: group name
132
:param permissions: octal permissions
133
:param maxdepth: maximum recursion depth. A negative maxdepth allows
134
infinite recursion and maxdepth=0 means no recursion.
137
if not os.path.exists(path):
138
log("File '%s' does not exist - cannot set permissions" % (path),
142
_user = pwd.getpwnam(user)
143
os.chown(path, _user.pw_uid, grp.getgrnam(group).gr_gid)
144
os.chmod(path, permissions)
147
log("Max recursion depth reached - skipping further recursion",
153
if os.path.isdir(path):
154
contents = glob.glob("%s/*" % (path))
156
ensure_permissions(c, user=user, group=group,
157
permissions=permissions, maxdepth=maxdepth)