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

Proposed by Liam Young
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
Reviewer Review Type Date Requested Status
Chris Glass (community) Approve
Review via email: mp+271262@code.launchpad.net
To post a comment you must log in.
Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_lint_check #10410 glance for gnuoy mp271262
    LINT OK: passed

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

Revision history for this message
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://paste.ubuntu.com/12514441/
Build: http://10.245.162.77:8080/job/charm_amulet_test/6555/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_unit_test #9626 glance for gnuoy mp271262
    UNIT OK: passed

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

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_lint_check #10437 glance for gnuoy mp271262
    LINT OK: passed

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

125. By Liam Young

Empty commit to trigger osci

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_lint_check #10458 glance for gnuoy mp271262
    LINT OK: passed

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

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_unit_test #9648 glance for gnuoy mp271262
    UNIT OK: passed

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

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_amulet_test #6582 glance for gnuoy mp271262
    AMULET OK: passed

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

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

Looks good! +1

review: Approve
Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_amulet_test #6602 glance for gnuoy mp271262
    AMULET OK: passed

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'hooks/charmhelpers/cli/__init__.py'
--- hooks/charmhelpers/cli/__init__.py 2015-08-10 16:34:51 +0000
+++ hooks/charmhelpers/cli/__init__.py 2015-09-22 15:21:44 +0000
@@ -152,15 +152,11 @@
152 arguments = self.argument_parser.parse_args()152 arguments = self.argument_parser.parse_args()
153 argspec = inspect.getargspec(arguments.func)153 argspec = inspect.getargspec(arguments.func)
154 vargs = []154 vargs = []
155 kwargs = {}
156 for arg in argspec.args:155 for arg in argspec.args:
157 vargs.append(getattr(arguments, arg))156 vargs.append(getattr(arguments, arg))
158 if argspec.varargs:157 if argspec.varargs:
159 vargs.extend(getattr(arguments, argspec.varargs))158 vargs.extend(getattr(arguments, argspec.varargs))
160 if argspec.keywords:159 output = arguments.func(*vargs)
161 for kwarg in argspec.keywords.items():
162 kwargs[kwarg] = getattr(arguments, kwarg)
163 output = arguments.func(*vargs, **kwargs)
164 if getattr(arguments.func, '_cli_test_command', False):160 if getattr(arguments.func, '_cli_test_command', False):
165 self.exit_code = 0 if output else 1161 self.exit_code = 0 if output else 1
166 output = ''162 output = ''
167163
=== modified file 'hooks/charmhelpers/cli/commands.py'
--- hooks/charmhelpers/cli/commands.py 2015-08-10 16:34:51 +0000
+++ hooks/charmhelpers/cli/commands.py 2015-09-22 15:21:44 +0000
@@ -26,7 +26,7 @@
26"""26"""
27Import the sub-modules which have decorated subcommands to register with chlp.27Import the sub-modules which have decorated subcommands to register with chlp.
28"""28"""
29import host # noqa29from . import host # noqa
30import benchmark # noqa30from . import benchmark # noqa
31import unitdata # noqa31from . import unitdata # noqa
32from charmhelpers.core import hookenv # noqa32from . import hookenv # noqa
3333
=== added file 'hooks/charmhelpers/cli/hookenv.py'
--- hooks/charmhelpers/cli/hookenv.py 1970-01-01 00:00:00 +0000
+++ hooks/charmhelpers/cli/hookenv.py 2015-09-22 15:21:44 +0000
@@ -0,0 +1,23 @@
1# Copyright 2014-2015 Canonical Limited.
2#
3# This file is part of charm-helpers.
4#
5# charm-helpers is free software: you can redistribute it and/or modify
6# it under the terms of the GNU Lesser General Public License version 3 as
7# published by the Free Software Foundation.
8#
9# charm-helpers is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU Lesser General Public License for more details.
13#
14# You should have received a copy of the GNU Lesser General Public License
15# along with charm-helpers. If not, see <http://www.gnu.org/licenses/>.
16
17from . import cmdline
18from charmhelpers.core import hookenv
19
20
21cmdline.subcommand('relation-id')(hookenv.relation_id._wrapped)
22cmdline.subcommand('service-name')(hookenv.service_name)
23cmdline.subcommand('remote-service-name')(hookenv.remote_service_name._wrapped)
024
=== modified file 'hooks/charmhelpers/contrib/openstack/context.py'
--- hooks/charmhelpers/contrib/openstack/context.py 2015-08-10 16:34:51 +0000
+++ hooks/charmhelpers/contrib/openstack/context.py 2015-09-22 15:21:44 +0000
@@ -483,13 +483,15 @@
483483
484 log('Generating template context for ceph', level=DEBUG)484 log('Generating template context for ceph', level=DEBUG)
485 mon_hosts = []485 mon_hosts = []
486 auth = None486 ctxt = {
487 key = None487 'use_syslog': str(config('use-syslog')).lower()
488 use_syslog = str(config('use-syslog')).lower()488 }
489 for rid in relation_ids('ceph'):489 for rid in relation_ids('ceph'):
490 for unit in related_units(rid):490 for unit in related_units(rid):
491 auth = relation_get('auth', rid=rid, unit=unit)491 if not ctxt.get('auth'):
492 key = relation_get('key', rid=rid, unit=unit)492 ctxt['auth'] = relation_get('auth', rid=rid, unit=unit)
493 if not ctxt.get('key'):
494 ctxt['key'] = relation_get('key', rid=rid, unit=unit)
493 ceph_pub_addr = relation_get('ceph-public-address', rid=rid,495 ceph_pub_addr = relation_get('ceph-public-address', rid=rid,
494 unit=unit)496 unit=unit)
495 unit_priv_addr = relation_get('private-address', rid=rid,497 unit_priv_addr = relation_get('private-address', rid=rid,
@@ -498,10 +500,7 @@
498 ceph_addr = format_ipv6_addr(ceph_addr) or ceph_addr500 ceph_addr = format_ipv6_addr(ceph_addr) or ceph_addr
499 mon_hosts.append(ceph_addr)501 mon_hosts.append(ceph_addr)
500502
501 ctxt = {'mon_hosts': ' '.join(sorted(mon_hosts)),503 ctxt['mon_hosts'] = ' '.join(sorted(mon_hosts))
502 'auth': auth,
503 'key': key,
504 'use_syslog': use_syslog}
505504
506 if not os.path.isdir('/etc/ceph'):505 if not os.path.isdir('/etc/ceph'):
507 os.mkdir('/etc/ceph')506 os.mkdir('/etc/ceph')
508507
=== modified file 'hooks/charmhelpers/contrib/openstack/utils.py'
--- hooks/charmhelpers/contrib/openstack/utils.py 2015-08-10 16:34:51 +0000
+++ hooks/charmhelpers/contrib/openstack/utils.py 2015-09-22 15:21:44 +0000
@@ -1,5 +1,3 @@
1#!/usr/bin/python
2
3# Copyright 2014-2015 Canonical Limited.1# Copyright 2014-2015 Canonical Limited.
4#2#
5# This file is part of charm-helpers.3# This file is part of charm-helpers.
@@ -167,9 +165,9 @@
167 error_out(e)165 error_out(e)
168166
169167
170def get_os_version_codename(codename):168def get_os_version_codename(codename, version_map=OPENSTACK_CODENAMES):
171 '''Determine OpenStack version number from codename.'''169 '''Determine OpenStack version number from codename.'''
172 for k, v in six.iteritems(OPENSTACK_CODENAMES):170 for k, v in six.iteritems(version_map):
173 if v == codename:171 if v == codename:
174 return k172 return k
175 e = 'Could not derive OpenStack version for '\173 e = 'Could not derive OpenStack version for '\
@@ -392,7 +390,11 @@
392 import apt_pkg as apt390 import apt_pkg as apt
393 src = config('openstack-origin')391 src = config('openstack-origin')
394 cur_vers = get_os_version_package(package)392 cur_vers = get_os_version_package(package)
395 available_vers = get_os_version_install_source(src)393 if "swift" in package:
394 codename = get_os_codename_install_source(src)
395 available_vers = get_os_version_codename(codename, SWIFT_CODENAMES)
396 else:
397 available_vers = get_os_version_install_source(src)
396 apt.init()398 apt.init()
397 return apt.version_compare(available_vers, cur_vers) == 1399 return apt.version_compare(available_vers, cur_vers) == 1
398400
399401
=== modified file 'hooks/charmhelpers/contrib/storage/linux/ceph.py'
--- hooks/charmhelpers/contrib/storage/linux/ceph.py 2015-08-10 16:34:51 +0000
+++ hooks/charmhelpers/contrib/storage/linux/ceph.py 2015-09-22 15:21:44 +0000
@@ -28,6 +28,7 @@
28import shutil28import shutil
29import json29import json
30import time30import time
31import uuid
3132
32from subprocess import (33from subprocess import (
33 check_call,34 check_call,
@@ -35,8 +36,10 @@
35 CalledProcessError,36 CalledProcessError,
36)37)
37from charmhelpers.core.hookenv import (38from charmhelpers.core.hookenv import (
39 local_unit,
38 relation_get,40 relation_get,
39 relation_ids,41 relation_ids,
42 relation_set,
40 related_units,43 related_units,
41 log,44 log,
42 DEBUG,45 DEBUG,
@@ -411,17 +414,52 @@
411414
412 The API is versioned and defaults to version 1.415 The API is versioned and defaults to version 1.
413 """416 """
414 def __init__(self, api_version=1):417 def __init__(self, api_version=1, request_id=None):
415 self.api_version = api_version418 self.api_version = api_version
419 if request_id:
420 self.request_id = request_id
421 else:
422 self.request_id = str(uuid.uuid1())
416 self.ops = []423 self.ops = []
417424
418 def add_op_create_pool(self, name, replica_count=3):425 def add_op_create_pool(self, name, replica_count=3):
419 self.ops.append({'op': 'create-pool', 'name': name,426 self.ops.append({'op': 'create-pool', 'name': name,
420 'replicas': replica_count})427 'replicas': replica_count})
421428
429 def set_ops(self, ops):
430 """Set request ops to provided value.
431
432 Useful for injecting ops that come from a previous request
433 to allow comparisons to ensure validity.
434 """
435 self.ops = ops
436
422 @property437 @property
423 def request(self):438 def request(self):
424 return json.dumps({'api-version': self.api_version, 'ops': self.ops})439 return json.dumps({'api-version': self.api_version, 'ops': self.ops,
440 'request-id': self.request_id})
441
442 def _ops_equal(self, other):
443 if len(self.ops) == len(other.ops):
444 for req_no in range(0, len(self.ops)):
445 for key in ['replicas', 'name', 'op']:
446 if self.ops[req_no][key] != other.ops[req_no][key]:
447 return False
448 else:
449 return False
450 return True
451
452 def __eq__(self, other):
453 if not isinstance(other, self.__class__):
454 return False
455 if self.api_version == other.api_version and \
456 self._ops_equal(other):
457 return True
458 else:
459 return False
460
461 def __ne__(self, other):
462 return not self.__eq__(other)
425463
426464
427class CephBrokerRsp(object):465class CephBrokerRsp(object):
@@ -431,14 +469,198 @@
431469
432 The API is versioned and defaults to version 1.470 The API is versioned and defaults to version 1.
433 """471 """
472
434 def __init__(self, encoded_rsp):473 def __init__(self, encoded_rsp):
435 self.api_version = None474 self.api_version = None
436 self.rsp = json.loads(encoded_rsp)475 self.rsp = json.loads(encoded_rsp)
437476
438 @property477 @property
478 def request_id(self):
479 return self.rsp.get('request-id')
480
481 @property
439 def exit_code(self):482 def exit_code(self):
440 return self.rsp.get('exit-code')483 return self.rsp.get('exit-code')
441484
442 @property485 @property
443 def exit_msg(self):486 def exit_msg(self):
444 return self.rsp.get('stderr')487 return self.rsp.get('stderr')
488
489
490# Ceph Broker Conversation:
491# If a charm needs an action to be taken by ceph it can create a CephBrokerRq
492# and send that request to ceph via the ceph relation. The CephBrokerRq has a
493# unique id so that the client can identity which CephBrokerRsp is associated
494# with the request. Ceph will also respond to each client unit individually
495# creating a response key per client unit eg glance/0 will get a CephBrokerRsp
496# via key broker-rsp-glance-0
497#
498# To use this the charm can just do something like:
499#
500# from charmhelpers.contrib.storage.linux.ceph import (
501# send_request_if_needed,
502# is_request_complete,
503# CephBrokerRq,
504# )
505#
506# @hooks.hook('ceph-relation-changed')
507# def ceph_changed():
508# rq = CephBrokerRq()
509# rq.add_op_create_pool(name='poolname', replica_count=3)
510#
511# if is_request_complete(rq):
512# <Request complete actions>
513# else:
514# send_request_if_needed(get_ceph_request())
515#
516# CephBrokerRq and CephBrokerRsp are serialized into JSON. Below is an example
517# of glance having sent a request to ceph which ceph has successfully processed
518# 'ceph:8': {
519# 'ceph/0': {
520# 'auth': 'cephx',
521# 'broker-rsp-glance-0': '{"request-id": "0bc7dc54", "exit-code": 0}',
522# 'broker_rsp': '{"request-id": "0da543b8", "exit-code": 0}',
523# 'ceph-public-address': '10.5.44.103',
524# 'key': 'AQCLDttVuHXINhAAvI144CB09dYchhHyTUY9BQ==',
525# 'private-address': '10.5.44.103',
526# },
527# 'glance/0': {
528# 'broker_req': ('{"api-version": 1, "request-id": "0bc7dc54", '
529# '"ops": [{"replicas": 3, "name": "glance", '
530# '"op": "create-pool"}]}'),
531# 'private-address': '10.5.44.109',
532# },
533# }
534
535def get_previous_request(rid):
536 """Return the last ceph broker request sent on a given relation
537
538 @param rid: Relation id to query for request
539 """
540 request = None
541 broker_req = relation_get(attribute='broker_req', rid=rid,
542 unit=local_unit())
543 if broker_req:
544 request_data = json.loads(broker_req)
545 request = CephBrokerRq(api_version=request_data['api-version'],
546 request_id=request_data['request-id'])
547 request.set_ops(request_data['ops'])
548
549 return request
550
551
552def get_request_states(request):
553 """Return a dict of requests per relation id with their corresponding
554 completion state.
555
556 This allows a charm, which has a request for ceph, to see whether there is
557 an equivalent request already being processed and if so what state that
558 request is in.
559
560 @param request: A CephBrokerRq object
561 """
562 complete = []
563 requests = {}
564 for rid in relation_ids('ceph'):
565 complete = False
566 previous_request = get_previous_request(rid)
567 if request == previous_request:
568 sent = True
569 complete = is_request_complete_for_rid(previous_request, rid)
570 else:
571 sent = False
572 complete = False
573
574 requests[rid] = {
575 'sent': sent,
576 'complete': complete,
577 }
578
579 return requests
580
581
582def is_request_sent(request):
583 """Check to see if a functionally equivalent request has already been sent
584
585 Returns True if a similair request has been sent
586
587 @param request: A CephBrokerRq object
588 """
589 states = get_request_states(request)
590 for rid in states.keys():
591 if not states[rid]['sent']:
592 return False
593
594 return True
595
596
597def is_request_complete(request):
598 """Check to see if a functionally equivalent request has already been
599 completed
600
601 Returns True if a similair request has been completed
602
603 @param request: A CephBrokerRq object
604 """
605 states = get_request_states(request)
606 for rid in states.keys():
607 if not states[rid]['complete']:
608 return False
609
610 return True
611
612
613def is_request_complete_for_rid(request, rid):
614 """Check if a given request has been completed on the given relation
615
616 @param request: A CephBrokerRq object
617 @param rid: Relation ID
618 """
619 broker_key = get_broker_rsp_key()
620 for unit in related_units(rid):
621 rdata = relation_get(rid=rid, unit=unit)
622 if rdata.get(broker_key):
623 rsp = CephBrokerRsp(rdata.get(broker_key))
624 if rsp.request_id == request.request_id:
625 if not rsp.exit_code:
626 return True
627 else:
628 # The remote unit sent no reply targeted at this unit so either the
629 # remote ceph cluster does not support unit targeted replies or it
630 # has not processed our request yet.
631 if rdata.get('broker_rsp'):
632 request_data = json.loads(rdata['broker_rsp'])
633 if request_data.get('request-id'):
634 log('Ignoring legacy broker_rsp without unit key as remote '
635 'service supports unit specific replies', level=DEBUG)
636 else:
637 log('Using legacy broker_rsp as remote service does not '
638 'supports unit specific replies', level=DEBUG)
639 rsp = CephBrokerRsp(rdata['broker_rsp'])
640 if not rsp.exit_code:
641 return True
642
643 return False
644
645
646def get_broker_rsp_key():
647 """Return broker response key for this unit
648
649 This is the key that ceph is going to use to pass request status
650 information back to this unit
651 """
652 return 'broker-rsp-' + local_unit().replace('/', '-')
653
654
655def send_request_if_needed(request):
656 """Send broker request if an equivalent request has not already been sent
657
658 @param request: A CephBrokerRq object
659 """
660 if is_request_sent(request):
661 log('Request already sent but not complete, not sending new request',
662 level=DEBUG)
663 else:
664 for rid in relation_ids('ceph'):
665 log('Sending request {}'.format(request.request_id), level=DEBUG)
666 relation_set(relation_id=rid, broker_req=request.request)
445667
=== modified file 'hooks/charmhelpers/core/hookenv.py'
--- hooks/charmhelpers/core/hookenv.py 2015-08-10 16:34:51 +0000
+++ hooks/charmhelpers/core/hookenv.py 2015-09-22 15:21:44 +0000
@@ -34,23 +34,6 @@
34import tempfile34import tempfile
35from subprocess import CalledProcessError35from subprocess import CalledProcessError
3636
37try:
38 from charmhelpers.cli import cmdline
39except ImportError as e:
40 # due to the anti-pattern of partially synching charmhelpers directly
41 # into charms, it's possible that charmhelpers.cli is not available;
42 # if that's the case, they don't really care about using the cli anyway,
43 # so mock it out
44 if str(e) == 'No module named cli':
45 class cmdline(object):
46 @classmethod
47 def subcommand(cls, *args, **kwargs):
48 def _wrap(func):
49 return func
50 return _wrap
51 else:
52 raise
53
54import six37import six
55if not six.PY3:38if not six.PY3:
56 from UserDict import UserDict39 from UserDict import UserDict
@@ -91,6 +74,7 @@
91 res = func(*args, **kwargs)74 res = func(*args, **kwargs)
92 cache[key] = res75 cache[key] = res
93 return res76 return res
77 wrapper._wrapped = func
94 return wrapper78 return wrapper
9579
9680
@@ -190,7 +174,6 @@
190 return os.environ.get('JUJU_RELATION', None)174 return os.environ.get('JUJU_RELATION', None)
191175
192176
193@cmdline.subcommand()
194@cached177@cached
195def relation_id(relation_name=None, service_or_unit=None):178def relation_id(relation_name=None, service_or_unit=None):
196 """The relation ID for the current or a specified relation"""179 """The relation ID for the current or a specified relation"""
@@ -216,13 +199,11 @@
216 return os.environ.get('JUJU_REMOTE_UNIT', None)199 return os.environ.get('JUJU_REMOTE_UNIT', None)
217200
218201
219@cmdline.subcommand()
220def service_name():202def service_name():
221 """The name service group this unit belongs to"""203 """The name service group this unit belongs to"""
222 return local_unit().split('/')[0]204 return local_unit().split('/')[0]
223205
224206
225@cmdline.subcommand()
226@cached207@cached
227def remote_service_name(relid=None):208def remote_service_name(relid=None):
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)"""
229210
=== modified file 'hooks/charmhelpers/core/host.py'
--- hooks/charmhelpers/core/host.py 2015-08-10 16:34:51 +0000
+++ hooks/charmhelpers/core/host.py 2015-09-22 15:21:44 +0000
@@ -72,7 +72,7 @@
72 stopped = service_stop(service_name)72 stopped = service_stop(service_name)
73 # XXX: Support systemd too73 # XXX: Support systemd too
74 override_path = os.path.join(74 override_path = os.path.join(
75 init_dir, '{}.conf.override'.format(service_name))75 init_dir, '{}.override'.format(service_name))
76 with open(override_path, 'w') as fh:76 with open(override_path, 'w') as fh:
77 fh.write("manual\n")77 fh.write("manual\n")
78 return stopped78 return stopped
@@ -86,7 +86,7 @@
86 if init_dir is None:86 if init_dir is None:
87 init_dir = "/etc/init"87 init_dir = "/etc/init"
88 override_path = os.path.join(88 override_path = os.path.join(
89 init_dir, '{}.conf.override'.format(service_name))89 init_dir, '{}.override'.format(service_name))
90 if os.path.exists(override_path):90 if os.path.exists(override_path):
91 os.unlink(override_path)91 os.unlink(override_path)
92 started = service_start(service_name)92 started = service_start(service_name)
9393
=== modified file 'hooks/glance_relations.py'
--- hooks/glance_relations.py 2015-08-10 16:34:51 +0000
+++ hooks/glance_relations.py 2015-09-22 15:21:44 +0000
@@ -29,7 +29,6 @@
29 config,29 config,
30 Hooks,30 Hooks,
31 log as juju_log,31 log as juju_log,
32 INFO,
33 ERROR,32 ERROR,
34 open_port,33 open_port,
35 is_relation_made,34 is_relation_made,
@@ -66,9 +65,10 @@
66 sync_db_with_multi_ipv6_addresses,65 sync_db_with_multi_ipv6_addresses,
67)66)
68from charmhelpers.contrib.storage.linux.ceph import (67from charmhelpers.contrib.storage.linux.ceph import (
68 send_request_if_needed,
69 is_request_complete,
69 ensure_ceph_keyring,70 ensure_ceph_keyring,
70 CephBrokerRq,71 CephBrokerRq,
71 CephBrokerRsp,
72 delete_keyring,72 delete_keyring,
73)73)
74from charmhelpers.payload.execd import (74from charmhelpers.payload.execd import (
@@ -240,6 +240,14 @@
240 apt_install(['ceph-common', 'python-ceph'])240 apt_install(['ceph-common', 'python-ceph'])
241241
242242
243def get_ceph_request():
244 service = service_name()
245 rq = CephBrokerRq()
246 replicas = config('ceph-osd-replication-count')
247 rq.add_op_create_pool(name=service, replica_count=replicas)
248 return rq
249
250
243@hooks.hook('ceph-relation-changed')251@hooks.hook('ceph-relation-changed')
244@restart_on_change(restart_map())252@restart_on_change(restart_map())
245def ceph_changed():253def ceph_changed():
@@ -253,29 +261,15 @@
253 juju_log('Could not create ceph keyring: peer not ready?')261 juju_log('Could not create ceph keyring: peer not ready?')
254 return262 return
255263
256 settings = relation_get()264 if is_request_complete(get_ceph_request()):
257 if settings and 'broker_rsp' in settings:265 juju_log('Request complete')
258 rsp = CephBrokerRsp(settings['broker_rsp'])
259 # Non-zero return code implies failure
260 if rsp.exit_code:
261 juju_log("Ceph broker request failed (rc=%s, msg=%s)" %
262 (rsp.exit_code, rsp.exit_msg), level=ERROR)
263 return
264
265 juju_log("Ceph broker request succeeded (rc=%s, msg=%s)" %
266 (rsp.exit_code, rsp.exit_msg), level=INFO)
267 CONFIGS.write(GLANCE_API_CONF)266 CONFIGS.write(GLANCE_API_CONF)
268 CONFIGS.write(ceph_config_file())267 CONFIGS.write(ceph_config_file())
269 # Ensure that glance-api is restarted since only now can we268 # Ensure that glance-api is restarted since only now can we
270 # guarantee that ceph resources are ready.269 # guarantee that ceph resources are ready.
271 service_restart('glance-api')270 service_restart('glance-api')
272 else:271 else:
273 rq = CephBrokerRq()272 send_request_if_needed(get_ceph_request())
274 replicas = config('ceph-osd-replication-count')
275 rq.add_op_create_pool(name=service, replica_count=replicas)
276 for rid in relation_ids('ceph'):
277 relation_set(relation_id=rid, broker_req=rq.request)
278 juju_log("Request(s) sent to Ceph broker (rid=%s)" % (rid))
279273
280274
281@hooks.hook('ceph-relation-broken')275@hooks.hook('ceph-relation-broken')
282276
=== modified file 'templates/ceph.conf'
--- templates/ceph.conf 2014-03-25 18:44:22 +0000
+++ templates/ceph.conf 2015-09-22 15:21:44 +0000
@@ -10,7 +10,8 @@
10 keyring = /etc/ceph/ceph.$name.keyring10 keyring = /etc/ceph/ceph.$name.keyring
11 mon host = {{ mon_hosts }}11 mon host = {{ mon_hosts }}
12{% endif -%}12{% endif -%}
13{% if use_syslog -%}
13 log to syslog = {{ use_syslog }}14 log to syslog = {{ use_syslog }}
14 err to syslog = {{ use_syslog }}15 err to syslog = {{ use_syslog }}
15 clog to syslog = {{ use_syslog }}16 clog to syslog = {{ use_syslog }}
1617{% endif -%}
1718
=== modified file 'unit_tests/test_glance_relations.py'
--- unit_tests/test_glance_relations.py 2015-08-10 16:34:51 +0000
+++ unit_tests/test_glance_relations.py 2015-09-22 15:21:44 +0000
@@ -68,6 +68,9 @@
68 'get_ipv6_addr',68 'get_ipv6_addr',
69 'sync_db_with_multi_ipv6_addresses',69 'sync_db_with_multi_ipv6_addresses',
70 'delete_keyring',70 'delete_keyring',
71 'is_request_complete',
72 'send_request_if_needed',
73 'CephBrokerRq',
71]74]
7275
7376
@@ -398,24 +401,24 @@
398 'Could not create ceph keyring: peer not ready?'401 'Could not create ceph keyring: peer not ready?'
399 )402 )
400403
404 @patch("glance_relations.get_ceph_request")
401 @patch("glance_relations.relation_set")405 @patch("glance_relations.relation_set")
402 @patch("glance_relations.relation_get")406 @patch("glance_relations.relation_get")
403 @patch.object(relations, 'CONFIGS')407 @patch.object(relations, 'CONFIGS')
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,
405 mock_relation_set):409 mock_relation_set,
410 mock_get_ceph_request):
411 mock_get_ceph_request.return_value = "CephRequest"
406 configs.complete_contexts.return_value = ['ceph']412 configs.complete_contexts.return_value = ['ceph']
407 self.service_name.return_value = 'glance'413 self.service_name.return_value = 'glance'
408 self.ensure_ceph_keyring.return_value = True414 self.ensure_ceph_keyring.return_value = True
409 self.relation_ids.return_value = ['ceph:0']415 self.relation_ids.return_value = ['ceph:0']
416 self.is_request_complete.return_value = False
410 relations.hooks.execute(['hooks/ceph-relation-changed'])417 relations.hooks.execute(['hooks/ceph-relation-changed'])
411 self.ensure_ceph_keyring.assert_called_with(service='glance',418 self.ensure_ceph_keyring.assert_called_with(service='glance',
412 user='glance',419 user='glance',
413 group='glance')420 group='glance')
414 req = {'api-version': 1,421 self.send_request_if_needed.assert_called_with("CephRequest")
415 'ops': [{"op": "create-pool", "name": "glance", "replicas": 3}]}
416 broker_dict = json.dumps(req)
417 mock_relation_set.assert_called_with(broker_req=broker_dict,
418 relation_id='ceph:0')
419 for c in [call('/etc/glance/glance.conf')]:422 for c in [call('/etc/glance/glance.conf')]:
420 self.assertNotIn(c, configs.write.call_args_list)423 self.assertNotIn(c, configs.write.call_args_list)
421424

Subscribers

People subscribed via source and target branches