Merge lp:~sidnei/juju-deployer/inherit-multiple into lp:~gandelman-a/juju-deployer/trunk

Proposed by Sidnei da Silva
Status: Merged
Merged at revision: 70
Proposed branch: lp:~sidnei/juju-deployer/inherit-multiple
Merge into: lp:~gandelman-a/juju-deployer/trunk
Diff against target: 384 lines (+337/-23)
2 files modified
tests/test_utils.py (+301/-0)
utils.py (+36/-23)
To merge this branch: bzr merge lp:~sidnei/juju-deployer/inherit-multiple
Reviewer Review Type Date Requested Status
Adam Gandelman Pending
Review via email: mp+160236@code.launchpad.net

Description of the change

- Allow 'inherits' to be a list of configs to inherit, to make it easy to create a full stack from multiple smaller ones without deep inheritance chain.
- Make 'weight' optional in relations.

To post a comment you must log in.
71. By Sidnei da Silva

- Also update test_inherit_multiple

72. By Sidnei da Silva

- Add another test, make 'weight' optional while keeping (perhaps unintentional) feature of overriding a relation if it has the same weight.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added directory 'tests'
=== added file 'tests/test_utils.py'
--- tests/test_utils.py 1970-01-01 00:00:00 +0000
+++ tests/test_utils.py 2013-04-23 01:41:25 +0000
@@ -0,0 +1,301 @@
1from unittest import TestCase
2from utils import load_deployment, relations_json_to_tuples
3
4
5class TestLoadDeployment(TestCase):
6
7 def test_inherits_one_level(self):
8 """
9 One level of inheritance is supported just fine.
10 """
11 config = {
12 'foo': {
13 'series': 'precise',
14 'services': {
15 'foo-1': {
16 'options': {
17 'foo': True,
18 },
19 },
20 'foo-2': {},
21 },
22 },
23 'bar': {
24 'series': 'lucid',
25 'inherits': 'foo',
26 'services': {
27 'foo-1': {
28 'options': {
29 'foo': False,
30 'bar': True,
31 },
32 },
33 'bar-1': {}
34 },
35 }
36 }
37
38 (series, charms,
39 relations, overrides) = load_deployment(config, 'bar')
40 self.assertEqual('lucid', series)
41 self.assertEqual({
42 'foo-1': {
43 'options': {
44 'foo': False,
45 'bar': True,
46 },
47 },
48 'foo-2': {},
49 'bar-1': {},
50 }, charms)
51 self.assertEqual({}, relations)
52 self.assertEqual({}, overrides)
53
54 def test_inherits_two_levels(self):
55 """
56 Muliple recursive levels of inheritance are also supported.
57 """
58 config = {
59 'foo': {
60 'series': 'precise',
61 'services': {
62 'foo-1': {
63 'options': {
64 'foo': True,
65 },
66 },
67 'foo-2': {},
68 },
69 },
70 'bar': {
71 'series': 'lucid',
72 'inherits': 'foo',
73 'services': {
74 'foo-1': {
75 'options': {
76 'foo': False,
77 'bar': True,
78 },
79 },
80 },
81 },
82 'baz': {
83 'series': 'precise',
84 'inherits': 'bar',
85 'services': {
86 'foo-1': {
87 'options': {
88 'baz': True,
89 },
90 },
91 'baz-1': {},
92 },
93 },
94 }
95
96 (series, charms,
97 relations, overrides) = load_deployment(config, 'baz')
98 self.assertEqual('precise', series)
99 self.assertEqual({
100 'foo-1': {
101 'options': {
102 'foo': False,
103 'bar': True,
104 'baz': True,
105 },
106 },
107 'foo-2': {},
108 'baz-1': {},
109 }, charms)
110 self.assertEqual({}, relations)
111 self.assertEqual({}, overrides)
112
113 def test_inherits_multiple(self):
114 """
115 It is also possible to inherit from multiple deployments at a single
116 level, which may or may not recurse.
117 """
118 config = {
119 'foo': {
120 'series': 'precise',
121 'services': {
122 'foo-1': {
123 'options': {
124 'foo': True,
125 },
126 },
127 'foo-2': {},
128 },
129 },
130 'bar': {
131 'series': 'lucid',
132 'services': {
133 'foo-1': {
134 'options': {
135 'foo': False,
136 'bar': True,
137 },
138 },
139 'bar-1': {},
140 },
141 },
142 'baz': {
143 'series': 'quantal',
144 'inherits': ['foo', 'bar'],
145 'services': {
146 'foo-1': {
147 'options': {
148 'baz': True,
149 },
150 },
151 'baz-1': {},
152 },
153 },
154 }
155
156 (series, charms,
157 relations, overrides) = load_deployment(config, 'baz')
158 self.assertEqual('quantal', series)
159 self.assertEqual({
160 'foo-1': {
161 'options': {
162 'foo': False,
163 'bar': True,
164 'baz': True,
165 },
166 },
167 'foo-2': {},
168 'bar-1': {},
169 'baz-1': {},
170 }, charms)
171 self.assertEqual({}, relations)
172 self.assertEqual({}, overrides)
173
174 def test_inherits_multiple_recurse(self):
175 """
176 It is also possible to inherit from multiple deployments at a single
177 level, one of which inherits from another deployment.
178 """
179 config = {
180 'qux': {
181 'series': 'precise',
182 'services': {
183 'foo-1': {
184 'options': {
185 'qux': True,
186 },
187 },
188 'foo-2': {},
189 },
190 },
191 'foo': {
192 'inherits': 'qux',
193 'series': 'precise',
194 'services': {
195 'foo-1': {
196 'options': {
197 'foo': True,
198 },
199 },
200 'foo-2': {},
201 },
202 },
203 'bar': {
204 'series': 'lucid',
205 'services': {
206 'foo-1': {
207 'options': {
208 'foo': False,
209 'bar': True,
210 },
211 },
212 'bar-1': {},
213 },
214 },
215 'baz': {
216 'series': 'quantal',
217 'inherits': ['foo', 'bar'],
218 'services': {
219 'foo-1': {
220 'options': {
221 'baz': True,
222 },
223 },
224 'baz-1': {},
225 },
226 },
227 }
228
229 (series, charms,
230 relations, overrides) = load_deployment(config, 'baz')
231 self.assertEqual('quantal', series)
232 self.assertEqual({
233 'foo-1': {
234 'options': {
235 'qux': True,
236 'foo': False,
237 'bar': True,
238 'baz': True,
239 },
240 },
241 'foo-2': {},
242 'bar-1': {},
243 'baz-1': {},
244 }, charms)
245 self.assertEqual({}, relations)
246 self.assertEqual({}, overrides)
247
248
249class TestRelationsJSONToTuples(TestCase):
250
251 def test_key_by_weight(self):
252 """
253 Relations are grouped by weight.
254 """
255 relations = {
256 'foo': {
257 'weight': 42,
258 'consumes': ['bar'],
259 },
260 'baz': {
261 'weight': 60,
262 'consumes': ['qux'],
263 }
264 }
265 self.assertEqual({42: [('foo', 'bar')],
266 60: [('baz', 'qux')]},
267 relations_json_to_tuples(relations))
268
269 def test_same_weight_overrides_deterministic(self):
270 """
271 If a weight is specified and two relations have the same weight, the
272 last one in alphabetical consumer order wins.
273 """
274 relations = {
275 'foo': {
276 'weight': 42,
277 'consumes': ['bar'],
278 },
279 'baz': {
280 'weight': 42,
281 'consumes': ['qux'],
282 }
283 }
284 self.assertEqual({42: [('foo', 'bar')]},
285 relations_json_to_tuples(relations))
286
287 def test_weight_optional(self):
288 """
289 If a weight is not provided, all relations are taken into account with
290 no overrides.
291 """
292 relations = {
293 'foo': {
294 'consumes': ['bar'],
295 },
296 'baz': {
297 'consumes': ['qux'],
298 }
299 }
300 self.assertEqual({0: [('baz', 'qux'), ('foo', 'bar')]},
301 relations_json_to_tuples(relations))
0302
=== modified file 'utils.py'
--- utils.py 2013-03-12 03:30:18 +0000
+++ utils.py 2013-04-23 01:41:25 +0000
@@ -465,10 +465,15 @@
465 to a list of tuples that describe a relation as (consumer, provider)465 to a list of tuples that describe a relation as (consumer, provider)
466 """466 """
467 t = {}467 t = {}
468 for consumer in relations.keys():468 for consumer in sorted(relations.keys()):
469 t[relations[consumer]["weight"]] = []469 weight = relations[consumer].get("weight", 0)
470 if not weight:
471 relation_list = t.setdefault(weight, [])
472 else:
473 relation_list = t[weight] = []
470 for provider in relations[consumer]["consumes"]:474 for provider in relations[consumer]["consumes"]:
471 t[relations[consumer]["weight"]].append((consumer, provider))475 relation_list.append((consumer, provider))
476 relation_list.sort()
472 return t477 return t
473478
474479
@@ -546,26 +551,34 @@
546 display_deploys(config)551 display_deploys(config)
547 exit(1)552 exit(1)
548553
549 deploy_config = config[deployment]554 cur = config[deployment]
550 if 'inherits' in deploy_config:555 configs = [cur]
551 cur = config[deployment]556
552 configs = []557 idx = 0
553558 inherits = []
554 while 'inherits' in cur:559 while True:
555 configs.insert(0, cur)560 parents = cur.get('inherits', ())
556 parent = cur['inherits']561 if isinstance(parents, basestring):
557 try:562 parents = [parents]
558 cur = config[parent]563
559 except KeyError:564 if parents:
560 log.error("Could not find parent deployment in config: %s" %565 inherits[idx:idx] = parents[::-1]
561 parent)566
562 exit(1)567 if not inherits or idx > len(inherits) - 1:
563568 break
564 base = cur569
565 configs.insert(0, base)570 parent = inherits[idx]
566 configs.append(config[deployment])571 idx += 1
567572 try:
568 deploy_config = reduce(dict_merge, configs)573 cur = config[parent]
574 configs.append(cur)
575 except KeyError:
576 log.error("Could not find parent deployment in config: %s" %
577 parent)
578 exit(1)
579
580 configs = configs[::-1]
581 deploy_config = reduce(dict_merge, configs)
569582
570 series = deploy_config.get('series')583 series = deploy_config.get('series')
571 charms = deploy_config.get('services', {})584 charms = deploy_config.get('services', {})

Subscribers

People subscribed via source and target branches