1
# Copyright 2014-2015 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/>.
18
from charmhelpers.core.hookenv import relation_id as current_relation_id
19
from charmhelpers.core.hookenv import (
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.
35
To use this, the "peer_echo()" method has to be called form the peer
36
relation's relation-changed hook:
38
@hooks.hook("cluster-relation-changed") # Adapt the to your peer relation name
39
def cluster_relation_changed():
42
Once this is done, you can use peer storage from anywhere:
44
@hooks.hook("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")
53
print "No peers joind the relation, cannot share key/values :("
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,
65
raise ValueError('Unable to detect'
66
'peer relation {}'.format(relation_name))
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)
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:
82
if new_key in inc_list or len(inc_list) == 0:
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})
95
raise ValueError('Unable to detect '
96
'peer relation {}'.format(relation_name))
99
def peer_echo(includes=None):
100
"""Echo filtered attributes back onto the same relation for storage.
102
This is a requirement to use the peerstorage module - it needs to be called
103
from the peer relation's changed hook.
105
rdata = relation_get()
108
echo_data = rdata.copy()
109
for ex in ['private-address', 'public-address']:
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)
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.
126
It functions like doing relation_set() and peer_store() at the same time,
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."""
134
relation_settings = relation_settings if relation_settings else {}
135
relation_set(relation_id=relation_id,
136
relation_settings=relation_settings,
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,
144
relation_name=peer_relation_name)
147
raise ValueError('Unable to detect '
148
'peer relation {}'.format(peer_relation_name))