Merge lp:~gnuoy/charms/trusty/nova-compute/1453940-stable into lp:~openstack-charmers-archive/charms/trusty/nova-compute/trunk

Proposed by Liam Young on 2015-09-16
Status: Merged
Merged at revision: 137
Proposed branch: lp:~gnuoy/charms/trusty/nova-compute/1453940-stable
Merge into: lp:~openstack-charmers-archive/charms/trusty/nova-compute/trunk
Diff against target: 634 lines (+295/-73)
12 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/contrib/storage/linux/utils.py (+3/-2)
hooks/charmhelpers/core/hookenv.py (+1/-20)
hooks/charmhelpers/core/host.py (+2/-2)
hooks/nova_compute_hooks.py (+14/-23)
metadata.yaml (+1/-1)
unit_tests/test_nova_compute_hooks.py (+7/-0)
To merge this branch: bzr merge lp:~gnuoy/charms/trusty/nova-compute/1453940-stable
Reviewer Review Type Date Requested Status
Chris Glass (community) 2015-09-16 Approve on 2015-09-23
Review via email: mp+271257@code.launchpad.net
To post a comment you must log in.

charm_lint_check #10407 nova-compute for gnuoy mp271257
    LINT FAIL: lint-test failed
    LINT FAIL: charm-proof failed

LINT Results (max last 2 lines):
make: *** [lint] Error 100
ERROR:root:Make target returned non-zero.

Full lint test output: http://paste.ubuntu.com/12514277/
Build: http://10.245.162.77:8080/job/charm_lint_check/10407/

charm_unit_test #9557 nova-compute for gnuoy mp271257
    UNIT OK: passed

Build: http://10.245.162.77:8080/job/charm_unit_test/9557/

charm_amulet_test #6549 nova-compute for gnuoy mp271257
    AMULET FAIL: amulet-test failed

AMULET Results (max last 2 lines):
make: *** [test] Error 1
ERROR:root:Make target returned non-zero.

Full amulet test output: http://paste.ubuntu.com/12514377/
Build: http://10.245.162.77:8080/job/charm_amulet_test/6549/

140. By Liam Young on 2015-09-22

Fix charm proof by renaming the 'categories' field to 'tags'

charm_lint_check #10457 nova-compute for gnuoy mp271257
    LINT OK: passed

Build: http://10.245.162.77:8080/job/charm_lint_check/10457/

charm_unit_test #9651 nova-compute for gnuoy mp271257
    UNIT OK: passed

Build: http://10.245.162.77:8080/job/charm_unit_test/9651/

charm_amulet_test #6604 nova-compute for gnuoy mp271257
    AMULET OK: passed

Build: http://10.245.162.77:8080/job/charm_amulet_test/6604/

Chris Glass (tribaal) wrote :

Looks good! Similar to your other branches, no surprises there.

+1

review: Approve

Preview Diff

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

Subscribers

People subscribed via source and target branches