Merge lp:~gnuoy/charm-helpers/peerstorage-updates into lp:charm-helpers

Proposed by Liam Young
Status: Merged
Merged at revision: 195
Proposed branch: lp:~gnuoy/charm-helpers/peerstorage-updates
Merge into: lp:charm-helpers
Diff against target: 208 lines (+157/-3)
3 files modified
charmhelpers/contrib/peerstorage/__init__.py (+47/-0)
charmhelpers/core/hookenv.py (+2/-1)
tests/contrib/peerstorage/test_peerstorage.py (+108/-2)
To merge this branch: bzr merge lp:~gnuoy/charm-helpers/peerstorage-updates
Reviewer Review Type Date Requested Status
Chris Glass (community) Approve
Liam Young (community) Needs Resubmitting
Review via email: mp+231201@code.launchpad.net

Description of the change

Add helper to perform relation set and store the dict in the peer db. This function will be used address Bug #1355848

To post a comment you must log in.
199. By Liam Young

Added peer_retrieve_by_prefix function to return all k/v pairs from the peer db given a prefix and filter using {inc,exc}_list.

Revision history for this message
Chris Glass (tribaal) wrote :

A couple of comments inline. The default to mutable argument is a showstopper as far as I'm concerned, but is an easy fix :)

review: Needs Fixing
Revision history for this message
Chris Glass (tribaal) :
Revision history for this message
Liam Young (gnuoy) wrote :

Thanks for the feedback and the link to the article, very interesting! I'll update the mp accordingly

200. By Liam Young

* Remove mutable defaults from new peer functions and from core.hookenv.relation_set
* Improve peer_store_and_set doc string

Revision history for this message
Liam Young (gnuoy) :
review: Needs Resubmitting
Revision history for this message
Chris Glass (tribaal) wrote :

