Merge lp:~gnuoy/charms/trusty/glance/1453940-stable into lp:~openstack-charmers-archive/charms/trusty/glance/trunk
- Trusty Tahr (14.04)
- 1453940-stable
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 122 |
Proposed branch: | lp:~gnuoy/charms/trusty/glance/1453940-stable |
Merge into: | lp:~openstack-charmers-archive/charms/trusty/glance/trunk |
Diff against target: |
623 lines (+294/-73) 11 files modified
hooks/charmhelpers/cli/__init__.py (+1/-5) hooks/charmhelpers/cli/commands.py (+4/-4) hooks/charmhelpers/cli/hookenv.py (+23/-0) hooks/charmhelpers/contrib/openstack/context.py (+8/-9) hooks/charmhelpers/contrib/openstack/utils.py (+7/-5) hooks/charmhelpers/contrib/storage/linux/ceph.py (+224/-2) hooks/charmhelpers/core/hookenv.py (+1/-20) hooks/charmhelpers/core/host.py (+2/-2) hooks/glance_relations.py (+13/-19) templates/ceph.conf (+2/-1) unit_tests/test_glance_relations.py (+9/-6) |
To merge this branch: | bzr merge lp:~gnuoy/charms/trusty/glance/1453940-stable |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Chris Glass (community) | Approve | ||
Review via email: mp+271262@code.launchpad.net |
Commit message
Description of the change
uosci-testing-bot (uosci-testing-bot) wrote : | # |
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #6555 glance for gnuoy mp271262
AMULET FAIL: amulet-test failed
AMULET Results (max last 2 lines):
make: *** [functional_test] Error 1
ERROR:root:Make target returned non-zero.
Full amulet test output: http://
Build: http://
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #9626 glance for gnuoy mp271262
UNIT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #10437 glance for gnuoy mp271262
LINT OK: passed
Build: http://
- 125. By Liam Young
-
Empty commit to trigger osci
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #10458 glance for gnuoy mp271262
LINT OK: passed
Build: http://
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #9648 glance for gnuoy mp271262
UNIT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #6582 glance for gnuoy mp271262
AMULET OK: passed
Build: http://
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #6602 glance for gnuoy mp271262
AMULET OK: passed
Build: http://
Preview Diff
1 | === modified file 'hooks/charmhelpers/cli/__init__.py' | |||
2 | --- hooks/charmhelpers/cli/__init__.py 2015-08-10 16:34:51 +0000 | |||
3 | +++ hooks/charmhelpers/cli/__init__.py 2015-09-22 15:21:44 +0000 | |||
4 | @@ -152,15 +152,11 @@ | |||
5 | 152 | arguments = self.argument_parser.parse_args() | 152 | arguments = self.argument_parser.parse_args() |
6 | 153 | argspec = inspect.getargspec(arguments.func) | 153 | argspec = inspect.getargspec(arguments.func) |
7 | 154 | vargs = [] | 154 | vargs = [] |
8 | 155 | kwargs = {} | ||
9 | 156 | for arg in argspec.args: | 155 | for arg in argspec.args: |
10 | 157 | vargs.append(getattr(arguments, arg)) | 156 | vargs.append(getattr(arguments, arg)) |
11 | 158 | if argspec.varargs: | 157 | if argspec.varargs: |
12 | 159 | vargs.extend(getattr(arguments, argspec.varargs)) | 158 | vargs.extend(getattr(arguments, argspec.varargs)) |
17 | 160 | if argspec.keywords: | 159 | output = arguments.func(*vargs) |
14 | 161 | for kwarg in argspec.keywords.items(): | ||
15 | 162 | kwargs[kwarg] = getattr(arguments, kwarg) | ||
16 | 163 | output = arguments.func(*vargs, **kwargs) | ||
18 | 164 | if getattr(arguments.func, '_cli_test_command', False): | 160 | if getattr(arguments.func, '_cli_test_command', False): |
19 | 165 | self.exit_code = 0 if output else 1 | 161 | self.exit_code = 0 if output else 1 |
20 | 166 | output = '' | 162 | output = '' |
21 | 167 | 163 | ||
22 | === modified file 'hooks/charmhelpers/cli/commands.py' | |||
23 | --- hooks/charmhelpers/cli/commands.py 2015-08-10 16:34:51 +0000 | |||
24 | +++ hooks/charmhelpers/cli/commands.py 2015-09-22 15:21:44 +0000 | |||
25 | @@ -26,7 +26,7 @@ | |||
26 | 26 | """ | 26 | """ |
27 | 27 | Import the sub-modules which have decorated subcommands to register with chlp. | 27 | Import the sub-modules which have decorated subcommands to register with chlp. |
28 | 28 | """ | 28 | """ |
33 | 29 | import host # noqa | 29 | from . import host # noqa |
34 | 30 | import benchmark # noqa | 30 | from . import benchmark # noqa |
35 | 31 | import unitdata # noqa | 31 | from . import unitdata # noqa |
36 | 32 | from charmhelpers.core import hookenv # noqa | 32 | from . import hookenv # noqa |
37 | 33 | 33 | ||
38 | === added file 'hooks/charmhelpers/cli/hookenv.py' | |||
39 | --- hooks/charmhelpers/cli/hookenv.py 1970-01-01 00:00:00 +0000 | |||
40 | +++ hooks/charmhelpers/cli/hookenv.py 2015-09-22 15:21:44 +0000 | |||
41 | @@ -0,0 +1,23 @@ | |||
42 | 1 | # Copyright 2014-2015 Canonical Limited. | ||
43 | 2 | # | ||
44 | 3 | # This file is part of charm-helpers. | ||
45 | 4 | # | ||
46 | 5 | # charm-helpers is free software: you can redistribute it and/or modify | ||
47 | 6 | # it under the terms of the GNU Lesser General Public License version 3 as | ||
48 | 7 | # published by the Free Software Foundation. | ||
49 | 8 | # | ||
50 | 9 | # charm-helpers is distributed in the hope that it will be useful, | ||
51 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
52 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
53 | 12 | # GNU Lesser General Public License for more details. | ||
54 | 13 | # | ||
55 | 14 | # You should have received a copy of the GNU Lesser General Public License | ||
56 | 15 | # along with charm-helpers. If not, see <http://www.gnu.org/licenses/>. | ||
57 | 16 | |||
58 | 17 | from . import cmdline | ||
59 | 18 | from charmhelpers.core import hookenv | ||
60 | 19 | |||
61 | 20 | |||
62 | 21 | cmdline.subcommand('relation-id')(hookenv.relation_id._wrapped) | ||
63 | 22 | cmdline.subcommand('service-name')(hookenv.service_name) | ||
64 | 23 | cmdline.subcommand('remote-service-name')(hookenv.remote_service_name._wrapped) | ||
65 | 0 | 24 | ||
66 | === modified file 'hooks/charmhelpers/contrib/openstack/context.py' | |||
67 | --- hooks/charmhelpers/contrib/openstack/context.py 2015-08-10 16:34:51 +0000 | |||
68 | +++ hooks/charmhelpers/contrib/openstack/context.py 2015-09-22 15:21:44 +0000 | |||
69 | @@ -483,13 +483,15 @@ | |||
70 | 483 | 483 | ||
71 | 484 | log('Generating template context for ceph', level=DEBUG) | 484 | log('Generating template context for ceph', level=DEBUG) |
72 | 485 | mon_hosts = [] | 485 | mon_hosts = [] |
76 | 486 | auth = None | 486 | ctxt = { |
77 | 487 | key = None | 487 | 'use_syslog': str(config('use-syslog')).lower() |
78 | 488 | use_syslog = str(config('use-syslog')).lower() | 488 | } |
79 | 489 | for rid in relation_ids('ceph'): | 489 | for rid in relation_ids('ceph'): |
80 | 490 | for unit in related_units(rid): | 490 | for unit in related_units(rid): |
83 | 491 | auth = relation_get('auth', rid=rid, unit=unit) | 491 | if not ctxt.get('auth'): |
84 | 492 | key = relation_get('key', rid=rid, unit=unit) | 492 | ctxt['auth'] = relation_get('auth', rid=rid, unit=unit) |
85 | 493 | if not ctxt.get('key'): | ||
86 | 494 | ctxt['key'] = relation_get('key', rid=rid, unit=unit) | ||
87 | 493 | ceph_pub_addr = relation_get('ceph-public-address', rid=rid, | 495 | ceph_pub_addr = relation_get('ceph-public-address', rid=rid, |
88 | 494 | unit=unit) | 496 | unit=unit) |
89 | 495 | unit_priv_addr = relation_get('private-address', rid=rid, | 497 | unit_priv_addr = relation_get('private-address', rid=rid, |
90 | @@ -498,10 +500,7 @@ | |||
91 | 498 | ceph_addr = format_ipv6_addr(ceph_addr) or ceph_addr | 500 | ceph_addr = format_ipv6_addr(ceph_addr) or ceph_addr |
92 | 499 | mon_hosts.append(ceph_addr) | 501 | mon_hosts.append(ceph_addr) |
93 | 500 | 502 | ||
98 | 501 | ctxt = {'mon_hosts': ' '.join(sorted(mon_hosts)), | 503 | ctxt['mon_hosts'] = ' '.join(sorted(mon_hosts)) |
95 | 502 | 'auth': auth, | ||
96 | 503 | 'key': key, | ||
97 | 504 | 'use_syslog': use_syslog} | ||
99 | 505 | 504 | ||
100 | 506 | if not os.path.isdir('/etc/ceph'): | 505 | if not os.path.isdir('/etc/ceph'): |
101 | 507 | os.mkdir('/etc/ceph') | 506 | os.mkdir('/etc/ceph') |
102 | 508 | 507 | ||
103 | === modified file 'hooks/charmhelpers/contrib/openstack/utils.py' | |||
104 | --- hooks/charmhelpers/contrib/openstack/utils.py 2015-08-10 16:34:51 +0000 | |||
105 | +++ hooks/charmhelpers/contrib/openstack/utils.py 2015-09-22 15:21:44 +0000 | |||
106 | @@ -1,5 +1,3 @@ | |||
107 | 1 | #!/usr/bin/python | ||
108 | 2 | |||
109 | 3 | # Copyright 2014-2015 Canonical Limited. | 1 | # Copyright 2014-2015 Canonical Limited. |
110 | 4 | # | 2 | # |
111 | 5 | # This file is part of charm-helpers. | 3 | # This file is part of charm-helpers. |
112 | @@ -167,9 +165,9 @@ | |||
113 | 167 | error_out(e) | 165 | error_out(e) |
114 | 168 | 166 | ||
115 | 169 | 167 | ||
117 | 170 | def get_os_version_codename(codename): | 168 | def get_os_version_codename(codename, version_map=OPENSTACK_CODENAMES): |
118 | 171 | '''Determine OpenStack version number from codename.''' | 169 | '''Determine OpenStack version number from codename.''' |
120 | 172 | for k, v in six.iteritems(OPENSTACK_CODENAMES): | 170 | for k, v in six.iteritems(version_map): |
121 | 173 | if v == codename: | 171 | if v == codename: |
122 | 174 | return k | 172 | return k |
123 | 175 | e = 'Could not derive OpenStack version for '\ | 173 | e = 'Could not derive OpenStack version for '\ |
124 | @@ -392,7 +390,11 @@ | |||
125 | 392 | import apt_pkg as apt | 390 | import apt_pkg as apt |
126 | 393 | src = config('openstack-origin') | 391 | src = config('openstack-origin') |
127 | 394 | cur_vers = get_os_version_package(package) | 392 | cur_vers = get_os_version_package(package) |
129 | 395 | available_vers = get_os_version_install_source(src) | 393 | if "swift" in package: |
130 | 394 | codename = get_os_codename_install_source(src) | ||
131 | 395 | available_vers = get_os_version_codename(codename, SWIFT_CODENAMES) | ||
132 | 396 | else: | ||
133 | 397 | available_vers = get_os_version_install_source(src) | ||
134 | 396 | apt.init() | 398 | apt.init() |
135 | 397 | return apt.version_compare(available_vers, cur_vers) == 1 | 399 | return apt.version_compare(available_vers, cur_vers) == 1 |
136 | 398 | 400 | ||
137 | 399 | 401 | ||
138 | === modified file 'hooks/charmhelpers/contrib/storage/linux/ceph.py' | |||
139 | --- hooks/charmhelpers/contrib/storage/linux/ceph.py 2015-08-10 16:34:51 +0000 | |||
140 | +++ hooks/charmhelpers/contrib/storage/linux/ceph.py 2015-09-22 15:21:44 +0000 | |||
141 | @@ -28,6 +28,7 @@ | |||
142 | 28 | import shutil | 28 | import shutil |
143 | 29 | import json | 29 | import json |
144 | 30 | import time | 30 | import time |
145 | 31 | import uuid | ||
146 | 31 | 32 | ||
147 | 32 | from subprocess import ( | 33 | from subprocess import ( |
148 | 33 | check_call, | 34 | check_call, |
149 | @@ -35,8 +36,10 @@ | |||
150 | 35 | CalledProcessError, | 36 | CalledProcessError, |
151 | 36 | ) | 37 | ) |
152 | 37 | from charmhelpers.core.hookenv import ( | 38 | from charmhelpers.core.hookenv import ( |
153 | 39 | local_unit, | ||
154 | 38 | relation_get, | 40 | relation_get, |
155 | 39 | relation_ids, | 41 | relation_ids, |
156 | 42 | relation_set, | ||
157 | 40 | related_units, | 43 | related_units, |
158 | 41 | log, | 44 | log, |
159 | 42 | DEBUG, | 45 | DEBUG, |
160 | @@ -411,17 +414,52 @@ | |||
161 | 411 | 414 | ||
162 | 412 | The API is versioned and defaults to version 1. | 415 | The API is versioned and defaults to version 1. |
163 | 413 | """ | 416 | """ |
165 | 414 | def __init__(self, api_version=1): | 417 | def __init__(self, api_version=1, request_id=None): |
166 | 415 | self.api_version = api_version | 418 | self.api_version = api_version |
167 | 419 | if request_id: | ||
168 | 420 | self.request_id = request_id | ||
169 | 421 | else: | ||
170 | 422 | self.request_id = str(uuid.uuid1()) | ||
171 | 416 | self.ops = [] | 423 | self.ops = [] |
172 | 417 | 424 | ||
173 | 418 | def add_op_create_pool(self, name, replica_count=3): | 425 | def add_op_create_pool(self, name, replica_count=3): |
174 | 419 | self.ops.append({'op': 'create-pool', 'name': name, | 426 | self.ops.append({'op': 'create-pool', 'name': name, |
175 | 420 | 'replicas': replica_count}) | 427 | 'replicas': replica_count}) |
176 | 421 | 428 | ||
177 | 429 | def set_ops(self, ops): | ||
178 | 430 | """Set request ops to provided value. | ||
179 | 431 | |||
180 | 432 | Useful for injecting ops that come from a previous request | ||
181 | 433 | to allow comparisons to ensure validity. | ||
182 | 434 | """ | ||
183 | 435 | self.ops = ops | ||
184 | 436 | |||
185 | 422 | @property | 437 | @property |
186 | 423 | def request(self): | 438 | def request(self): |
188 | 424 | return json.dumps({'api-version': self.api_version, 'ops': self.ops}) | 439 | return json.dumps({'api-version': self.api_version, 'ops': self.ops, |
189 | 440 | 'request-id': self.request_id}) | ||
190 | 441 | |||
191 | 442 | def _ops_equal(self, other): | ||
192 | 443 | if len(self.ops) == len(other.ops): | ||
193 | 444 | for req_no in range(0, len(self.ops)): | ||
194 | 445 | for key in ['replicas', 'name', 'op']: | ||
195 | 446 | if self.ops[req_no][key] != other.ops[req_no][key]: | ||
196 | 447 | return False | ||
197 | 448 | else: | ||
198 | 449 | return False | ||
199 | 450 | return True | ||
200 | 451 | |||
201 | 452 | def __eq__(self, other): | ||
202 | 453 | if not isinstance(other, self.__class__): | ||
203 | 454 | return False | ||
204 | 455 | if self.api_version == other.api_version and \ | ||
205 | 456 | self._ops_equal(other): | ||
206 | 457 | return True | ||
207 | 458 | else: | ||
208 | 459 | return False | ||
209 | 460 | |||
210 | 461 | def __ne__(self, other): | ||
211 | 462 | return not self.__eq__(other) | ||
212 | 425 | 463 | ||
213 | 426 | 464 | ||
214 | 427 | class CephBrokerRsp(object): | 465 | class CephBrokerRsp(object): |
215 | @@ -431,14 +469,198 @@ | |||
216 | 431 | 469 | ||
217 | 432 | The API is versioned and defaults to version 1. | 470 | The API is versioned and defaults to version 1. |
218 | 433 | """ | 471 | """ |
219 | 472 | |||
220 | 434 | def __init__(self, encoded_rsp): | 473 | def __init__(self, encoded_rsp): |
221 | 435 | self.api_version = None | 474 | self.api_version = None |
222 | 436 | self.rsp = json.loads(encoded_rsp) | 475 | self.rsp = json.loads(encoded_rsp) |
223 | 437 | 476 | ||
224 | 438 | @property | 477 | @property |
225 | 478 | def request_id(self): | ||
226 | 479 | return self.rsp.get('request-id') | ||
227 | 480 | |||
228 | 481 | @property | ||
229 | 439 | def exit_code(self): | 482 | def exit_code(self): |
230 | 440 | return self.rsp.get('exit-code') | 483 | return self.rsp.get('exit-code') |
231 | 441 | 484 | ||
232 | 442 | @property | 485 | @property |
233 | 443 | def exit_msg(self): | 486 | def exit_msg(self): |
234 | 444 | return self.rsp.get('stderr') | 487 | return self.rsp.get('stderr') |
235 | 488 | |||
236 | 489 | |||
237 | 490 | # Ceph Broker Conversation: | ||
238 | 491 | # If a charm needs an action to be taken by ceph it can create a CephBrokerRq | ||
239 | 492 | # and send that request to ceph via the ceph relation. The CephBrokerRq has a | ||
240 | 493 | # unique id so that the client can identity which CephBrokerRsp is associated | ||
241 | 494 | # with the request. Ceph will also respond to each client unit individually | ||
242 | 495 | # creating a response key per client unit eg glance/0 will get a CephBrokerRsp | ||
243 | 496 | # via key broker-rsp-glance-0 | ||
244 | 497 | # | ||
245 | 498 | # To use this the charm can just do something like: | ||
246 | 499 | # | ||
247 | 500 | # from charmhelpers.contrib.storage.linux.ceph import ( | ||
248 | 501 | # send_request_if_needed, | ||
249 | 502 | # is_request_complete, | ||
250 | 503 | # CephBrokerRq, | ||
251 | 504 | # ) | ||
252 | 505 | # | ||
253 | 506 | # @hooks.hook('ceph-relation-changed') | ||
254 | 507 | # def ceph_changed(): | ||
255 | 508 | # rq = CephBrokerRq() | ||
256 | 509 | # rq.add_op_create_pool(name='poolname', replica_count=3) | ||
257 | 510 | # | ||
258 | 511 | # if is_request_complete(rq): | ||
259 | 512 | # <Request complete actions> | ||
260 | 513 | # else: | ||
261 | 514 | # send_request_if_needed(get_ceph_request()) | ||
262 | 515 | # | ||
263 | 516 | # CephBrokerRq and CephBrokerRsp are serialized into JSON. Below is an example | ||
264 | 517 | # of glance having sent a request to ceph which ceph has successfully processed | ||
265 | 518 | # 'ceph:8': { | ||
266 | 519 | # 'ceph/0': { | ||
267 | 520 | # 'auth': 'cephx', | ||
268 | 521 | # 'broker-rsp-glance-0': '{"request-id": "0bc7dc54", "exit-code": 0}', | ||
269 | 522 | # 'broker_rsp': '{"request-id": "0da543b8", "exit-code": 0}', | ||
270 | 523 | # 'ceph-public-address': '10.5.44.103', | ||
271 | 524 | # 'key': 'AQCLDttVuHXINhAAvI144CB09dYchhHyTUY9BQ==', | ||
272 | 525 | # 'private-address': '10.5.44.103', | ||
273 | 526 | # }, | ||
274 | 527 | # 'glance/0': { | ||
275 | 528 | # 'broker_req': ('{"api-version": 1, "request-id": "0bc7dc54", ' | ||
276 | 529 | # '"ops": [{"replicas": 3, "name": "glance", ' | ||
277 | 530 | # '"op": "create-pool"}]}'), | ||
278 | 531 | # 'private-address': '10.5.44.109', | ||
279 | 532 | # }, | ||
280 | 533 | # } | ||
281 | 534 | |||
282 | 535 | def get_previous_request(rid): | ||
283 | 536 | """Return the last ceph broker request sent on a given relation | ||
284 | 537 | |||
285 | 538 | @param rid: Relation id to query for request | ||
286 | 539 | """ | ||
287 | 540 | request = None | ||
288 | 541 | broker_req = relation_get(attribute='broker_req', rid=rid, | ||
289 | 542 | unit=local_unit()) | ||
290 | 543 | if broker_req: | ||
291 | 544 | request_data = json.loads(broker_req) | ||
292 | 545 | request = CephBrokerRq(api_version=request_data['api-version'], | ||
293 | 546 | request_id=request_data['request-id']) | ||
294 | 547 | request.set_ops(request_data['ops']) | ||
295 | 548 | |||
296 | 549 | return request | ||
297 | 550 | |||
298 | 551 | |||
299 | 552 | def get_request_states(request): | ||
300 | 553 | """Return a dict of requests per relation id with their corresponding | ||
301 | 554 | completion state. | ||
302 | 555 | |||
303 | 556 | This allows a charm, which has a request for ceph, to see whether there is | ||
304 | 557 | an equivalent request already being processed and if so what state that | ||
305 | 558 | request is in. | ||
306 | 559 | |||
307 | 560 | @param request: A CephBrokerRq object | ||
308 | 561 | """ | ||
309 | 562 | complete = [] | ||
310 | 563 | requests = {} | ||
311 | 564 | for rid in relation_ids('ceph'): | ||
312 | 565 | complete = False | ||
313 | 566 | previous_request = get_previous_request(rid) | ||
314 | 567 | if request == previous_request: | ||
315 | 568 | sent = True | ||
316 | 569 | complete = is_request_complete_for_rid(previous_request, rid) | ||
317 | 570 | else: | ||
318 | 571 | sent = False | ||
319 | 572 | complete = False | ||
320 | 573 | |||
321 | 574 | requests[rid] = { | ||
322 | 575 | 'sent': sent, | ||
323 | 576 | 'complete': complete, | ||
324 | 577 | } | ||
325 | 578 | |||
326 | 579 | return requests | ||
327 | 580 | |||
328 | 581 | |||
329 | 582 | def is_request_sent(request): | ||
330 | 583 | """Check to see if a functionally equivalent request has already been sent | ||
331 | 584 | |||
332 | 585 | Returns True if a similair request has been sent | ||
333 | 586 | |||
334 | 587 | @param request: A CephBrokerRq object | ||
335 | 588 | """ | ||
336 | 589 | states = get_request_states(request) | ||
337 | 590 | for rid in states.keys(): | ||
338 | 591 | if not states[rid]['sent']: | ||
339 | 592 | return False | ||
340 | 593 | |||
341 | 594 | return True | ||
342 | 595 | |||
343 | 596 | |||
344 | 597 | def is_request_complete(request): | ||
345 | 598 | """Check to see if a functionally equivalent request has already been | ||
346 | 599 | completed | ||
347 | 600 | |||
348 | 601 | Returns True if a similair request has been completed | ||
349 | 602 | |||
350 | 603 | @param request: A CephBrokerRq object | ||
351 | 604 | """ | ||
352 | 605 | states = get_request_states(request) | ||
353 | 606 | for rid in states.keys(): | ||
354 | 607 | if not states[rid]['complete']: | ||
355 | 608 | return False | ||
356 | 609 | |||
357 | 610 | return True | ||
358 | 611 | |||
359 | 612 | |||
360 | 613 | def is_request_complete_for_rid(request, rid): | ||
361 | 614 | """Check if a given request has been completed on the given relation | ||
362 | 615 | |||
363 | 616 | @param request: A CephBrokerRq object | ||
364 | 617 | @param rid: Relation ID | ||
365 | 618 | """ | ||
366 | 619 | broker_key = get_broker_rsp_key() | ||
367 | 620 | for unit in related_units(rid): | ||
368 | 621 | rdata = relation_get(rid=rid, unit=unit) | ||
369 | 622 | if rdata.get(broker_key): | ||
370 | 623 | rsp = CephBrokerRsp(rdata.get(broker_key)) | ||
371 | 624 | if rsp.request_id == request.request_id: | ||
372 | 625 | if not rsp.exit_code: | ||
373 | 626 | return True | ||
374 | 627 | else: | ||
375 | 628 | # The remote unit sent no reply targeted at this unit so either the | ||
376 | 629 | # remote ceph cluster does not support unit targeted replies or it | ||
377 | 630 | # has not processed our request yet. | ||
378 | 631 | if rdata.get('broker_rsp'): | ||
379 | 632 | request_data = json.loads(rdata['broker_rsp']) | ||
380 | 633 | if request_data.get('request-id'): | ||
381 | 634 | log('Ignoring legacy broker_rsp without unit key as remote ' | ||
382 | 635 | 'service supports unit specific replies', level=DEBUG) | ||
383 | 636 | else: | ||
384 | 637 | log('Using legacy broker_rsp as remote service does not ' | ||
385 | 638 | 'supports unit specific replies', level=DEBUG) | ||
386 | 639 | rsp = CephBrokerRsp(rdata['broker_rsp']) | ||
387 | 640 | if not rsp.exit_code: | ||
388 | 641 | return True | ||
389 | 642 | |||
390 | 643 | return False | ||
391 | 644 | |||
392 | 645 | |||
393 | 646 | def get_broker_rsp_key(): | ||
394 | 647 | """Return broker response key for this unit | ||
395 | 648 | |||
396 | 649 | This is the key that ceph is going to use to pass request status | ||
397 | 650 | information back to this unit | ||
398 | 651 | """ | ||
399 | 652 | return 'broker-rsp-' + local_unit().replace('/', '-') | ||
400 | 653 | |||
401 | 654 | |||
402 | 655 | def send_request_if_needed(request): | ||
403 | 656 | """Send broker request if an equivalent request has not already been sent | ||
404 | 657 | |||
405 | 658 | @param request: A CephBrokerRq object | ||
406 | 659 | """ | ||
407 | 660 | if is_request_sent(request): | ||
408 | 661 | log('Request already sent but not complete, not sending new request', | ||
409 | 662 | level=DEBUG) | ||
410 | 663 | else: | ||
411 | 664 | for rid in relation_ids('ceph'): | ||
412 | 665 | log('Sending request {}'.format(request.request_id), level=DEBUG) | ||
413 | 666 | relation_set(relation_id=rid, broker_req=request.request) | ||
414 | 445 | 667 | ||
415 | === modified file 'hooks/charmhelpers/core/hookenv.py' | |||
416 | --- hooks/charmhelpers/core/hookenv.py 2015-08-10 16:34:51 +0000 | |||
417 | +++ hooks/charmhelpers/core/hookenv.py 2015-09-22 15:21:44 +0000 | |||
418 | @@ -34,23 +34,6 @@ | |||
419 | 34 | import tempfile | 34 | import tempfile |
420 | 35 | from subprocess import CalledProcessError | 35 | from subprocess import CalledProcessError |
421 | 36 | 36 | ||
422 | 37 | try: | ||
423 | 38 | from charmhelpers.cli import cmdline | ||
424 | 39 | except ImportError as e: | ||
425 | 40 | # due to the anti-pattern of partially synching charmhelpers directly | ||
426 | 41 | # into charms, it's possible that charmhelpers.cli is not available; | ||
427 | 42 | # if that's the case, they don't really care about using the cli anyway, | ||
428 | 43 | # so mock it out | ||
429 | 44 | if str(e) == 'No module named cli': | ||
430 | 45 | class cmdline(object): | ||
431 | 46 | @classmethod | ||
432 | 47 | def subcommand(cls, *args, **kwargs): | ||
433 | 48 | def _wrap(func): | ||
434 | 49 | return func | ||
435 | 50 | return _wrap | ||
436 | 51 | else: | ||
437 | 52 | raise | ||
438 | 53 | |||
439 | 54 | import six | 37 | import six |
440 | 55 | if not six.PY3: | 38 | if not six.PY3: |
441 | 56 | from UserDict import UserDict | 39 | from UserDict import UserDict |
442 | @@ -91,6 +74,7 @@ | |||
443 | 91 | res = func(*args, **kwargs) | 74 | res = func(*args, **kwargs) |
444 | 92 | cache[key] = res | 75 | cache[key] = res |
445 | 93 | return res | 76 | return res |
446 | 77 | wrapper._wrapped = func | ||
447 | 94 | return wrapper | 78 | return wrapper |
448 | 95 | 79 | ||
449 | 96 | 80 | ||
450 | @@ -190,7 +174,6 @@ | |||
451 | 190 | return os.environ.get('JUJU_RELATION', None) | 174 | return os.environ.get('JUJU_RELATION', None) |
452 | 191 | 175 | ||
453 | 192 | 176 | ||
454 | 193 | @cmdline.subcommand() | ||
455 | 194 | @cached | 177 | @cached |
456 | 195 | def relation_id(relation_name=None, service_or_unit=None): | 178 | def relation_id(relation_name=None, service_or_unit=None): |
457 | 196 | """The relation ID for the current or a specified relation""" | 179 | """The relation ID for the current or a specified relation""" |
458 | @@ -216,13 +199,11 @@ | |||
459 | 216 | return os.environ.get('JUJU_REMOTE_UNIT', None) | 199 | return os.environ.get('JUJU_REMOTE_UNIT', None) |
460 | 217 | 200 | ||
461 | 218 | 201 | ||
462 | 219 | @cmdline.subcommand() | ||
463 | 220 | def service_name(): | 202 | def service_name(): |
464 | 221 | """The name service group this unit belongs to""" | 203 | """The name service group this unit belongs to""" |
465 | 222 | return local_unit().split('/')[0] | 204 | return local_unit().split('/')[0] |
466 | 223 | 205 | ||
467 | 224 | 206 | ||
468 | 225 | @cmdline.subcommand() | ||
469 | 226 | @cached | 207 | @cached |
470 | 227 | def remote_service_name(relid=None): | 208 | def remote_service_name(relid=None): |
471 | 228 | """The remote service name for a given relation-id (or the current relation)""" | 209 | """The remote service name for a given relation-id (or the current relation)""" |
472 | 229 | 210 | ||
473 | === modified file 'hooks/charmhelpers/core/host.py' | |||
474 | --- hooks/charmhelpers/core/host.py 2015-08-10 16:34:51 +0000 | |||
475 | +++ hooks/charmhelpers/core/host.py 2015-09-22 15:21:44 +0000 | |||
476 | @@ -72,7 +72,7 @@ | |||
477 | 72 | stopped = service_stop(service_name) | 72 | stopped = service_stop(service_name) |
478 | 73 | # XXX: Support systemd too | 73 | # XXX: Support systemd too |
479 | 74 | override_path = os.path.join( | 74 | override_path = os.path.join( |
481 | 75 | init_dir, '{}.conf.override'.format(service_name)) | 75 | init_dir, '{}.override'.format(service_name)) |
482 | 76 | with open(override_path, 'w') as fh: | 76 | with open(override_path, 'w') as fh: |
483 | 77 | fh.write("manual\n") | 77 | fh.write("manual\n") |
484 | 78 | return stopped | 78 | return stopped |
485 | @@ -86,7 +86,7 @@ | |||
486 | 86 | if init_dir is None: | 86 | if init_dir is None: |
487 | 87 | init_dir = "/etc/init" | 87 | init_dir = "/etc/init" |
488 | 88 | override_path = os.path.join( | 88 | override_path = os.path.join( |
490 | 89 | init_dir, '{}.conf.override'.format(service_name)) | 89 | init_dir, '{}.override'.format(service_name)) |
491 | 90 | if os.path.exists(override_path): | 90 | if os.path.exists(override_path): |
492 | 91 | os.unlink(override_path) | 91 | os.unlink(override_path) |
493 | 92 | started = service_start(service_name) | 92 | started = service_start(service_name) |
494 | 93 | 93 | ||
495 | === modified file 'hooks/glance_relations.py' | |||
496 | --- hooks/glance_relations.py 2015-08-10 16:34:51 +0000 | |||
497 | +++ hooks/glance_relations.py 2015-09-22 15:21:44 +0000 | |||
498 | @@ -29,7 +29,6 @@ | |||
499 | 29 | config, | 29 | config, |
500 | 30 | Hooks, | 30 | Hooks, |
501 | 31 | log as juju_log, | 31 | log as juju_log, |
502 | 32 | INFO, | ||
503 | 33 | ERROR, | 32 | ERROR, |
504 | 34 | open_port, | 33 | open_port, |
505 | 35 | is_relation_made, | 34 | is_relation_made, |
506 | @@ -66,9 +65,10 @@ | |||
507 | 66 | sync_db_with_multi_ipv6_addresses, | 65 | sync_db_with_multi_ipv6_addresses, |
508 | 67 | ) | 66 | ) |
509 | 68 | from charmhelpers.contrib.storage.linux.ceph import ( | 67 | from charmhelpers.contrib.storage.linux.ceph import ( |
510 | 68 | send_request_if_needed, | ||
511 | 69 | is_request_complete, | ||
512 | 69 | ensure_ceph_keyring, | 70 | ensure_ceph_keyring, |
513 | 70 | CephBrokerRq, | 71 | CephBrokerRq, |
514 | 71 | CephBrokerRsp, | ||
515 | 72 | delete_keyring, | 72 | delete_keyring, |
516 | 73 | ) | 73 | ) |
517 | 74 | from charmhelpers.payload.execd import ( | 74 | from charmhelpers.payload.execd import ( |
518 | @@ -240,6 +240,14 @@ | |||
519 | 240 | apt_install(['ceph-common', 'python-ceph']) | 240 | apt_install(['ceph-common', 'python-ceph']) |
520 | 241 | 241 | ||
521 | 242 | 242 | ||
522 | 243 | def get_ceph_request(): | ||
523 | 244 | service = service_name() | ||
524 | 245 | rq = CephBrokerRq() | ||
525 | 246 | replicas = config('ceph-osd-replication-count') | ||
526 | 247 | rq.add_op_create_pool(name=service, replica_count=replicas) | ||
527 | 248 | return rq | ||
528 | 249 | |||
529 | 250 | |||
530 | 243 | @hooks.hook('ceph-relation-changed') | 251 | @hooks.hook('ceph-relation-changed') |
531 | 244 | @restart_on_change(restart_map()) | 252 | @restart_on_change(restart_map()) |
532 | 245 | def ceph_changed(): | 253 | def ceph_changed(): |
533 | @@ -253,29 +261,15 @@ | |||
534 | 253 | juju_log('Could not create ceph keyring: peer not ready?') | 261 | juju_log('Could not create ceph keyring: peer not ready?') |
535 | 254 | return | 262 | return |
536 | 255 | 263 | ||
548 | 256 | settings = relation_get() | 264 | if is_request_complete(get_ceph_request()): |
549 | 257 | if settings and 'broker_rsp' in settings: | 265 | juju_log('Request complete') |
539 | 258 | rsp = CephBrokerRsp(settings['broker_rsp']) | ||
540 | 259 | # Non-zero return code implies failure | ||
541 | 260 | if rsp.exit_code: | ||
542 | 261 | juju_log("Ceph broker request failed (rc=%s, msg=%s)" % | ||
543 | 262 | (rsp.exit_code, rsp.exit_msg), level=ERROR) | ||
544 | 263 | return | ||
545 | 264 | |||
546 | 265 | juju_log("Ceph broker request succeeded (rc=%s, msg=%s)" % | ||
547 | 266 | (rsp.exit_code, rsp.exit_msg), level=INFO) | ||
550 | 267 | CONFIGS.write(GLANCE_API_CONF) | 266 | CONFIGS.write(GLANCE_API_CONF) |
551 | 268 | CONFIGS.write(ceph_config_file()) | 267 | CONFIGS.write(ceph_config_file()) |
552 | 269 | # Ensure that glance-api is restarted since only now can we | 268 | # Ensure that glance-api is restarted since only now can we |
553 | 270 | # guarantee that ceph resources are ready. | 269 | # guarantee that ceph resources are ready. |
554 | 271 | service_restart('glance-api') | 270 | service_restart('glance-api') |
555 | 272 | else: | 271 | else: |
562 | 273 | rq = CephBrokerRq() | 272 | send_request_if_needed(get_ceph_request()) |
557 | 274 | replicas = config('ceph-osd-replication-count') | ||
558 | 275 | rq.add_op_create_pool(name=service, replica_count=replicas) | ||
559 | 276 | for rid in relation_ids('ceph'): | ||
560 | 277 | relation_set(relation_id=rid, broker_req=rq.request) | ||
561 | 278 | juju_log("Request(s) sent to Ceph broker (rid=%s)" % (rid)) | ||
563 | 279 | 273 | ||
564 | 280 | 274 | ||
565 | 281 | @hooks.hook('ceph-relation-broken') | 275 | @hooks.hook('ceph-relation-broken') |
566 | 282 | 276 | ||
567 | === modified file 'templates/ceph.conf' | |||
568 | --- templates/ceph.conf 2014-03-25 18:44:22 +0000 | |||
569 | +++ templates/ceph.conf 2015-09-22 15:21:44 +0000 | |||
570 | @@ -10,7 +10,8 @@ | |||
571 | 10 | keyring = /etc/ceph/ceph.$name.keyring | 10 | keyring = /etc/ceph/ceph.$name.keyring |
572 | 11 | mon host = {{ mon_hosts }} | 11 | mon host = {{ mon_hosts }} |
573 | 12 | {% endif -%} | 12 | {% endif -%} |
574 | 13 | {% if use_syslog -%} | ||
575 | 13 | log to syslog = {{ use_syslog }} | 14 | log to syslog = {{ use_syslog }} |
576 | 14 | err to syslog = {{ use_syslog }} | 15 | err to syslog = {{ use_syslog }} |
577 | 15 | clog to syslog = {{ use_syslog }} | 16 | clog to syslog = {{ use_syslog }} |
579 | 16 | 17 | {% endif -%} | |
580 | 17 | 18 | ||
581 | === modified file 'unit_tests/test_glance_relations.py' | |||
582 | --- unit_tests/test_glance_relations.py 2015-08-10 16:34:51 +0000 | |||
583 | +++ unit_tests/test_glance_relations.py 2015-09-22 15:21:44 +0000 | |||
584 | @@ -68,6 +68,9 @@ | |||
585 | 68 | 'get_ipv6_addr', | 68 | 'get_ipv6_addr', |
586 | 69 | 'sync_db_with_multi_ipv6_addresses', | 69 | 'sync_db_with_multi_ipv6_addresses', |
587 | 70 | 'delete_keyring', | 70 | 'delete_keyring', |
588 | 71 | 'is_request_complete', | ||
589 | 72 | 'send_request_if_needed', | ||
590 | 73 | 'CephBrokerRq', | ||
591 | 71 | ] | 74 | ] |
592 | 72 | 75 | ||
593 | 73 | 76 | ||
594 | @@ -398,24 +401,24 @@ | |||
595 | 398 | 'Could not create ceph keyring: peer not ready?' | 401 | 'Could not create ceph keyring: peer not ready?' |
596 | 399 | ) | 402 | ) |
597 | 400 | 403 | ||
598 | 404 | @patch("glance_relations.get_ceph_request") | ||
599 | 401 | @patch("glance_relations.relation_set") | 405 | @patch("glance_relations.relation_set") |
600 | 402 | @patch("glance_relations.relation_get") | 406 | @patch("glance_relations.relation_get") |
601 | 403 | @patch.object(relations, 'CONFIGS') | 407 | @patch.object(relations, 'CONFIGS') |
602 | 404 | def test_ceph_changed_broker_send_rq(self, configs, mock_relation_get, | 408 | def test_ceph_changed_broker_send_rq(self, configs, mock_relation_get, |
604 | 405 | mock_relation_set): | 409 | mock_relation_set, |
605 | 410 | mock_get_ceph_request): | ||
606 | 411 | mock_get_ceph_request.return_value = "CephRequest" | ||
607 | 406 | configs.complete_contexts.return_value = ['ceph'] | 412 | configs.complete_contexts.return_value = ['ceph'] |
608 | 407 | self.service_name.return_value = 'glance' | 413 | self.service_name.return_value = 'glance' |
609 | 408 | self.ensure_ceph_keyring.return_value = True | 414 | self.ensure_ceph_keyring.return_value = True |
610 | 409 | self.relation_ids.return_value = ['ceph:0'] | 415 | self.relation_ids.return_value = ['ceph:0'] |
611 | 416 | self.is_request_complete.return_value = False | ||
612 | 410 | relations.hooks.execute(['hooks/ceph-relation-changed']) | 417 | relations.hooks.execute(['hooks/ceph-relation-changed']) |
613 | 411 | self.ensure_ceph_keyring.assert_called_with(service='glance', | 418 | self.ensure_ceph_keyring.assert_called_with(service='glance', |
614 | 412 | user='glance', | 419 | user='glance', |
615 | 413 | group='glance') | 420 | group='glance') |
621 | 414 | req = {'api-version': 1, | 421 | self.send_request_if_needed.assert_called_with("CephRequest") |
617 | 415 | 'ops': [{"op": "create-pool", "name": "glance", "replicas": 3}]} | ||
618 | 416 | broker_dict = json.dumps(req) | ||
619 | 417 | mock_relation_set.assert_called_with(broker_req=broker_dict, | ||
620 | 418 | relation_id='ceph:0') | ||
622 | 419 | for c in [call('/etc/glance/glance.conf')]: | 422 | for c in [call('/etc/glance/glance.conf')]: |
623 | 420 | self.assertNotIn(c, configs.write.call_args_list) | 423 | self.assertNotIn(c, configs.write.call_args_list) |
624 | 421 | 424 |
charm_lint_check #10410 glance for gnuoy mp271262
LINT OK: passed
Build: http:// 10.245. 162.77: 8080/job/ charm_lint_ check/10410/