2
from charmhelpers.core.hookenv import relation_id as current_relation_id
3
from charmhelpers.core.hookenv import (
13
This helper provides functions to support use of a peer relation
14
for basic key/value storage, with the added benefit that all storage
15
can be replicated across peer units.
19
To use this, the "peer_echo()" method has to be called form the peer
20
relation's relation-changed hook:
22
@hooks.hook("cluster-relation-changed") # Adapt the to your peer relation name
23
def cluster_relation_changed():
26
Once this is done, you can use peer storage from anywhere:
28
@hooks.hook("some-hook")
30
# You can store and retrieve key/values this way:
31
if is_relation_made("cluster"): # from charmhelpers.core.hookenv
32
# There are peers available so we can work with peer storage
33
peer_store("mykey", "myvalue")
34
value = peer_retrieve("mykey")
37
print "No peers joind the relation, cannot share key/values :("
41
def peer_retrieve(key, relation_name='cluster'):
42
"""Retrieve a named key from peer relation `relation_name`."""
43
cluster_rels = relation_ids(relation_name)
44
if len(cluster_rels) > 0:
45
cluster_rid = cluster_rels[0]
46
return relation_get(attribute=key, rid=cluster_rid,
49
raise ValueError('Unable to detect'
50
'peer relation {}'.format(relation_name))
53
def peer_retrieve_by_prefix(prefix, relation_name='cluster', delimiter='_',
54
inc_list=None, exc_list=None):
55
""" Retrieve k/v pairs given a prefix and filter using {inc,exc}_list """
56
inc_list = inc_list if inc_list else []
57
exc_list = exc_list if exc_list else []
58
peerdb_settings = peer_retrieve('-', relation_name=relation_name)
60
for k, v in peerdb_settings.items():
61
full_prefix = prefix + delimiter
62
if k.startswith(full_prefix):
63
new_key = k.replace(full_prefix, '')
64
if new_key in exc_list:
66
if new_key in inc_list or len(inc_list) == 0:
71
def peer_store(key, value, relation_name='cluster'):
72
"""Store the key/value pair on the named peer relation `relation_name`."""
73
cluster_rels = relation_ids(relation_name)
74
if len(cluster_rels) > 0:
75
cluster_rid = cluster_rels[0]
76
relation_set(relation_id=cluster_rid,
77
relation_settings={key: value})
79
raise ValueError('Unable to detect '
80
'peer relation {}'.format(relation_name))
83
def peer_echo(includes=None):
84
"""Echo filtered attributes back onto the same relation for storage.
86
This is a requirement to use the peerstorage module - it needs to be called
87
from the peer relation's changed hook.
89
rdata = relation_get()
92
echo_data = rdata.copy()
93
for ex in ['private-address', 'public-address']:
97
for attribute, value in six.iteritems(rdata):
98
for include in includes:
99
if include in attribute:
100
echo_data[attribute] = value
101
if len(echo_data) > 0:
102
relation_set(relation_settings=echo_data)
105
def peer_store_and_set(relation_id=None, peer_relation_name='cluster',
106
peer_store_fatal=False, relation_settings=None,
107
delimiter='_', **kwargs):
108
"""Store passed-in arguments both in argument relation and in peer storage.
110
It functions like doing relation_set() and peer_store() at the same time,
113
@param relation_id: the id of the relation to store the data on. Defaults
114
to the current relation.
115
@param peer_store_fatal: Set to True, the function will raise an exception
116
should the peer sotrage not be avialable."""
118
relation_settings = relation_settings if relation_settings else {}
119
relation_set(relation_id=relation_id,
120
relation_settings=relation_settings,
122
if is_relation_made(peer_relation_name):
123
for key, value in six.iteritems(dict(list(kwargs.items()) +
124
list(relation_settings.items()))):
125
key_prefix = relation_id or current_relation_id()
126
peer_store(key_prefix + delimiter + key,
128
relation_name=peer_relation_name)
131
raise ValueError('Unable to detect '
132
'peer relation {}'.format(peer_relation_name))