Looks good! +1, with a small inline nitpick :)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'charmhelpers/contrib/peerstorage/__init__.py'
2--- charmhelpers/contrib/peerstorage/__init__.py 2014-03-07 11:57:28 +0000
3+++ charmhelpers/contrib/peerstorage/__init__.py 2014-08-19 14:05:21 +0000
4@@ -1,4 +1,6 @@
5+from charmhelpers.core.hookenv import relation_id as current_relation_id
6 from charmhelpers.core.hookenv import (
7+ is_relation_made,
8 relation_ids,
9 relation_get,
10 local_unit,
11@@ -49,6 +51,24 @@
12 'peer relation {}'.format(relation_name))
13
14
15+def peer_retrieve_by_prefix(prefix, relation_name='cluster', delimiter='_',
16+ inc_list=None, exc_list=None):
17+ """ Retrieve k/v pairs given a prefix and filter using {inc,exc}_list """
18+ inc_list = inc_list if inc_list else []
19+ exc_list = exc_list if exc_list else []
20+ peerdb_settings = peer_retrieve('-', relation_name=relation_name)
21+ matched = {}
22+ for k, v in peerdb_settings.items():
23+ full_prefix = prefix + delimiter
24+ if k.startswith(full_prefix):
25+ new_key = k.replace(full_prefix, '')
26+ if new_key in exc_list:
27+ continue
28+ if new_key in inc_list or len(inc_list) == 0:
29+ matched[new_key] = v
30+ return matched
31+
32+
33 def peer_store(key, value, relation_name='cluster'):
34 """ Store the key/value pair on the named peer relation relation_name """
35 cluster_rels = relation_ids(relation_name)
36@@ -81,3 +101,30 @@
37 echo_data[attribute] = value
38 if len(echo_data) > 0:
39 relation_set(relation_settings=echo_data)
40+
41+
42+def peer_store_and_set(relation_id=None, peer_relation_name='cluster',
43+ peer_store_fatal=False, relation_settings=None,
44+ delimiter='_', **kwargs):
45+ """Store the passed-in arguments both in the argument relation and in peer storage.
46+
47+ It functions like doing relation_set() and peer_store() at the same time, with the same data.
48+
49+ @param relation_id: the id of the relation to store the data on. Defaults to the current relation.
50+ @param peer_store_fatal: Set to True, the function will raise an exception should the peer sotrage not be avialable."""
51+
52+ relation_settings = relation_settings if relation_settings else {}
53+ relation_set(relation_id=relation_id,
54+ relation_settings=relation_settings,
55+ **kwargs)
56+ if is_relation_made(peer_relation_name):
57+ for key, value in dict(kwargs.items() +
58+ relation_settings.items()).iteritems():
59+ key_prefix = relation_id or current_relation_id()
60+ peer_store(key_prefix + delimiter + key,
61+ value,
62+ relation_name=peer_relation_name)
63+ else:
64+ if peer_store_fatal:
65+ raise ValueError('Unable to detect '
66+ 'peer relation {}'.format(peer_relation_name))
67
68=== modified file 'charmhelpers/core/hookenv.py'
69--- charmhelpers/core/hookenv.py 2014-06-09 17:10:38 +0000
70+++ charmhelpers/core/hookenv.py 2014-08-19 14:05:21 +0000
71@@ -285,8 +285,9 @@
72 raise
73
74
75-def relation_set(relation_id=None, relation_settings={}, **kwargs):
76+def relation_set(relation_id=None, relation_settings=None, **kwargs):
77 """Set relation information for the current unit"""
78+ relation_settings = relation_settings if relation_settings else {}
79 relation_cmd_line = ['relation-set']
80 if relation_id is not None:
81 relation_cmd_line.extend(('-r', relation_id))
82
83=== modified file 'tests/contrib/peerstorage/test_peerstorage.py'
84--- tests/contrib/peerstorage/test_peerstorage.py 2014-03-05 10:32:49 +0000
85+++ tests/contrib/peerstorage/test_peerstorage.py 2014-08-19 14:05:21 +0000
86@@ -1,10 +1,17 @@
87 from tests.helpers import FakeRelation
88 from testtools import TestCase
89-from mock import patch
90+from mock import patch, call
91 from charmhelpers.contrib import peerstorage
92
93
94-TO_PATCH = ['relation_ids', 'relation_set', 'relation_get', 'local_unit']
95+TO_PATCH = [
96+ 'current_relation_id',
97+ 'is_relation_made',
98+ 'local_unit',
99+ 'relation_get',
100+ 'relation_ids',
101+ 'relation_set',
102+]
103 FAKE_RELATION_NAME = 'cluster'
104 FAKE_RELATION = {
105 'cluster:0': {
106@@ -67,3 +74,102 @@
107 def test_peer_echo_includes(self):
108 peerstorage.peer_echo(['key1'])
109 self.relation_set.assert_called_with(relation_settings={'key1': 'value1'})
110+
111+ @patch.object(peerstorage, 'peer_store')
112+ def test_peer_store_and_set_no_relation(self, peer_store):
113+ self.is_relation_made.return_value = False
114+ peerstorage.peer_store_and_set(relation_id='db', kwarg1='kwarg1_v')
115+ self.relation_set.assert_called_with(relation_id='db',
116+ relation_settings={},
117+ kwarg1='kwarg1_v')
118+ peer_store.assert_not_called()
119+
120+ @patch.object(peerstorage, 'peer_store')
121+ def test_peer_store_and_set_no_relation_fatal(self, peer_store):
122+ self.is_relation_made.return_value = False
123+ self.assertRaises(ValueError,
124+ peerstorage.peer_store_and_set,
125+ relation_id='db',
126+ kwarg1='kwarg1_v',
127+ peer_store_fatal=True)
128+
129+ @patch.object(peerstorage, 'peer_store')
130+ def test_peer_store_and_set_kwargs(self, peer_store):
131+ self.is_relation_made.return_value = True
132+ peerstorage.peer_store_and_set(relation_id='db', kwarg1='kwarg1_v')
133+ self.relation_set.assert_called_with(relation_id='db',
134+ relation_settings={},
135+ kwarg1='kwarg1_v')
136+ calls = [call('db_kwarg1', 'kwarg1_v', relation_name='cluster')]
137+ peer_store.assert_has_calls(calls, any_order=True)
138+
139+ @patch.object(peerstorage, 'peer_store')
140+ def test_peer_store_and_rel_settings(self, peer_store):
141+ self.is_relation_made.return_value = True
142+ rel_setting = {
143+ 'rel_set1': 'relset1_v'
144+ }
145+ peerstorage.peer_store_and_set(relation_id='db',
146+ relation_settings=rel_setting)
147+ self.relation_set.assert_called_with(relation_id='db',
148+ relation_settings=rel_setting)
149+ calls = [call('db_rel_set1', 'relset1_v', relation_name='cluster')]
150+ peer_store.assert_has_calls(calls, any_order=True)
151+
152+ @patch.object(peerstorage, 'peer_store')
153+ def test_peer_store_and_set(self, peer_store):
154+ self.is_relation_made.return_value = True
155+ rel_setting = {
156+ 'rel_set1': 'relset1_v'
157+ }
158+ peerstorage.peer_store_and_set(relation_id='db',
159+ relation_settings=rel_setting,
160+ kwarg1='kwarg1_v',
161+ delimiter='+')
162+ self.relation_set.assert_called_with(relation_id='db',
163+ relation_settings=rel_setting,
164+ kwarg1='kwarg1_v')
165+ calls = [call('db+rel_set1', 'relset1_v', relation_name='cluster'),
166+ call('db+kwarg1', 'kwarg1_v', relation_name='cluster')]
167+ peer_store.assert_has_calls(calls, any_order=True)
168+
169+ @patch.object(peerstorage, 'peer_retrieve')
170+ def test_peer_retrieve_by_prefix(self, peer_retrieve):
171+ rel_id = 'db:2'
172+ settings = {
173+ 'user': 'bob',
174+ 'pass': 'reallyhardpassword',
175+ 'host': 'myhost',
176+ }
177+ peer_settings = {rel_id + '_' + k: v for k, v in settings.items()}
178+ peer_retrieve.return_value = peer_settings
179+ self.assertEquals(peerstorage.peer_retrieve_by_prefix(rel_id), settings)
180+
181+ @patch.object(peerstorage, 'peer_retrieve')
182+ def test_peer_retrieve_by_prefix_exc_list(self, peer_retrieve):
183+ rel_id = 'db:2'
184+ settings = {
185+ 'user': 'bob',
186+ 'pass': 'reallyhardpassword',
187+ 'host': 'myhost',
188+ }
189+ peer_settings = {rel_id + '_' + k: v for k, v in settings.items()}
190+ del settings['host']
191+ peer_retrieve.return_value = peer_settings
192+ self.assertEquals(peerstorage.peer_retrieve_by_prefix(rel_id,
193+ exc_list=['host']),
194+ settings)
195+
196+ @patch.object(peerstorage, 'peer_retrieve')
197+ def test_peer_retrieve_by_prefix_inc_list(self, peer_retrieve):
198+ rel_id = 'db:2'
199+ settings = {
200+ 'user': 'bob',
201+ 'pass': 'reallyhardpassword',
202+ 'host': 'myhost',
203+ }
204+ peer_settings = {rel_id + '_' + k: v for k, v in settings.items()}
205+ peer_retrieve.return_value = peer_settings
206+ self.assertEquals(peerstorage.peer_retrieve_by_prefix(rel_id,
207+ inc_list=['host']),
208+ {'host': 'myhost'})

Subscribers

People subscribed via source and target branches