Merge lp:~gnuoy/charm-helpers/stable-1453940 into lp:~openstack-charmers/charm-helpers/stable-1604
- stable-1453940
- Merge into stable-1604
Proposed by
Liam Young
Status: | Merged |
---|---|
Merged at revision: | 371 |
Proposed branch: | lp:~gnuoy/charm-helpers/stable-1453940 |
Merge into: | lp:~openstack-charmers/charm-helpers/stable-1604 |
Diff against target: |
812 lines (+612/-30) 5 files modified
charmhelpers/contrib/openstack/context.py (+8/-9) charmhelpers/contrib/storage/linux/ceph.py (+224/-2) tests/contrib/openstack/test_os_contexts.py (+36/-4) tests/contrib/storage/test_linux_ceph.py (+337/-8) tests/helpers.py (+7/-7) |
To merge this branch: | bzr merge lp:~gnuoy/charm-helpers/stable-1453940 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Chris Glass (community) | Approve | ||
Review via email: mp+271258@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'charmhelpers/contrib/openstack/context.py' | |||
2 | --- charmhelpers/contrib/openstack/context.py 2015-08-10 16:39:41 +0000 | |||
3 | +++ charmhelpers/contrib/openstack/context.py 2015-09-16 09:01:05 +0000 | |||
4 | @@ -483,13 +483,15 @@ | |||
5 | 483 | 483 | ||
6 | 484 | log('Generating template context for ceph', level=DEBUG) | 484 | log('Generating template context for ceph', level=DEBUG) |
7 | 485 | mon_hosts = [] | 485 | mon_hosts = [] |
11 | 486 | auth = None | 486 | ctxt = { |
12 | 487 | key = None | 487 | 'use_syslog': str(config('use-syslog')).lower() |
13 | 488 | use_syslog = str(config('use-syslog')).lower() | 488 | } |
14 | 489 | for rid in relation_ids('ceph'): | 489 | for rid in relation_ids('ceph'): |
15 | 490 | for unit in related_units(rid): | 490 | for unit in related_units(rid): |
18 | 491 | auth = relation_get('auth', rid=rid, unit=unit) | 491 | if not ctxt.get('auth'): |
19 | 492 | key = relation_get('key', rid=rid, unit=unit) | 492 | ctxt['auth'] = relation_get('auth', rid=rid, unit=unit) |
20 | 493 | if not ctxt.get('key'): | ||
21 | 494 | ctxt['key'] = relation_get('key', rid=rid, unit=unit) | ||
22 | 493 | ceph_pub_addr = relation_get('ceph-public-address', rid=rid, | 495 | ceph_pub_addr = relation_get('ceph-public-address', rid=rid, |
23 | 494 | unit=unit) | 496 | unit=unit) |
24 | 495 | unit_priv_addr = relation_get('private-address', rid=rid, | 497 | unit_priv_addr = relation_get('private-address', rid=rid, |
25 | @@ -498,10 +500,7 @@ | |||
26 | 498 | ceph_addr = format_ipv6_addr(ceph_addr) or ceph_addr | 500 | ceph_addr = format_ipv6_addr(ceph_addr) or ceph_addr |
27 | 499 | mon_hosts.append(ceph_addr) | 501 | mon_hosts.append(ceph_addr) |
28 | 500 | 502 | ||
33 | 501 | ctxt = {'mon_hosts': ' '.join(sorted(mon_hosts)), | 503 | ctxt['mon_hosts'] = ' '.join(sorted(mon_hosts)) |
30 | 502 | 'auth': auth, | ||
31 | 503 | 'key': key, | ||
32 | 504 | 'use_syslog': use_syslog} | ||
34 | 505 | 504 | ||
35 | 506 | if not os.path.isdir('/etc/ceph'): | 505 | if not os.path.isdir('/etc/ceph'): |
36 | 507 | os.mkdir('/etc/ceph') | 506 | os.mkdir('/etc/ceph') |
37 | 508 | 507 | ||
38 | === modified file 'charmhelpers/contrib/storage/linux/ceph.py' | |||
39 | --- charmhelpers/contrib/storage/linux/ceph.py 2015-08-10 16:39:41 +0000 | |||
40 | +++ charmhelpers/contrib/storage/linux/ceph.py 2015-09-16 09:01:05 +0000 | |||
41 | @@ -28,6 +28,7 @@ | |||
42 | 28 | import shutil | 28 | import shutil |
43 | 29 | import json | 29 | import json |
44 | 30 | import time | 30 | import time |
45 | 31 | import uuid | ||
46 | 31 | 32 | ||
47 | 32 | from subprocess import ( | 33 | from subprocess import ( |
48 | 33 | check_call, | 34 | check_call, |
49 | @@ -35,8 +36,10 @@ | |||
50 | 35 | CalledProcessError, | 36 | CalledProcessError, |
51 | 36 | ) | 37 | ) |
52 | 37 | from charmhelpers.core.hookenv import ( | 38 | from charmhelpers.core.hookenv import ( |
53 | 39 | local_unit, | ||
54 | 38 | relation_get, | 40 | relation_get, |
55 | 39 | relation_ids, | 41 | relation_ids, |
56 | 42 | relation_set, | ||
57 | 40 | related_units, | 43 | related_units, |
58 | 41 | log, | 44 | log, |
59 | 42 | DEBUG, | 45 | DEBUG, |
60 | @@ -411,17 +414,52 @@ | |||
61 | 411 | 414 | ||
62 | 412 | The API is versioned and defaults to version 1. | 415 | The API is versioned and defaults to version 1. |
63 | 413 | """ | 416 | """ |
65 | 414 | def __init__(self, api_version=1): | 417 | def __init__(self, api_version=1, request_id=None): |
66 | 415 | self.api_version = api_version | 418 | self.api_version = api_version |
67 | 419 | if request_id: | ||
68 | 420 | self.request_id = request_id | ||
69 | 421 | else: | ||
70 | 422 | self.request_id = str(uuid.uuid1()) | ||
71 | 416 | self.ops = [] | 423 | self.ops = [] |
72 | 417 | 424 | ||
73 | 418 | def add_op_create_pool(self, name, replica_count=3): | 425 | def add_op_create_pool(self, name, replica_count=3): |
74 | 419 | self.ops.append({'op': 'create-pool', 'name': name, | 426 | self.ops.append({'op': 'create-pool', 'name': name, |
75 | 420 | 'replicas': replica_count}) | 427 | 'replicas': replica_count}) |
76 | 421 | 428 | ||
77 | 429 | def set_ops(self, ops): | ||
78 | 430 | """Set request ops to provided value. | ||
79 | 431 | |||
80 | 432 | Useful for injecting ops that come from a previous request | ||
81 | 433 | to allow comparisons to ensure validity. | ||
82 | 434 | """ | ||
83 | 435 | self.ops = ops | ||
84 | 436 | |||
85 | 422 | @property | 437 | @property |
86 | 423 | def request(self): | 438 | def request(self): |
88 | 424 | return json.dumps({'api-version': self.api_version, 'ops': self.ops}) | 439 | return json.dumps({'api-version': self.api_version, 'ops': self.ops, |
89 | 440 | 'request-id': self.request_id}) | ||
90 | 441 | |||
91 | 442 | def _ops_equal(self, other): | ||
92 | 443 | if len(self.ops) == len(other.ops): | ||
93 | 444 | for req_no in range(0, len(self.ops)): | ||
94 | 445 | for key in ['replicas', 'name', 'op']: | ||
95 | 446 | if self.ops[req_no][key] != other.ops[req_no][key]: | ||
96 | 447 | return False | ||
97 | 448 | else: | ||
98 | 449 | return False | ||
99 | 450 | return True | ||
100 | 451 | |||
101 | 452 | def __eq__(self, other): | ||
102 | 453 | if not isinstance(other, self.__class__): | ||
103 | 454 | return False | ||
104 | 455 | if self.api_version == other.api_version and \ | ||
105 | 456 | self._ops_equal(other): | ||
106 | 457 | return True | ||
107 | 458 | else: | ||
108 | 459 | return False | ||
109 | 460 | |||
110 | 461 | def __ne__(self, other): | ||
111 | 462 | return not self.__eq__(other) | ||
112 | 425 | 463 | ||
113 | 426 | 464 | ||
114 | 427 | class CephBrokerRsp(object): | 465 | class CephBrokerRsp(object): |
115 | @@ -431,14 +469,198 @@ | |||
116 | 431 | 469 | ||
117 | 432 | The API is versioned and defaults to version 1. | 470 | The API is versioned and defaults to version 1. |
118 | 433 | """ | 471 | """ |
119 | 472 | |||
120 | 434 | def __init__(self, encoded_rsp): | 473 | def __init__(self, encoded_rsp): |
121 | 435 | self.api_version = None | 474 | self.api_version = None |
122 | 436 | self.rsp = json.loads(encoded_rsp) | 475 | self.rsp = json.loads(encoded_rsp) |
123 | 437 | 476 | ||
124 | 438 | @property | 477 | @property |
125 | 478 | def request_id(self): | ||
126 | 479 | return self.rsp.get('request-id') | ||
127 | 480 | |||
128 | 481 | @property | ||
129 | 439 | def exit_code(self): | 482 | def exit_code(self): |
130 | 440 | return self.rsp.get('exit-code') | 483 | return self.rsp.get('exit-code') |
131 | 441 | 484 | ||
132 | 442 | @property | 485 | @property |
133 | 443 | def exit_msg(self): | 486 | def exit_msg(self): |
134 | 444 | return self.rsp.get('stderr') | 487 | return self.rsp.get('stderr') |
135 | 488 | |||
136 | 489 | |||
137 | 490 | # Ceph Broker Conversation: | ||
138 | 491 | # If a charm needs an action to be taken by ceph it can create a CephBrokerRq | ||
139 | 492 | # and send that request to ceph via the ceph relation. The CephBrokerRq has a | ||
140 | 493 | # unique id so that the client can identity which CephBrokerRsp is associated | ||
141 | 494 | # with the request. Ceph will also respond to each client unit individually | ||
142 | 495 | # creating a response key per client unit eg glance/0 will get a CephBrokerRsp | ||
143 | 496 | # via key broker-rsp-glance-0 | ||
144 | 497 | # | ||
145 | 498 | # To use this the charm can just do something like: | ||
146 | 499 | # | ||
147 | 500 | # from charmhelpers.contrib.storage.linux.ceph import ( | ||
148 | 501 | # send_request_if_needed, | ||
149 | 502 | # is_request_complete, | ||
150 | 503 | # CephBrokerRq, | ||
151 | 504 | # ) | ||
152 | 505 | # | ||
153 | 506 | # @hooks.hook('ceph-relation-changed') | ||
154 | 507 | # def ceph_changed(): | ||
155 | 508 | # rq = CephBrokerRq() | ||
156 | 509 | # rq.add_op_create_pool(name='poolname', replica_count=3) | ||
157 | 510 | # | ||
158 | 511 | # if is_request_complete(rq): | ||
159 | 512 | # <Request complete actions> | ||
160 | 513 | # else: | ||
161 | 514 | # send_request_if_needed(get_ceph_request()) | ||
162 | 515 | # | ||
163 | 516 | # CephBrokerRq and CephBrokerRsp are serialized into JSON. Below is an example | ||
164 | 517 | # of glance having sent a request to ceph which ceph has successfully processed | ||
165 | 518 | # 'ceph:8': { | ||
166 | 519 | # 'ceph/0': { | ||
167 | 520 | # 'auth': 'cephx', | ||
168 | 521 | # 'broker-rsp-glance-0': '{"request-id": "0bc7dc54", "exit-code": 0}', | ||
169 | 522 | # 'broker_rsp': '{"request-id": "0da543b8", "exit-code": 0}', | ||
170 | 523 | # 'ceph-public-address': '10.5.44.103', | ||
171 | 524 | # 'key': 'AQCLDttVuHXINhAAvI144CB09dYchhHyTUY9BQ==', | ||
172 | 525 | # 'private-address': '10.5.44.103', | ||
173 | 526 | # }, | ||
174 | 527 | # 'glance/0': { | ||
175 | 528 | # 'broker_req': ('{"api-version": 1, "request-id": "0bc7dc54", ' | ||
176 | 529 | # '"ops": [{"replicas": 3, "name": "glance", ' | ||
177 | 530 | # '"op": "create-pool"}]}'), | ||
178 | 531 | # 'private-address': '10.5.44.109', | ||
179 | 532 | # }, | ||
180 | 533 | # } | ||
181 | 534 | |||
182 | 535 | def get_previous_request(rid): | ||
183 | 536 | """Return the last ceph broker request sent on a given relation | ||
184 | 537 | |||
185 | 538 | @param rid: Relation id to query for request | ||
186 | 539 | """ | ||
187 | 540 | request = None | ||
188 | 541 | broker_req = relation_get(attribute='broker_req', rid=rid, | ||
189 | 542 | unit=local_unit()) | ||
190 | 543 | if broker_req: | ||
191 | 544 | request_data = json.loads(broker_req) | ||
192 | 545 | request = CephBrokerRq(api_version=request_data['api-version'], | ||
193 | 546 | request_id=request_data['request-id']) | ||
194 | 547 | request.set_ops(request_data['ops']) | ||
195 | 548 | |||
196 | 549 | return request | ||
197 | 550 | |||
198 | 551 | |||
199 | 552 | def get_request_states(request): | ||
200 | 553 | """Return a dict of requests per relation id with their corresponding | ||
201 | 554 | completion state. | ||
202 | 555 | |||
203 | 556 | This allows a charm, which has a request for ceph, to see whether there is | ||
204 | 557 | an equivalent request already being processed and if so what state that | ||
205 | 558 | request is in. | ||
206 | 559 | |||
207 | 560 | @param request: A CephBrokerRq object | ||
208 | 561 | """ | ||
209 | 562 | complete = [] | ||
210 | 563 | requests = {} | ||
211 | 564 | for rid in relation_ids('ceph'): | ||
212 | 565 | complete = False | ||
213 | 566 | previous_request = get_previous_request(rid) | ||
214 | 567 | if request == previous_request: | ||
215 | 568 | sent = True | ||
216 | 569 | complete = is_request_complete_for_rid(previous_request, rid) | ||
217 | 570 | else: | ||
218 | 571 | sent = False | ||
219 | 572 | complete = False | ||
220 | 573 | |||
221 | 574 | requests[rid] = { | ||
222 | 575 | 'sent': sent, | ||
223 | 576 | 'complete': complete, | ||
224 | 577 | } | ||
225 | 578 | |||
226 | 579 | return requests | ||
227 | 580 | |||
228 | 581 | |||
229 | 582 | def is_request_sent(request): | ||
230 | 583 | """Check to see if a functionally equivalent request has already been sent | ||
231 | 584 | |||
232 | 585 | Returns True if a similair request has been sent | ||
233 | 586 | |||
234 | 587 | @param request: A CephBrokerRq object | ||
235 | 588 | """ | ||
236 | 589 | states = get_request_states(request) | ||
237 | 590 | for rid in states.keys(): | ||
238 | 591 | if not states[rid]['sent']: | ||
239 | 592 | return False | ||
240 | 593 | |||
241 | 594 | return True | ||
242 | 595 | |||
243 | 596 | |||
244 | 597 | def is_request_complete(request): | ||
245 | 598 | """Check to see if a functionally equivalent request has already been | ||
246 | 599 | completed | ||
247 | 600 | |||
248 | 601 | Returns True if a similair request has been completed | ||
249 | 602 | |||
250 | 603 | @param request: A CephBrokerRq object | ||
251 | 604 | """ | ||
252 | 605 | states = get_request_states(request) | ||
253 | 606 | for rid in states.keys(): | ||
254 | 607 | if not states[rid]['complete']: | ||
255 | 608 | return False | ||
256 | 609 | |||
257 | 610 | return True | ||
258 | 611 | |||
259 | 612 | |||
260 | 613 | def is_request_complete_for_rid(request, rid): | ||
261 | 614 | """Check if a given request has been completed on the given relation | ||
262 | 615 | |||
263 | 616 | @param request: A CephBrokerRq object | ||
264 | 617 | @param rid: Relation ID | ||
265 | 618 | """ | ||
266 | 619 | broker_key = get_broker_rsp_key() | ||
267 | 620 | for unit in related_units(rid): | ||
268 | 621 | rdata = relation_get(rid=rid, unit=unit) | ||
269 | 622 | if rdata.get(broker_key): | ||
270 | 623 | rsp = CephBrokerRsp(rdata.get(broker_key)) | ||
271 | 624 | if rsp.request_id == request.request_id: | ||
272 | 625 | if not rsp.exit_code: | ||
273 | 626 | return True | ||
274 | 627 | else: | ||
275 | 628 | # The remote unit sent no reply targeted at this unit so either the | ||
276 | 629 | # remote ceph cluster does not support unit targeted replies or it | ||
277 | 630 | # has not processed our request yet. | ||
278 | 631 | if rdata.get('broker_rsp'): | ||
279 | 632 | request_data = json.loads(rdata['broker_rsp']) | ||
280 | 633 | if request_data.get('request-id'): | ||
281 | 634 | log('Ignoring legacy broker_rsp without unit key as remote ' | ||
282 | 635 | 'service supports unit specific replies', level=DEBUG) | ||
283 | 636 | else: | ||
284 | 637 | log('Using legacy broker_rsp as remote service does not ' | ||
285 | 638 | 'supports unit specific replies', level=DEBUG) | ||
286 | 639 | rsp = CephBrokerRsp(rdata['broker_rsp']) | ||
287 | 640 | if not rsp.exit_code: | ||
288 | 641 | return True | ||
289 | 642 | |||
290 | 643 | return False | ||
291 | 644 | |||
292 | 645 | |||
293 | 646 | def get_broker_rsp_key(): | ||
294 | 647 | """Return broker response key for this unit | ||
295 | 648 | |||
296 | 649 | This is the key that ceph is going to use to pass request status | ||
297 | 650 | information back to this unit | ||
298 | 651 | """ | ||
299 | 652 | return 'broker-rsp-' + local_unit().replace('/', '-') | ||
300 | 653 | |||
301 | 654 | |||
302 | 655 | def send_request_if_needed(request): | ||
303 | 656 | """Send broker request if an equivalent request has not already been sent | ||
304 | 657 | |||
305 | 658 | @param request: A CephBrokerRq object | ||
306 | 659 | """ | ||
307 | 660 | if is_request_sent(request): | ||
308 | 661 | log('Request already sent but not complete, not sending new request', | ||
309 | 662 | level=DEBUG) | ||
310 | 663 | else: | ||
311 | 664 | for rid in relation_ids('ceph'): | ||
312 | 665 | log('Sending request {}'.format(request.request_id), level=DEBUG) | ||
313 | 666 | relation_set(relation_id=rid, broker_req=request.request) | ||
314 | 445 | 667 | ||
315 | === modified file 'tests/contrib/openstack/test_os_contexts.py' | |||
316 | --- tests/contrib/openstack/test_os_contexts.py 2015-08-10 16:39:41 +0000 | |||
317 | +++ tests/contrib/openstack/test_os_contexts.py 2015-09-16 09:01:05 +0000 | |||
318 | @@ -74,7 +74,7 @@ | |||
319 | 74 | 74 | ||
320 | 75 | def relation_ids(self, relation): | 75 | def relation_ids(self, relation): |
321 | 76 | rids = [] | 76 | rids = [] |
323 | 77 | for rid in self.relation_data.keys(): | 77 | for rid in sorted(self.relation_data.keys()): |
324 | 78 | if relation + ':' in rid: | 78 | if relation + ':' in rid: |
325 | 79 | rids.append(rid) | 79 | rids.append(rid) |
326 | 80 | return rids | 80 | return rids |
327 | @@ -82,7 +82,7 @@ | |||
328 | 82 | def relation_units(self, relation_id): | 82 | def relation_units(self, relation_id): |
329 | 83 | if relation_id not in self.relation_data: | 83 | if relation_id not in self.relation_data: |
330 | 84 | return None | 84 | return None |
332 | 85 | return self.relation_data[relation_id].keys() | 85 | return sorted(self.relation_data[relation_id].keys()) |
333 | 86 | 86 | ||
334 | 87 | SHARED_DB_RELATION = { | 87 | SHARED_DB_RELATION = { |
335 | 88 | 'db_host': 'dbserver.local', | 88 | 'db_host': 'dbserver.local', |
336 | @@ -1029,7 +1029,7 @@ | |||
337 | 1029 | def test_ceph_context_with_data(self, ensure_packages, mkdir, isdir, | 1029 | def test_ceph_context_with_data(self, ensure_packages, mkdir, isdir, |
338 | 1030 | config): | 1030 | config): |
339 | 1031 | '''Test ceph context with all relation data''' | 1031 | '''Test ceph context with all relation data''' |
341 | 1032 | config.return_value = True | 1032 | config.side_effect = fake_config({'use-syslog': 'True'}) |
342 | 1033 | isdir.return_value = False | 1033 | isdir.return_value = False |
343 | 1034 | relation = FakeRelation(relation_data=CEPH_RELATION) | 1034 | relation = FakeRelation(relation_data=CEPH_RELATION) |
344 | 1035 | self.relation_get.side_effect = relation.get | 1035 | self.relation_get.side_effect = relation.get |
345 | @@ -1051,7 +1051,7 @@ | |||
346 | 1051 | @patch.object(context, 'ensure_packages') | 1051 | @patch.object(context, 'ensure_packages') |
347 | 1052 | def test_ceph_context_with_missing_data(self, ensure_packages, mkdir): | 1052 | def test_ceph_context_with_missing_data(self, ensure_packages, mkdir): |
348 | 1053 | '''Test ceph context with missing relation data''' | 1053 | '''Test ceph context with missing relation data''' |
350 | 1054 | relation = copy(CEPH_RELATION) | 1054 | relation = deepcopy(CEPH_RELATION) |
351 | 1055 | for k, v in six.iteritems(relation): | 1055 | for k, v in six.iteritems(relation): |
352 | 1056 | for u in six.iterkeys(v): | 1056 | for u in six.iterkeys(v): |
353 | 1057 | del relation[k][u]['auth'] | 1057 | del relation[k][u]['auth'] |
354 | @@ -1068,6 +1068,38 @@ | |||
355 | 1068 | @patch('os.path.isdir') | 1068 | @patch('os.path.isdir') |
356 | 1069 | @patch('os.mkdir') | 1069 | @patch('os.mkdir') |
357 | 1070 | @patch.object(context, 'ensure_packages') | 1070 | @patch.object(context, 'ensure_packages') |
358 | 1071 | def test_ceph_context_partial_missing_data(self, ensure_packages, mkdir, | ||
359 | 1072 | isdir, config): | ||
360 | 1073 | '''Test ceph context last unit missing data | ||
361 | 1074 | |||
362 | 1075 | Tests a fix to a previously bug which meant only the config from | ||
363 | 1076 | last unit was returned so if a valid value was supplied from an | ||
364 | 1077 | earlier unit it would be ignored''' | ||
365 | 1078 | config.side_effect = fake_config({'use-syslog': 'True'}) | ||
366 | 1079 | relation = deepcopy(CEPH_RELATION) | ||
367 | 1080 | for k, v in six.iteritems(relation): | ||
368 | 1081 | last_unit = sorted(six.iterkeys(v))[-1] | ||
369 | 1082 | unit_data = relation[k][last_unit] | ||
370 | 1083 | del unit_data['auth'] | ||
371 | 1084 | relation[k][last_unit] = unit_data | ||
372 | 1085 | relation = FakeRelation(relation_data=relation) | ||
373 | 1086 | self.relation_get.side_effect = relation.get | ||
374 | 1087 | self.relation_ids.side_effect = relation.relation_ids | ||
375 | 1088 | self.related_units.side_effect = relation.relation_units | ||
376 | 1089 | ceph = context.CephContext() | ||
377 | 1090 | result = ceph() | ||
378 | 1091 | expected = { | ||
379 | 1092 | 'mon_hosts': 'ceph_node1 ceph_node2', | ||
380 | 1093 | 'auth': 'foo', | ||
381 | 1094 | 'key': 'bar', | ||
382 | 1095 | 'use_syslog': 'true' | ||
383 | 1096 | } | ||
384 | 1097 | self.assertEquals(result, expected) | ||
385 | 1098 | |||
386 | 1099 | @patch.object(context, 'config') | ||
387 | 1100 | @patch('os.path.isdir') | ||
388 | 1101 | @patch('os.mkdir') | ||
389 | 1102 | @patch.object(context, 'ensure_packages') | ||
390 | 1071 | def test_ceph_context_with_public_addr( | 1103 | def test_ceph_context_with_public_addr( |
391 | 1072 | self, ensure_packages, mkdir, isdir, config): | 1104 | self, ensure_packages, mkdir, isdir, config): |
392 | 1073 | '''Test ceph context in host with multiple networks with all | 1105 | '''Test ceph context in host with multiple networks with all |
393 | 1074 | 1106 | ||
394 | === modified file 'tests/contrib/storage/test_linux_ceph.py' | |||
395 | --- tests/contrib/storage/test_linux_ceph.py 2015-08-10 16:39:41 +0000 | |||
396 | +++ tests/contrib/storage/test_linux_ceph.py 2015-09-16 09:01:05 +0000 | |||
397 | @@ -5,10 +5,11 @@ | |||
398 | 5 | from threading import Timer | 5 | from threading import Timer |
399 | 6 | from testtools import TestCase | 6 | from testtools import TestCase |
400 | 7 | import json | 7 | import json |
401 | 8 | import copy | ||
402 | 8 | 9 | ||
403 | 9 | import charmhelpers.contrib.storage.linux.ceph as ceph_utils | 10 | import charmhelpers.contrib.storage.linux.ceph as ceph_utils |
404 | 10 | from subprocess import CalledProcessError | 11 | from subprocess import CalledProcessError |
406 | 11 | from tests.helpers import patch_open | 12 | from tests.helpers import patch_open, FakeRelation |
407 | 12 | import nose.plugins.attrib | 13 | import nose.plugins.attrib |
408 | 13 | import os | 14 | import os |
409 | 14 | import time | 15 | import time |
410 | @@ -31,6 +32,46 @@ | |||
411 | 31 | baz | 32 | baz |
412 | 32 | """ | 33 | """ |
413 | 33 | 34 | ||
414 | 35 | CEPH_CLIENT_RELATION = { | ||
415 | 36 | 'ceph:8': { | ||
416 | 37 | 'ceph/0': { | ||
417 | 38 | 'auth': 'cephx', | ||
418 | 39 | 'broker-rsp-glance-0': '{"request-id": "0bc7dc54", "exit-code": 0}', | ||
419 | 40 | 'broker-rsp-glance-1': '{"request-id": "0880e22a", "exit-code": 0}', | ||
420 | 41 | 'broker-rsp-glance-2': '{"request-id": "0da543b8", "exit-code": 0}', | ||
421 | 42 | 'broker_rsp': '{"request-id": "0da543b8", "exit-code": 0}', | ||
422 | 43 | 'ceph-public-address': '10.5.44.103', | ||
423 | 44 | 'key': 'AQCLDttVuHXINhAAvI144CB09dYchhHyTUY9BQ==', | ||
424 | 45 | 'private-address': '10.5.44.103', | ||
425 | 46 | }, | ||
426 | 47 | 'ceph/1': { | ||
427 | 48 | 'auth': 'cephx', | ||
428 | 49 | 'ceph-public-address': '10.5.44.104', | ||
429 | 50 | 'key': 'AQCLDttVuHXINhAAvI144CB09dYchhHyTUY9BQ==', | ||
430 | 51 | 'private-address': '10.5.44.104', | ||
431 | 52 | }, | ||
432 | 53 | 'ceph/2': { | ||
433 | 54 | 'auth': 'cephx', | ||
434 | 55 | 'ceph-public-address': '10.5.44.105', | ||
435 | 56 | 'key': 'AQCLDttVuHXINhAAvI144CB09dYchhHyTUY9BQ==', | ||
436 | 57 | 'private-address': '10.5.44.105', | ||
437 | 58 | }, | ||
438 | 59 | 'glance/0': { | ||
439 | 60 | 'broker_req': '{"api-version": 1, "request-id": "0bc7dc54", "ops": [{"replicas": 3, "name": "glance", "op": "create-pool"}]}', | ||
440 | 61 | 'private-address': '10.5.44.109', | ||
441 | 62 | }, | ||
442 | 63 | } | ||
443 | 64 | } | ||
444 | 65 | |||
445 | 66 | CEPH_CLIENT_RELATION_LEGACY = copy.deepcopy(CEPH_CLIENT_RELATION) | ||
446 | 67 | CEPH_CLIENT_RELATION_LEGACY['ceph:8']['ceph/0'] = { | ||
447 | 68 | 'auth': 'cephx', | ||
448 | 69 | 'broker_rsp': '{"exit-code": 0}', | ||
449 | 70 | 'ceph-public-address': '10.5.44.103', | ||
450 | 71 | 'key': 'AQCLDttVuHXINhAAvI144CB09dYchhHyTUY9BQ==', | ||
451 | 72 | 'private-address': '10.5.44.103', | ||
452 | 73 | } | ||
453 | 74 | |||
454 | 34 | 75 | ||
455 | 35 | class CephUtilsTests(TestCase): | 76 | class CephUtilsTests(TestCase): |
456 | 36 | def setUp(self): | 77 | def setUp(self): |
457 | @@ -38,6 +79,10 @@ | |||
458 | 38 | [self._patch(m) for m in [ | 79 | [self._patch(m) for m in [ |
459 | 39 | 'check_call', | 80 | 'check_call', |
460 | 40 | 'check_output', | 81 | 'check_output', |
461 | 82 | 'relation_get', | ||
462 | 83 | 'related_units', | ||
463 | 84 | 'relation_ids', | ||
464 | 85 | 'relation_set', | ||
465 | 41 | 'log', | 86 | 'log', |
466 | 42 | ]] | 87 | ]] |
467 | 43 | 88 | ||
468 | @@ -563,19 +608,303 @@ | |||
469 | 563 | b'ceph version 0.67.4 (ad85b8bfafea6232d64cb7ba76a8b6e8252fa0c7)' | 608 | b'ceph version 0.67.4 (ad85b8bfafea6232d64cb7ba76a8b6e8252fa0c7)' |
470 | 564 | self.assertEquals(ceph_utils.ceph_version(), '0.67.4') | 609 | self.assertEquals(ceph_utils.ceph_version(), '0.67.4') |
471 | 565 | 610 | ||
473 | 566 | def test_ceph_broker_rq_class(self): | 611 | @patch.object(ceph_utils, 'uuid') |
474 | 612 | def test_ceph_broker_rq_class(self, uuid): | ||
475 | 613 | uuid.uuid1.return_value = 'uuid' | ||
476 | 567 | rq = ceph_utils.CephBrokerRq() | 614 | rq = ceph_utils.CephBrokerRq() |
477 | 568 | rq.add_op_create_pool('pool1', replica_count=1) | 615 | rq.add_op_create_pool('pool1', replica_count=1) |
478 | 569 | rq.add_op_create_pool('pool2') | 616 | rq.add_op_create_pool('pool2') |
485 | 570 | expected = json.dumps({'api-version': 1, | 617 | expected = { |
486 | 571 | 'ops': [{'op': 'create-pool', 'name': 'pool1', | 618 | 'api-version': 1, |
487 | 572 | 'replicas': 1}, | 619 | 'request-id': 'uuid', |
488 | 573 | {'op': 'create-pool', 'name': 'pool2', | 620 | 'ops': [{'op': 'create-pool', 'name': 'pool1', 'replicas': 1}, |
489 | 574 | 'replicas': 3}]}) | 621 | {'op': 'create-pool', 'name': 'pool2', 'replicas': 3}] |
490 | 575 | self.assertEqual(rq.request, expected) | 622 | } |
491 | 623 | request_dict = json.loads(rq.request) | ||
492 | 624 | for key in ['api-version', 'request-id']: | ||
493 | 625 | self.assertEqual(request_dict[key], expected[key]) | ||
494 | 626 | for key in ['op', 'name', 'replicas']: | ||
495 | 627 | self.assertEqual(request_dict['ops'][0][key], expected['ops'][0][key]) | ||
496 | 628 | self.assertEqual(request_dict['ops'][1][key], expected['ops'][1][key]) | ||
497 | 576 | 629 | ||
498 | 577 | def test_ceph_broker_rsp_class(self): | 630 | def test_ceph_broker_rsp_class(self): |
499 | 578 | rsp = ceph_utils.CephBrokerRsp(json.dumps({'exit-code': 0, | 631 | rsp = ceph_utils.CephBrokerRsp(json.dumps({'exit-code': 0, |
500 | 579 | 'stderr': "Success"})) | 632 | 'stderr': "Success"})) |
501 | 580 | self.assertEqual(rsp.exit_code, 0) | 633 | self.assertEqual(rsp.exit_code, 0) |
502 | 581 | self.assertEqual(rsp.exit_msg, "Success") | 634 | self.assertEqual(rsp.exit_msg, "Success") |
503 | 635 | self.assertEqual(rsp.request_id, None) | ||
504 | 636 | |||
505 | 637 | def test_ceph_broker_rsp_class_rqid(self): | ||
506 | 638 | rsp = ceph_utils.CephBrokerRsp(json.dumps({'exit-code': 0, | ||
507 | 639 | 'stderr': "Success", | ||
508 | 640 | 'request-id': 'reqid1'})) | ||
509 | 641 | self.assertEqual(rsp.exit_code, 0) | ||
510 | 642 | self.assertEqual(rsp.exit_msg, 'Success') | ||
511 | 643 | self.assertEqual(rsp.request_id, 'reqid1') | ||
512 | 644 | |||
513 | 645 | def setup_client_relation(self, relation): | ||
514 | 646 | relation = FakeRelation(relation) | ||
515 | 647 | self.relation_get.side_effect = relation.get | ||
516 | 648 | self.relation_ids.side_effect = relation.relation_ids | ||
517 | 649 | self.related_units.side_effect = relation.related_units | ||
518 | 650 | |||
519 | 651 | # @patch.object(ceph_utils, 'uuid') | ||
520 | 652 | # @patch.object(ceph_utils, 'local_unit') | ||
521 | 653 | # def test_get_request_states(self, mlocal_unit, muuid): | ||
522 | 654 | # muuid.uuid1.return_value = '0bc7dc54' | ||
523 | 655 | @patch.object(ceph_utils, 'local_unit') | ||
524 | 656 | def test_get_request_states(self, mlocal_unit): | ||
525 | 657 | mlocal_unit.return_value = 'glance/0' | ||
526 | 658 | self.setup_client_relation(CEPH_CLIENT_RELATION) | ||
527 | 659 | rq = ceph_utils.CephBrokerRq() | ||
528 | 660 | rq.add_op_create_pool(name='glance', replica_count=3) | ||
529 | 661 | expect = {'ceph:8': {'complete': True, 'sent': True}} | ||
530 | 662 | self.assertEqual(ceph_utils.get_request_states(rq), expect) | ||
531 | 663 | |||
532 | 664 | @patch.object(ceph_utils, 'local_unit') | ||
533 | 665 | def test_get_request_states_newrq(self, mlocal_unit): | ||
534 | 666 | mlocal_unit.return_value = 'glance/0' | ||
535 | 667 | self.setup_client_relation(CEPH_CLIENT_RELATION) | ||
536 | 668 | rq = ceph_utils.CephBrokerRq() | ||
537 | 669 | rq.add_op_create_pool(name='glance', replica_count=4) | ||
538 | 670 | expect = {'ceph:8': {'complete': False, 'sent': False}} | ||
539 | 671 | self.assertEqual(ceph_utils.get_request_states(rq), expect) | ||
540 | 672 | |||
541 | 673 | @patch.object(ceph_utils, 'local_unit') | ||
542 | 674 | def test_get_request_states_pendingrq(self, mlocal_unit): | ||
543 | 675 | mlocal_unit.return_value = 'glance/0' | ||
544 | 676 | rel = copy.deepcopy(CEPH_CLIENT_RELATION) | ||
545 | 677 | del rel['ceph:8']['ceph/0']['broker-rsp-glance-0'] | ||
546 | 678 | self.setup_client_relation(rel) | ||
547 | 679 | rq = ceph_utils.CephBrokerRq() | ||
548 | 680 | rq.add_op_create_pool(name='glance', replica_count=3) | ||
549 | 681 | expect = {'ceph:8': {'complete': False, 'sent': True}} | ||
550 | 682 | self.assertEqual(ceph_utils.get_request_states(rq), expect) | ||
551 | 683 | |||
552 | 684 | @patch.object(ceph_utils, 'local_unit') | ||
553 | 685 | def test_get_request_states_failedrq(self, mlocal_unit): | ||
554 | 686 | mlocal_unit.return_value = 'glance/0' | ||
555 | 687 | rel = copy.deepcopy(CEPH_CLIENT_RELATION) | ||
556 | 688 | rel['ceph:8']['ceph/0']['broker-rsp-glance-0'] = '{"request-id": "0bc7dc54", "exit-code": 1}' | ||
557 | 689 | self.setup_client_relation(rel) | ||
558 | 690 | rq = ceph_utils.CephBrokerRq() | ||
559 | 691 | rq.add_op_create_pool(name='glance', replica_count=3) | ||
560 | 692 | expect = {'ceph:8': {'complete': False, 'sent': True}} | ||
561 | 693 | self.assertEqual(ceph_utils.get_request_states(rq), expect) | ||
562 | 694 | |||
563 | 695 | @patch.object(ceph_utils, 'local_unit') | ||
564 | 696 | def test_is_request_sent(self, mlocal_unit): | ||
565 | 697 | mlocal_unit.return_value = 'glance/0' | ||
566 | 698 | self.setup_client_relation(CEPH_CLIENT_RELATION) | ||
567 | 699 | rq = ceph_utils.CephBrokerRq() | ||
568 | 700 | rq.add_op_create_pool(name='glance', replica_count=3) | ||
569 | 701 | self.assertTrue(ceph_utils.is_request_sent(rq)) | ||
570 | 702 | |||
571 | 703 | @patch.object(ceph_utils, 'local_unit') | ||
572 | 704 | def test_is_request_sent_newrq(self, mlocal_unit): | ||
573 | 705 | mlocal_unit.return_value = 'glance/0' | ||
574 | 706 | self.setup_client_relation(CEPH_CLIENT_RELATION) | ||
575 | 707 | rq = ceph_utils.CephBrokerRq() | ||
576 | 708 | rq.add_op_create_pool(name='glance', replica_count=4) | ||
577 | 709 | self.assertFalse(ceph_utils.is_request_sent(rq)) | ||
578 | 710 | |||
579 | 711 | @patch.object(ceph_utils, 'local_unit') | ||
580 | 712 | def test_is_request_sent_pending(self, mlocal_unit): | ||
581 | 713 | mlocal_unit.return_value = 'glance/0' | ||
582 | 714 | rel = copy.deepcopy(CEPH_CLIENT_RELATION) | ||
583 | 715 | del rel['ceph:8']['ceph/0']['broker-rsp-glance-0'] | ||
584 | 716 | self.setup_client_relation(rel) | ||
585 | 717 | rq = ceph_utils.CephBrokerRq() | ||
586 | 718 | rq.add_op_create_pool(name='glance', replica_count=3) | ||
587 | 719 | self.assertTrue(ceph_utils.is_request_sent(rq)) | ||
588 | 720 | |||
589 | 721 | @patch.object(ceph_utils, 'local_unit') | ||
590 | 722 | def test_is_request_sent_legacy(self, mlocal_unit): | ||
591 | 723 | mlocal_unit.return_value = 'glance/0' | ||
592 | 724 | self.setup_client_relation(CEPH_CLIENT_RELATION_LEGACY) | ||
593 | 725 | rq = ceph_utils.CephBrokerRq() | ||
594 | 726 | rq.add_op_create_pool(name='glance', replica_count=3) | ||
595 | 727 | self.assertTrue(ceph_utils.is_request_sent(rq)) | ||
596 | 728 | |||
597 | 729 | @patch.object(ceph_utils, 'local_unit') | ||
598 | 730 | def test_is_request_sent_legacy_newrq(self, mlocal_unit): | ||
599 | 731 | mlocal_unit.return_value = 'glance/0' | ||
600 | 732 | self.setup_client_relation(CEPH_CLIENT_RELATION_LEGACY) | ||
601 | 733 | rq = ceph_utils.CephBrokerRq() | ||
602 | 734 | rq.add_op_create_pool(name='glance', replica_count=4) | ||
603 | 735 | self.assertFalse(ceph_utils.is_request_sent(rq)) | ||
604 | 736 | |||
605 | 737 | @patch.object(ceph_utils, 'local_unit') | ||
606 | 738 | def test_is_request_sent_legacy_pending(self, mlocal_unit): | ||
607 | 739 | mlocal_unit.return_value = 'glance/0' | ||
608 | 740 | rel = copy.deepcopy(CEPH_CLIENT_RELATION_LEGACY) | ||
609 | 741 | del rel['ceph:8']['ceph/0']['broker_rsp'] | ||
610 | 742 | rq = ceph_utils.CephBrokerRq() | ||
611 | 743 | rq.add_op_create_pool(name='glance', replica_count=3) | ||
612 | 744 | self.assertTrue(ceph_utils.is_request_sent(rq)) | ||
613 | 745 | |||
614 | 746 | @patch.object(ceph_utils, 'uuid') | ||
615 | 747 | @patch.object(ceph_utils, 'local_unit') | ||
616 | 748 | def test_is_request_complete(self, mlocal_unit, muuid): | ||
617 | 749 | muuid.uuid1.return_value = '0bc7dc54' | ||
618 | 750 | mlocal_unit.return_value = 'glance/0' | ||
619 | 751 | self.setup_client_relation(CEPH_CLIENT_RELATION) | ||
620 | 752 | rq = ceph_utils.CephBrokerRq() | ||
621 | 753 | rq.add_op_create_pool(name='glance', replica_count=3) | ||
622 | 754 | self.assertTrue(ceph_utils.is_request_complete(rq)) | ||
623 | 755 | |||
624 | 756 | @patch.object(ceph_utils, 'local_unit') | ||
625 | 757 | def test_is_request_complete_newrq(self, mlocal_unit): | ||
626 | 758 | mlocal_unit.return_value = 'glance/0' | ||
627 | 759 | self.setup_client_relation(CEPH_CLIENT_RELATION) | ||
628 | 760 | rq = ceph_utils.CephBrokerRq() | ||
629 | 761 | rq.add_op_create_pool(name='glance', replica_count=4) | ||
630 | 762 | self.assertFalse(ceph_utils.is_request_complete(rq)) | ||
631 | 763 | |||
632 | 764 | @patch.object(ceph_utils, 'local_unit') | ||
633 | 765 | def test_is_request_complete_pending(self, mlocal_unit): | ||
634 | 766 | mlocal_unit.return_value = 'glance/0' | ||
635 | 767 | rel = copy.deepcopy(CEPH_CLIENT_RELATION) | ||
636 | 768 | del rel['ceph:8']['ceph/0']['broker-rsp-glance-0'] | ||
637 | 769 | self.setup_client_relation(rel) | ||
638 | 770 | rq = ceph_utils.CephBrokerRq() | ||
639 | 771 | rq.add_op_create_pool(name='glance', replica_count=3) | ||
640 | 772 | self.assertFalse(ceph_utils.is_request_complete(rq)) | ||
641 | 773 | |||
642 | 774 | @patch.object(ceph_utils, 'local_unit') | ||
643 | 775 | def test_is_request_complete_legacy(self, mlocal_unit): | ||
644 | 776 | mlocal_unit.return_value = 'glance/0' | ||
645 | 777 | self.setup_client_relation(CEPH_CLIENT_RELATION_LEGACY) | ||
646 | 778 | rq = ceph_utils.CephBrokerRq() | ||
647 | 779 | rq.add_op_create_pool(name='glance', replica_count=3) | ||
648 | 780 | self.assertTrue(ceph_utils.is_request_complete(rq)) | ||
649 | 781 | |||
650 | 782 | @patch.object(ceph_utils, 'local_unit') | ||
651 | 783 | def test_is_request_complete_legacy_newrq(self, mlocal_unit): | ||
652 | 784 | mlocal_unit.return_value = 'glance/0' | ||
653 | 785 | self.setup_client_relation(CEPH_CLIENT_RELATION_LEGACY) | ||
654 | 786 | rq = ceph_utils.CephBrokerRq() | ||
655 | 787 | rq.add_op_create_pool(name='glance', replica_count=4) | ||
656 | 788 | self.assertFalse(ceph_utils.is_request_complete(rq)) | ||
657 | 789 | |||
658 | 790 | @patch.object(ceph_utils, 'local_unit') | ||
659 | 791 | def test_is_request_complete_legacy_pending(self, mlocal_unit): | ||
660 | 792 | mlocal_unit.return_value = 'glance/0' | ||
661 | 793 | rel = copy.deepcopy(CEPH_CLIENT_RELATION_LEGACY) | ||
662 | 794 | del rel['ceph:8']['ceph/0']['broker_rsp'] | ||
663 | 795 | self.setup_client_relation(rel) | ||
664 | 796 | rq = ceph_utils.CephBrokerRq() | ||
665 | 797 | rq.add_op_create_pool(name='glance', replica_count=3) | ||
666 | 798 | self.assertFalse(ceph_utils.is_request_complete(rq)) | ||
667 | 799 | |||
668 | 800 | def test_equivalent_broker_requests(self): | ||
669 | 801 | rq1 = ceph_utils.CephBrokerRq() | ||
670 | 802 | rq1.add_op_create_pool(name='glance', replica_count=4) | ||
671 | 803 | rq2 = ceph_utils.CephBrokerRq() | ||
672 | 804 | rq2.add_op_create_pool(name='glance', replica_count=4) | ||
673 | 805 | self.assertTrue(rq1 == rq2) | ||
674 | 806 | |||
675 | 807 | def test_equivalent_broker_requests_diff1(self): | ||
676 | 808 | rq1 = ceph_utils.CephBrokerRq() | ||
677 | 809 | rq1.add_op_create_pool(name='glance', replica_count=3) | ||
678 | 810 | rq2 = ceph_utils.CephBrokerRq() | ||
679 | 811 | rq2.add_op_create_pool(name='glance', replica_count=4) | ||
680 | 812 | self.assertFalse(rq1 == rq2) | ||
681 | 813 | |||
682 | 814 | def test_equivalent_broker_requests_diff2(self): | ||
683 | 815 | rq1 = ceph_utils.CephBrokerRq() | ||
684 | 816 | rq1.add_op_create_pool(name='glance', replica_count=3) | ||
685 | 817 | rq2 = ceph_utils.CephBrokerRq() | ||
686 | 818 | rq2.add_op_create_pool(name='cinder', replica_count=3) | ||
687 | 819 | self.assertFalse(rq1 == rq2) | ||
688 | 820 | |||
689 | 821 | def test_equivalent_broker_requests_diff3(self): | ||
690 | 822 | rq1 = ceph_utils.CephBrokerRq() | ||
691 | 823 | rq1.add_op_create_pool(name='glance', replica_count=3) | ||
692 | 824 | rq2 = ceph_utils.CephBrokerRq(api_version=2) | ||
693 | 825 | rq2.add_op_create_pool(name='glance', replica_count=3) | ||
694 | 826 | self.assertFalse(rq1 == rq2) | ||
695 | 827 | |||
696 | 828 | @patch.object(ceph_utils, 'uuid') | ||
697 | 829 | @patch.object(ceph_utils, 'local_unit') | ||
698 | 830 | def test_is_request_complete_for_rid(self, mlocal_unit, muuid): | ||
699 | 831 | muuid.uuid1.return_value = '0bc7dc54' | ||
700 | 832 | req = ceph_utils.CephBrokerRq() | ||
701 | 833 | req.add_op_create_pool(name='glance', replica_count=3) | ||
702 | 834 | mlocal_unit.return_value = 'glance/0' | ||
703 | 835 | self.setup_client_relation(CEPH_CLIENT_RELATION) | ||
704 | 836 | self.assertTrue(ceph_utils.is_request_complete_for_rid(req, 'ceph:8')) | ||
705 | 837 | |||
706 | 838 | @patch.object(ceph_utils, 'uuid') | ||
707 | 839 | @patch.object(ceph_utils, 'local_unit') | ||
708 | 840 | def test_is_request_complete_for_rid_newrq(self, mlocal_unit, muuid): | ||
709 | 841 | muuid.uuid1.return_value = 'a44c0fa6' | ||
710 | 842 | req = ceph_utils.CephBrokerRq() | ||
711 | 843 | req.add_op_create_pool(name='glance', replica_count=4) | ||
712 | 844 | mlocal_unit.return_value = 'glance/0' | ||
713 | 845 | self.setup_client_relation(CEPH_CLIENT_RELATION) | ||
714 | 846 | self.assertFalse(ceph_utils.is_request_complete_for_rid(req, 'ceph:8')) | ||
715 | 847 | |||
716 | 848 | @patch.object(ceph_utils, 'uuid') | ||
717 | 849 | @patch.object(ceph_utils, 'local_unit') | ||
718 | 850 | def test_is_request_complete_for_rid_failed(self, mlocal_unit, muuid): | ||
719 | 851 | muuid.uuid1.return_value = '0bc7dc54' | ||
720 | 852 | req = ceph_utils.CephBrokerRq() | ||
721 | 853 | req.add_op_create_pool(name='glance', replica_count=4) | ||
722 | 854 | mlocal_unit.return_value = 'glance/0' | ||
723 | 855 | rel = copy.deepcopy(CEPH_CLIENT_RELATION) | ||
724 | 856 | rel['ceph:8']['ceph/0']['broker-rsp-glance-0'] = '{"request-id": "0bc7dc54", "exit-code": 1}' | ||
725 | 857 | self.setup_client_relation(rel) | ||
726 | 858 | self.assertFalse(ceph_utils.is_request_complete_for_rid(req, 'ceph:8')) | ||
727 | 859 | |||
728 | 860 | @patch.object(ceph_utils, 'uuid') | ||
729 | 861 | @patch.object(ceph_utils, 'local_unit') | ||
730 | 862 | def test_is_request_complete_for_rid_pending(self, mlocal_unit, muuid): | ||
731 | 863 | muuid.uuid1.return_value = '0bc7dc54' | ||
732 | 864 | req = ceph_utils.CephBrokerRq() | ||
733 | 865 | req.add_op_create_pool(name='glance', replica_count=4) | ||
734 | 866 | mlocal_unit.return_value = 'glance/0' | ||
735 | 867 | rel = copy.deepcopy(CEPH_CLIENT_RELATION) | ||
736 | 868 | del rel['ceph:8']['ceph/0']['broker-rsp-glance-0'] | ||
737 | 869 | self.setup_client_relation(rel) | ||
738 | 870 | self.assertFalse(ceph_utils.is_request_complete_for_rid(req, 'ceph:8')) | ||
739 | 871 | |||
740 | 872 | @patch.object(ceph_utils, 'uuid') | ||
741 | 873 | @patch.object(ceph_utils, 'local_unit') | ||
742 | 874 | def test_is_request_complete_for_rid_legacy(self, mlocal_unit, muuid): | ||
743 | 875 | muuid.uuid1.return_value = '0bc7dc54' | ||
744 | 876 | req = ceph_utils.CephBrokerRq() | ||
745 | 877 | req.add_op_create_pool(name='glance', replica_count=3) | ||
746 | 878 | mlocal_unit.return_value = 'glance/0' | ||
747 | 879 | self.setup_client_relation(CEPH_CLIENT_RELATION_LEGACY) | ||
748 | 880 | self.assertTrue(ceph_utils.is_request_complete_for_rid(req, 'ceph:8')) | ||
749 | 881 | |||
750 | 882 | @patch.object(ceph_utils, 'local_unit') | ||
751 | 883 | def test_get_broker_rsp_key(self, mlocal_unit): | ||
752 | 884 | mlocal_unit.return_value = 'glance/0' | ||
753 | 885 | self.assertEqual(ceph_utils.get_broker_rsp_key(), 'broker-rsp-glance-0') | ||
754 | 886 | |||
755 | 887 | @patch.object(ceph_utils, 'local_unit') | ||
756 | 888 | def test_send_request_if_needed(self, mlocal_unit): | ||
757 | 889 | mlocal_unit.return_value = 'glance/0' | ||
758 | 890 | self.setup_client_relation(CEPH_CLIENT_RELATION) | ||
759 | 891 | rq = ceph_utils.CephBrokerRq() | ||
760 | 892 | rq.add_op_create_pool(name='glance', replica_count=3) | ||
761 | 893 | ceph_utils.send_request_if_needed(rq) | ||
762 | 894 | self.relation_set.assert_has_calls([]) | ||
763 | 895 | |||
764 | 896 | @patch.object(ceph_utils, 'uuid') | ||
765 | 897 | @patch.object(ceph_utils, 'local_unit') | ||
766 | 898 | def test_send_request_if_needed_newrq(self, mlocal_unit, muuid): | ||
767 | 899 | muuid.uuid1.return_value = 'de67511e' | ||
768 | 900 | mlocal_unit.return_value = 'glance/0' | ||
769 | 901 | self.setup_client_relation(CEPH_CLIENT_RELATION) | ||
770 | 902 | rq = ceph_utils.CephBrokerRq() | ||
771 | 903 | rq.add_op_create_pool(name='glance', replica_count=4) | ||
772 | 904 | ceph_utils.send_request_if_needed(rq) | ||
773 | 905 | actual = json.loads(self.relation_set.call_args_list[0][1]['broker_req']) | ||
774 | 906 | self.assertEqual(actual['api-version'], 1) | ||
775 | 907 | self.assertEqual(actual['request-id'], 'de67511e') | ||
776 | 908 | self.assertEqual(actual['ops'][0]['replicas'], 4) | ||
777 | 909 | self.assertEqual(actual['ops'][0]['op'], 'create-pool') | ||
778 | 910 | self.assertEqual(actual['ops'][0]['name'], 'glance') | ||
779 | 582 | 911 | ||
780 | === modified file 'tests/helpers.py' | |||
781 | --- tests/helpers.py 2014-11-25 15:07:02 +0000 | |||
782 | +++ tests/helpers.py 2015-09-16 09:01:05 +0000 | |||
783 | @@ -74,12 +74,12 @@ | |||
784 | 74 | def __init__(self, relation_data): | 74 | def __init__(self, relation_data): |
785 | 75 | self.relation_data = relation_data | 75 | self.relation_data = relation_data |
786 | 76 | 76 | ||
788 | 77 | def get(self, attr=None, unit=None, rid=None): | 77 | def get(self, attribute=None, unit=None, rid=None): |
789 | 78 | if not rid or rid == 'foo:0': | 78 | if not rid or rid == 'foo:0': |
791 | 79 | if attr is None: | 79 | if attribute is None: |
792 | 80 | return self.relation_data | 80 | return self.relation_data |
795 | 81 | elif attr in self.relation_data: | 81 | elif attribute in self.relation_data: |
796 | 82 | return self.relation_data[attr] | 82 | return self.relation_data[attribute] |
797 | 83 | return None | 83 | return None |
798 | 84 | else: | 84 | else: |
799 | 85 | if rid not in self.relation_data: | 85 | if rid not in self.relation_data: |
800 | @@ -88,9 +88,9 @@ | |||
801 | 88 | relation = self.relation_data[rid][unit] | 88 | relation = self.relation_data[rid][unit] |
802 | 89 | except KeyError: | 89 | except KeyError: |
803 | 90 | return None | 90 | return None |
807 | 91 | if attr in relation: | 91 | if attribute and attribute in relation: |
808 | 92 | return relation[attr] | 92 | return relation[attribute] |
809 | 93 | return None | 93 | return relation |
810 | 94 | 94 | ||
811 | 95 | def relation_ids(self, relation=None): | 95 | def relation_ids(self, relation=None): |
812 | 96 | return self.relation_data.keys() | 96 | return self.relation_data.keys() |
Looks good. Same diff as for trunk. +1