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

« back to all changes in this revision

Viewing changes to hooks/charmhelpers/contrib/peerstorage/__init__.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
import six
 
18
from charmhelpers.core.hookenv import relation_id as current_relation_id
 
19
from charmhelpers.core.hookenv import (
 
20
    is_relation_made,
 
21
    relation_ids,
 
22
    relation_get,
 
23
    local_unit,
 
24
    relation_set,
 
25
)
 
26
 
 
27
 
 
28
"""
 
29
This helper provides functions to support use of a peer relation
 
30
for basic key/value storage, with the added benefit that all storage
 
31
can be replicated across peer units.
 
32
 
 
33
Requirement to use:
 
34
 
 
35
To use this, the "peer_echo()" method has to be called form the peer
 
36
relation's relation-changed hook:
 
37
 
 
38
@hooks.hook("cluster-relation-changed") # Adapt the to your peer relation name
 
39
def cluster_relation_changed():
 
40
    peer_echo()
 
41
 
 
42
Once this is done, you can use peer storage from anywhere:
 
43
 
 
44
@hooks.hook("some-hook")
 
45
def some_hook():
 
46
    # You can store and retrieve key/values this way:
 
47
    if is_relation_made("cluster"):  # from charmhelpers.core.hookenv
 
48
        # There are peers available so we can work with peer storage
 
49
        peer_store("mykey", "myvalue")
 
50
        value = peer_retrieve("mykey")
 
51
        print value
 
52
    else:
 
53
        print "No peers joind the relation, cannot share key/values :("
 
54
"""
 
55
 
 
56
 
 
57
def peer_retrieve(key, relation_name='cluster'):
 
58
    """Retrieve a named key from peer relation `relation_name`."""
 
59
    cluster_rels = relation_ids(relation_name)
 
60
    if len(cluster_rels) > 0:
 
61
        cluster_rid = cluster_rels[0]
 
62
        return relation_get(attribute=key, rid=cluster_rid,
 
63
                            unit=local_unit())
 
64
    else:
 
65
        raise ValueError('Unable to detect'
 
66
                         'peer relation {}'.format(relation_name))
 
67
 
 
68
 
 
69
def peer_retrieve_by_prefix(prefix, relation_name='cluster', delimiter='_',
 
70
                            inc_list=None, exc_list=None):
 
71
    """ Retrieve k/v pairs given a prefix and filter using {inc,exc}_list """
 
72
    inc_list = inc_list if inc_list else []
 
73
    exc_list = exc_list if exc_list else []
 
74
    peerdb_settings = peer_retrieve('-', relation_name=relation_name)
 
75
    matched = {}
 
76
    for k, v in peerdb_settings.items():
 
77
        full_prefix = prefix + delimiter
 
78
        if k.startswith(full_prefix):
 
79
            new_key = k.replace(full_prefix, '')
 
80
            if new_key in exc_list:
 
81
                continue
 
82
            if new_key in inc_list or len(inc_list) == 0:
 
83
                matched[new_key] = v
 
84
    return matched
 
85
 
 
86
 
 
87
def peer_store(key, value, relation_name='cluster'):
 
88
    """Store the key/value pair on the named peer relation `relation_name`."""
 
89
    cluster_rels = relation_ids(relation_name)
 
90
    if len(cluster_rels) > 0:
 
91
        cluster_rid = cluster_rels[0]
 
92
        relation_set(relation_id=cluster_rid,
 
93
                     relation_settings={key: value})
 
94
    else:
 
95
        raise ValueError('Unable to detect '
 
96
                         'peer relation {}'.format(relation_name))
 
97
 
 
98
 
 
99
def peer_echo(includes=None):
 
100
    """Echo filtered attributes back onto the same relation for storage.
 
101
 
 
102
    This is a requirement to use the peerstorage module - it needs to be called
 
103
    from the peer relation's changed hook.
 
104
    """
 
105
    rdata = relation_get()
 
106
    echo_data = {}
 
107
    if includes is None:
 
108
        echo_data = rdata.copy()
 
109
        for ex in ['private-address', 'public-address']:
 
110
            if ex in echo_data:
 
111
                echo_data.pop(ex)
 
112
    else:
 
113
        for attribute, value in six.iteritems(rdata):
 
114
            for include in includes:
 
115
                if include in attribute:
 
116
                    echo_data[attribute] = value
 
117
    if len(echo_data) > 0:
 
118
        relation_set(relation_settings=echo_data)
 
119
 
 
120
 
 
121
def peer_store_and_set(relation_id=None, peer_relation_name='cluster',
 
122
                       peer_store_fatal=False, relation_settings=None,
 
123
                       delimiter='_', **kwargs):
 
124
    """Store passed-in arguments both in argument relation and in peer storage.
 
125
 
 
126
    It functions like doing relation_set() and peer_store() at the same time,
 
127
    with the same data.
 
128
 
 
129
    @param relation_id: the id of the relation to store the data on. Defaults
 
130
                        to the current relation.
 
131
    @param peer_store_fatal: Set to True, the function will raise an exception
 
132
                             should the peer sotrage not be avialable."""
 
133
 
 
134
    relation_settings = relation_settings if relation_settings else {}
 
135
    relation_set(relation_id=relation_id,
 
136
                 relation_settings=relation_settings,
 
137
                 **kwargs)
 
138
    if is_relation_made(peer_relation_name):
 
139
        for key, value in six.iteritems(dict(list(kwargs.items()) +
 
140
                                             list(relation_settings.items()))):
 
141
            key_prefix = relation_id or current_relation_id()
 
142
            peer_store(key_prefix + delimiter + key,
 
143
                       value,
 
144
                       relation_name=peer_relation_name)
 
145
    else:
 
146
        if peer_store_fatal:
 
147
            raise ValueError('Unable to detect '
 
148
                             'peer relation {}'.format(peer_relation_name))