~cprov/charms/trusty/adt-image-mapper/no-dot-config

« back to all changes in this revision

Viewing changes to hooks/charmhelpers/contrib/templating/contexts.py

  • Committer: Celso Providelo
  • Date: 2015-03-13 13:06:46 UTC
  • Revision ID: celso.providelo@canonical.com-20150313130646-rx0yjm6kyfgl2iyj
Copy and renaming from adt-cloud-service

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright 2014-2015 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
# Copyright 2013 Canonical Ltd.
 
18
#
 
19
# Authors:
 
20
#  Charm Helpers Developers <juju@lists.ubuntu.com>
 
21
"""A helper to create a yaml cache of config with namespaced relation data."""
 
22
import os
 
23
import yaml
 
24
 
 
25
import six
 
26
 
 
27
import charmhelpers.core.hookenv
 
28
 
 
29
 
 
30
charm_dir = os.environ.get('CHARM_DIR', '')
 
31
 
 
32
 
 
33
def dict_keys_without_hyphens(a_dict):
 
34
    """Return the a new dict with underscores instead of hyphens in keys."""
 
35
    return dict(
 
36
        (key.replace('-', '_'), val) for key, val in a_dict.items())
 
37
 
 
38
 
 
39
def update_relations(context, namespace_separator=':'):
 
40
    """Update the context with the relation data."""
 
41
    # Add any relation data prefixed with the relation type.
 
42
    relation_type = charmhelpers.core.hookenv.relation_type()
 
43
    relations = []
 
44
    context['current_relation'] = {}
 
45
    if relation_type is not None:
 
46
        relation_data = charmhelpers.core.hookenv.relation_get()
 
47
        context['current_relation'] = relation_data
 
48
        # Deprecated: the following use of relation data as keys
 
49
        # directly in the context will be removed.
 
50
        relation_data = dict(
 
51
            ("{relation_type}{namespace_separator}{key}".format(
 
52
                relation_type=relation_type,
 
53
                key=key,
 
54
                namespace_separator=namespace_separator), val)
 
55
            for key, val in relation_data.items())
 
56
        relation_data = dict_keys_without_hyphens(relation_data)
 
57
        context.update(relation_data)
 
58
        relations = charmhelpers.core.hookenv.relations_of_type(relation_type)
 
59
        relations = [dict_keys_without_hyphens(rel) for rel in relations]
 
60
 
 
61
    context['relations_full'] = charmhelpers.core.hookenv.relations()
 
62
 
 
63
    # the hookenv.relations() data structure is effectively unusable in
 
64
    # templates and other contexts when trying to access relation data other
 
65
    # than the current relation. So provide a more useful structure that works
 
66
    # with any hook.
 
67
    local_unit = charmhelpers.core.hookenv.local_unit()
 
68
    relations = {}
 
69
    for rname, rids in context['relations_full'].items():
 
70
        relations[rname] = []
 
71
        for rid, rdata in rids.items():
 
72
            data = rdata.copy()
 
73
            if local_unit in rdata:
 
74
                data.pop(local_unit)
 
75
            for unit_name, rel_data in data.items():
 
76
                new_data = {'__relid__': rid, '__unit__': unit_name}
 
77
                new_data.update(rel_data)
 
78
                relations[rname].append(new_data)
 
79
    context['relations'] = relations
 
80
 
 
81
 
 
82
def juju_state_to_yaml(yaml_path, namespace_separator=':',
 
83
                       allow_hyphens_in_keys=True):
 
84
    """Update the juju config and state in a yaml file.
 
85
 
 
86
    This includes any current relation-get data, and the charm
 
87
    directory.
 
88
 
 
89
    This function was created for the ansible and saltstack
 
90
    support, as those libraries can use a yaml file to supply
 
91
    context to templates, but it may be useful generally to
 
92
    create and update an on-disk cache of all the config, including
 
93
    previous relation data.
 
94
 
 
95
    By default, hyphens are allowed in keys as this is supported
 
96
    by yaml, but for tools like ansible, hyphens are not valid [1].
 
97
 
 
98
    [1] http://www.ansibleworks.com/docs/playbooks_variables.html#what-makes-a-valid-variable-name
 
99
    """
 
100
    config = charmhelpers.core.hookenv.config()
 
101
 
 
102
    # Add the charm_dir which we will need to refer to charm
 
103
    # file resources etc.
 
104
    config['charm_dir'] = charm_dir
 
105
    config['local_unit'] = charmhelpers.core.hookenv.local_unit()
 
106
    config['unit_private_address'] = charmhelpers.core.hookenv.unit_private_ip()
 
107
    config['unit_public_address'] = charmhelpers.core.hookenv.unit_get(
 
108
        'public-address'
 
109
    )
 
110
 
 
111
    # Don't use non-standard tags for unicode which will not
 
112
    # work when salt uses yaml.load_safe.
 
113
    yaml.add_representer(six.text_type,
 
114
                         lambda dumper, value: dumper.represent_scalar(
 
115
                             six.u('tag:yaml.org,2002:str'), value))
 
116
 
 
117
    yaml_dir = os.path.dirname(yaml_path)
 
118
    if not os.path.exists(yaml_dir):
 
119
        os.makedirs(yaml_dir)
 
120
 
 
121
    if os.path.exists(yaml_path):
 
122
        with open(yaml_path, "r") as existing_vars_file:
 
123
            existing_vars = yaml.load(existing_vars_file.read())
 
124
    else:
 
125
        existing_vars = {}
 
126
 
 
127
    if not allow_hyphens_in_keys:
 
128
        config = dict_keys_without_hyphens(config)
 
129
    existing_vars.update(config)
 
130
 
 
131
    update_relations(existing_vars, namespace_separator)
 
132
 
 
133
    with open(yaml_path, "w+") as fp:
 
134
        fp.write(yaml.dump(existing_vars, default_flow_style=False))