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