~bbaqar/charms/trusty/neutron-api-plumgrid/temp

« back to all changes in this revision

Viewing changes to hooks/charmhelpers/contrib/hardening/utils.py

  • Committer: bbaqar at plumgrid
  • Date: 2016-05-17 18:03:56 UTC
  • mfrom: (19.1.13 neutron-api-plumgrid)
  • Revision ID: bbaqar@plumgrid.com-20160517180356-vyr2sx8kkq205gyl
changes

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright 2016 Canonical Limited.
2
 
#
3
 
# This file is part of charm-helpers.
4
 
#
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.
8
 
#
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.
13
 
#
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/>.
16
 
 
17
 
import glob
18
 
import grp
19
 
import os
20
 
import pwd
21
 
import six
22
 
import yaml
23
 
 
24
 
from charmhelpers.core.hookenv import (
25
 
    log,
26
 
    DEBUG,
27
 
    INFO,
28
 
    WARNING,
29
 
    ERROR,
30
 
)
31
 
 
32
 
 
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).
36
 
__SETTINGS__ = {}
37
 
 
38
 
 
39
 
def _get_defaults(modules):
40
 
    """Load the default config for the provided modules.
41
 
 
42
 
    :param modules: stack modules config defaults to lookup.
43
 
    :returns: modules default config dictionary.
44
 
    """
45
 
    default = os.path.join(os.path.dirname(__file__),
46
 
                           'defaults/%s.yaml' % (modules))
47
 
    return yaml.safe_load(open(default))
48
 
 
49
 
 
50
 
def _get_schema(modules):
51
 
    """Load the config schema for the provided modules.
52
 
 
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
55
 
    by the user.
56
 
 
57
 
    :param modules: stack modules config schema to lookup.
58
 
    :returns: modules default schema dictionary.
59
 
    """
60
 
    schema = os.path.join(os.path.dirname(__file__),
61
 
                          'defaults/%s.yaml.schema' % (modules))
62
 
    return yaml.safe_load(open(schema))
63
 
 
64
 
 
65
 
def _get_user_provided_overrides(modules):
66
 
    """Load user-provided config overrides.
67
 
 
68
 
    :param modules: stack modules to lookup in user overrides yaml file.
69
 
    :returns: overrides dictionary.
70
 
    """
71
 
    overrides = os.path.join(os.environ['JUJU_CHARM_DIR'],
72
 
                             'hardening.yaml')
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)
80
 
 
81
 
        log("No overrides found for '%s'" % (modules), level=DEBUG)
82
 
    else:
83
 
        log("No hardening config overrides file '%s' found in charm "
84
 
            "root dir" % (overrides), level=DEBUG)
85
 
 
86
 
    return {}
87
 
 
88
 
 
89
 
def _apply_overrides(settings, overrides, schema):
90
 
    """Get overrides config overlayed onto modules defaults.
91
 
 
92
 
    :param modules: require stack modules config.
93
 
    :returns: dictionary of modules config with user overrides applied.
94
 
    """
95
 
    if overrides:
96
 
        for k, v in six.iteritems(overrides):
97
 
            if k in schema:
98
 
                if schema[k] is None:
99
 
                    settings[k] = v
100
 
                elif type(schema[k]) is dict:
101
 
                    settings[k] = _apply_overrides(settings[k], overrides[k],
102
 
                                                   schema[k])
103
 
                else:
104
 
                    raise Exception("Unexpected type found in schema '%s'" %
105
 
                                    type(schema[k]), level=ERROR)
106
 
            else:
107
 
                log("Unknown override key '%s' - ignoring" % (k), level=INFO)
108
 
 
109
 
    return settings
110
 
 
111
 
 
112
 
def get_settings(modules):
113
 
    global __SETTINGS__
114
 
    if modules in __SETTINGS__:
115
 
        return __SETTINGS__[modules]
116
 
 
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]
122
 
 
123
 
 
124
 
def ensure_permissions(path, user, group, permissions, maxdepth=-1):
125
 
    """Ensure permissions for path.
126
 
 
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.
129
 
 
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.
135
 
    :returns: None
136
 
    """
137
 
    if not os.path.exists(path):
138
 
        log("File '%s' does not exist - cannot set permissions" % (path),
139
 
            level=WARNING)
140
 
        return
141
 
 
142
 
    _user = pwd.getpwnam(user)
143
 
    os.chown(path, _user.pw_uid, grp.getgrnam(group).gr_gid)
144
 
    os.chmod(path, permissions)
145
 
 
146
 
    if maxdepth == 0:
147
 
        log("Max recursion depth reached - skipping further recursion",
148
 
            level=DEBUG)
149
 
        return
150
 
    elif maxdepth > 0:
151
 
        maxdepth -= 1
152
 
 
153
 
    if os.path.isdir(path):
154
 
        contents = glob.glob("%s/*" % (path))
155
 
        for c in contents:
156
 
            ensure_permissions(c, user=user, group=group,
157
 
                               permissions=permissions, maxdepth=maxdepth)