Merge lp:~gnuoy/charm-helpers/stable-1453940 into lp:~openstack-charmers/charm-helpers/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
Reviewer Review Type Date Requested Status
Chris Glass (community) Approve
Review via email: mp+271258@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Chris Glass (tribaal) wrote :

Looks good. Same diff as for trunk. +1

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'charmhelpers/contrib/openstack/context.py'
--- charmhelpers/contrib/openstack/context.py 2015-08-10 16:39:41 +0000
+++ charmhelpers/contrib/openstack/context.py 2015-09-16 09:01:05 +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 'charmhelpers/contrib/storage/linux/ceph.py'
--- charmhelpers/contrib/storage/linux/ceph.py 2015-08-10 16:39:41 +0000
+++ charmhelpers/contrib/storage/linux/ceph.py 2015-09-16 09:01:05 +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 'tests/contrib/openstack/test_os_contexts.py'
--- tests/contrib/openstack/test_os_contexts.py 2015-08-10 16:39:41 +0000
+++ tests/contrib/openstack/test_os_contexts.py 2015-09-16 09:01:05 +0000
@@ -74,7 +74,7 @@
7474
75 def relation_ids(self, relation):75 def relation_ids(self, relation):
76 rids = []76 rids = []
77 for rid in self.relation_data.keys():77 for rid in sorted(self.relation_data.keys()):
78 if relation + ':' in rid:78 if relation + ':' in rid:
79 rids.append(rid)79 rids.append(rid)
80 return rids80 return rids
@@ -82,7 +82,7 @@
82 def relation_units(self, relation_id):82 def relation_units(self, relation_id):
83 if relation_id not in self.relation_data:83 if relation_id not in self.relation_data:
84 return None84 return None
85 return self.relation_data[relation_id].keys()85 return sorted(self.relation_data[relation_id].keys())
8686
87SHARED_DB_RELATION = {87SHARED_DB_RELATION = {
88 'db_host': 'dbserver.local',88 'db_host': 'dbserver.local',
@@ -1029,7 +1029,7 @@
1029 def test_ceph_context_with_data(self, ensure_packages, mkdir, isdir,1029 def test_ceph_context_with_data(self, ensure_packages, mkdir, isdir,
1030 config):1030 config):
1031 '''Test ceph context with all relation data'''1031 '''Test ceph context with all relation data'''
1032 config.return_value = True1032 config.side_effect = fake_config({'use-syslog': 'True'})
1033 isdir.return_value = False1033 isdir.return_value = False
1034 relation = FakeRelation(relation_data=CEPH_RELATION)1034 relation = FakeRelation(relation_data=CEPH_RELATION)
1035 self.relation_get.side_effect = relation.get1035 self.relation_get.side_effect = relation.get
@@ -1051,7 +1051,7 @@
1051 @patch.object(context, 'ensure_packages')1051 @patch.object(context, 'ensure_packages')
1052 def test_ceph_context_with_missing_data(self, ensure_packages, mkdir):1052 def test_ceph_context_with_missing_data(self, ensure_packages, mkdir):
1053 '''Test ceph context with missing relation data'''1053 '''Test ceph context with missing relation data'''
1054 relation = copy(CEPH_RELATION)1054 relation = deepcopy(CEPH_RELATION)
1055 for k, v in six.iteritems(relation):1055 for k, v in six.iteritems(relation):
1056 for u in six.iterkeys(v):1056 for u in six.iterkeys(v):
1057 del relation[k][u]['auth']1057 del relation[k][u]['auth']
@@ -1068,6 +1068,38 @@
1068 @patch('os.path.isdir')1068 @patch('os.path.isdir')
1069 @patch('os.mkdir')1069 @patch('os.mkdir')
1070 @patch.object(context, 'ensure_packages')1070 @patch.object(context, 'ensure_packages')
1071 def test_ceph_context_partial_missing_data(self, ensure_packages, mkdir,
1072 isdir, config):
1073 '''Test ceph context last unit missing data
1074
1075 Tests a fix to a previously bug which meant only the config from
1076 last unit was returned so if a valid value was supplied from an
1077 earlier unit it would be ignored'''
1078 config.side_effect = fake_config({'use-syslog': 'True'})
1079 relation = deepcopy(CEPH_RELATION)
1080 for k, v in six.iteritems(relation):
1081 last_unit = sorted(six.iterkeys(v))[-1]
1082 unit_data = relation[k][last_unit]
1083 del unit_data['auth']
1084 relation[k][last_unit] = unit_data
1085 relation = FakeRelation(relation_data=relation)
1086 self.relation_get.side_effect = relation.get
1087 self.relation_ids.side_effect = relation.relation_ids
1088 self.related_units.side_effect = relation.relation_units
1089 ceph = context.CephContext()
1090 result = ceph()
1091 expected = {
1092 'mon_hosts': 'ceph_node1 ceph_node2',
1093 'auth': 'foo',
1094 'key': 'bar',
1095 'use_syslog': 'true'
1096 }
1097 self.assertEquals(result, expected)
1098
1099 @patch.object(context, 'config')
1100 @patch('os.path.isdir')
1101 @patch('os.mkdir')
1102 @patch.object(context, 'ensure_packages')
1071 def test_ceph_context_with_public_addr(1103 def test_ceph_context_with_public_addr(
1072 self, ensure_packages, mkdir, isdir, config):1104 self, ensure_packages, mkdir, isdir, config):
1073 '''Test ceph context in host with multiple networks with all1105 '''Test ceph context in host with multiple networks with all
10741106
=== modified file 'tests/contrib/storage/test_linux_ceph.py'
--- tests/contrib/storage/test_linux_ceph.py 2015-08-10 16:39:41 +0000
+++ tests/contrib/storage/test_linux_ceph.py 2015-09-16 09:01:05 +0000
@@ -5,10 +5,11 @@
5from threading import Timer5from threading import Timer
6from testtools import TestCase6from testtools import TestCase
7import json7import json
8import copy
89
9import charmhelpers.contrib.storage.linux.ceph as ceph_utils10import charmhelpers.contrib.storage.linux.ceph as ceph_utils
10from subprocess import CalledProcessError11from subprocess import CalledProcessError
11from tests.helpers import patch_open12from tests.helpers import patch_open, FakeRelation
12import nose.plugins.attrib13import nose.plugins.attrib
13import os14import os
14import time15import time
@@ -31,6 +32,46 @@
31baz32baz
32"""33"""
3334
35CEPH_CLIENT_RELATION = {
36 'ceph:8': {
37 'ceph/0': {
38 'auth': 'cephx',
39 'broker-rsp-glance-0': '{"request-id": "0bc7dc54", "exit-code": 0}',
40 'broker-rsp-glance-1': '{"request-id": "0880e22a", "exit-code": 0}',
41 'broker-rsp-glance-2': '{"request-id": "0da543b8", "exit-code": 0}',
42 'broker_rsp': '{"request-id": "0da543b8", "exit-code": 0}',
43 'ceph-public-address': '10.5.44.103',
44 'key': 'AQCLDttVuHXINhAAvI144CB09dYchhHyTUY9BQ==',
45 'private-address': '10.5.44.103',
46 },
47 'ceph/1': {
48 'auth': 'cephx',
49 'ceph-public-address': '10.5.44.104',
50 'key': 'AQCLDttVuHXINhAAvI144CB09dYchhHyTUY9BQ==',
51 'private-address': '10.5.44.104',
52 },
53 'ceph/2': {
54 'auth': 'cephx',
55 'ceph-public-address': '10.5.44.105',
56 'key': 'AQCLDttVuHXINhAAvI144CB09dYchhHyTUY9BQ==',
57 'private-address': '10.5.44.105',
58 },
59 'glance/0': {
60 'broker_req': '{"api-version": 1, "request-id": "0bc7dc54", "ops": [{"replicas": 3, "name": "glance", "op": "create-pool"}]}',
61 'private-address': '10.5.44.109',
62 },
63 }
64}
65
66CEPH_CLIENT_RELATION_LEGACY = copy.deepcopy(CEPH_CLIENT_RELATION)
67CEPH_CLIENT_RELATION_LEGACY['ceph:8']['ceph/0'] = {
68 'auth': 'cephx',
69 'broker_rsp': '{"exit-code": 0}',
70 'ceph-public-address': '10.5.44.103',
71 'key': 'AQCLDttVuHXINhAAvI144CB09dYchhHyTUY9BQ==',
72 'private-address': '10.5.44.103',
73}
74
3475
35class CephUtilsTests(TestCase):76class CephUtilsTests(TestCase):
36 def setUp(self):77 def setUp(self):
@@ -38,6 +79,10 @@
38 [self._patch(m) for m in [79 [self._patch(m) for m in [
39 'check_call',80 'check_call',
40 'check_output',81 'check_output',
82 'relation_get',
83 'related_units',
84 'relation_ids',
85 'relation_set',
41 'log',86 'log',
42 ]]87 ]]
4388
@@ -563,19 +608,303 @@
563 b'ceph version 0.67.4 (ad85b8bfafea6232d64cb7ba76a8b6e8252fa0c7)'608 b'ceph version 0.67.4 (ad85b8bfafea6232d64cb7ba76a8b6e8252fa0c7)'
564 self.assertEquals(ceph_utils.ceph_version(), '0.67.4')609 self.assertEquals(ceph_utils.ceph_version(), '0.67.4')
565610
566 def test_ceph_broker_rq_class(self):611 @patch.object(ceph_utils, 'uuid')
612 def test_ceph_broker_rq_class(self, uuid):
613 uuid.uuid1.return_value = 'uuid'
567 rq = ceph_utils.CephBrokerRq()614 rq = ceph_utils.CephBrokerRq()
568 rq.add_op_create_pool('pool1', replica_count=1)615 rq.add_op_create_pool('pool1', replica_count=1)
569 rq.add_op_create_pool('pool2')616 rq.add_op_create_pool('pool2')
570 expected = json.dumps({'api-version': 1,617 expected = {
571 'ops': [{'op': 'create-pool', 'name': 'pool1',618 'api-version': 1,
572 'replicas': 1},619 'request-id': 'uuid',
573 {'op': 'create-pool', 'name': 'pool2',620 'ops': [{'op': 'create-pool', 'name': 'pool1', 'replicas': 1},
574 'replicas': 3}]})621 {'op': 'create-pool', 'name': 'pool2', 'replicas': 3}]
575 self.assertEqual(rq.request, expected)622 }
623 request_dict = json.loads(rq.request)
624 for key in ['api-version', 'request-id']:
625 self.assertEqual(request_dict[key], expected[key])
626 for key in ['op', 'name', 'replicas']:
627 self.assertEqual(request_dict['ops'][0][key], expected['ops'][0][key])
628 self.assertEqual(request_dict['ops'][1][key], expected['ops'][1][key])
576629
577 def test_ceph_broker_rsp_class(self):630 def test_ceph_broker_rsp_class(self):
578 rsp = ceph_utils.CephBrokerRsp(json.dumps({'exit-code': 0,631 rsp = ceph_utils.CephBrokerRsp(json.dumps({'exit-code': 0,
579 'stderr': "Success"}))632 'stderr': "Success"}))
580 self.assertEqual(rsp.exit_code, 0)633 self.assertEqual(rsp.exit_code, 0)
581 self.assertEqual(rsp.exit_msg, "Success")634 self.assertEqual(rsp.exit_msg, "Success")
635 self.assertEqual(rsp.request_id, None)
636
637 def test_ceph_broker_rsp_class_rqid(self):
638 rsp = ceph_utils.CephBrokerRsp(json.dumps({'exit-code': 0,
639 'stderr': "Success",
640 'request-id': 'reqid1'}))
641 self.assertEqual(rsp.exit_code, 0)
642 self.assertEqual(rsp.exit_msg, 'Success')
643 self.assertEqual(rsp.request_id, 'reqid1')
644
645 def setup_client_relation(self, relation):
646 relation = FakeRelation(relation)
647 self.relation_get.side_effect = relation.get
648 self.relation_ids.side_effect = relation.relation_ids
649 self.related_units.side_effect = relation.related_units
650
651# @patch.object(ceph_utils, 'uuid')
652# @patch.object(ceph_utils, 'local_unit')
653# def test_get_request_states(self, mlocal_unit, muuid):
654# muuid.uuid1.return_value = '0bc7dc54'
655 @patch.object(ceph_utils, 'local_unit')
656 def test_get_request_states(self, mlocal_unit):
657 mlocal_unit.return_value = 'glance/0'
658 self.setup_client_relation(CEPH_CLIENT_RELATION)
659 rq = ceph_utils.CephBrokerRq()
660 rq.add_op_create_pool(name='glance', replica_count=3)
661 expect = {'ceph:8': {'complete': True, 'sent': True}}
662 self.assertEqual(ceph_utils.get_request_states(rq), expect)
663
664 @patch.object(ceph_utils, 'local_unit')
665 def test_get_request_states_newrq(self, mlocal_unit):
666 mlocal_unit.return_value = 'glance/0'
667 self.setup_client_relation(CEPH_CLIENT_RELATION)
668 rq = ceph_utils.CephBrokerRq()
669 rq.add_op_create_pool(name='glance', replica_count=4)
670 expect = {'ceph:8': {'complete': False, 'sent': False}}
671 self.assertEqual(ceph_utils.get_request_states(rq), expect)
672
673 @patch.object(ceph_utils, 'local_unit')
674 def test_get_request_states_pendingrq(self, mlocal_unit):
675 mlocal_unit.return_value = 'glance/0'
676 rel = copy.deepcopy(CEPH_CLIENT_RELATION)
677 del rel['ceph:8']['ceph/0']['broker-rsp-glance-0']
678 self.setup_client_relation(rel)
679 rq = ceph_utils.CephBrokerRq()
680 rq.add_op_create_pool(name='glance', replica_count=3)
681 expect = {'ceph:8': {'complete': False, 'sent': True}}
682 self.assertEqual(ceph_utils.get_request_states(rq), expect)
683
684 @patch.object(ceph_utils, 'local_unit')
685 def test_get_request_states_failedrq(self, mlocal_unit):
686 mlocal_unit.return_value = 'glance/0'
687 rel = copy.deepcopy(CEPH_CLIENT_RELATION)
688 rel['ceph:8']['ceph/0']['broker-rsp-glance-0'] = '{"request-id": "0bc7dc54", "exit-code": 1}'
689 self.setup_client_relation(rel)
690 rq = ceph_utils.CephBrokerRq()
691 rq.add_op_create_pool(name='glance', replica_count=3)
692 expect = {'ceph:8': {'complete': False, 'sent': True}}
693 self.assertEqual(ceph_utils.get_request_states(rq), expect)
694
695 @patch.object(ceph_utils, 'local_unit')
696 def test_is_request_sent(self, mlocal_unit):
697 mlocal_unit.return_value = 'glance/0'
698 self.setup_client_relation(CEPH_CLIENT_RELATION)
699 rq = ceph_utils.CephBrokerRq()
700 rq.add_op_create_pool(name='glance', replica_count=3)
701 self.assertTrue(ceph_utils.is_request_sent(rq))
702
703 @patch.object(ceph_utils, 'local_unit')
704 def test_is_request_sent_newrq(self, mlocal_unit):
705 mlocal_unit.return_value = 'glance/0'
706 self.setup_client_relation(CEPH_CLIENT_RELATION)
707 rq = ceph_utils.CephBrokerRq()
708 rq.add_op_create_pool(name='glance', replica_count=4)
709 self.assertFalse(ceph_utils.is_request_sent(rq))
710
711 @patch.object(ceph_utils, 'local_unit')
712 def test_is_request_sent_pending(self, mlocal_unit):
713 mlocal_unit.return_value = 'glance/0'
714 rel = copy.deepcopy(CEPH_CLIENT_RELATION)
715 del rel['ceph:8']['ceph/0']['broker-rsp-glance-0']
716 self.setup_client_relation(rel)
717 rq = ceph_utils.CephBrokerRq()
718 rq.add_op_create_pool(name='glance', replica_count=3)
719 self.assertTrue(ceph_utils.is_request_sent(rq))
720
721 @patch.object(ceph_utils, 'local_unit')
722 def test_is_request_sent_legacy(self, mlocal_unit):
723 mlocal_unit.return_value = 'glance/0'
724 self.setup_client_relation(CEPH_CLIENT_RELATION_LEGACY)
725 rq = ceph_utils.CephBrokerRq()
726 rq.add_op_create_pool(name='glance', replica_count=3)
727 self.assertTrue(ceph_utils.is_request_sent(rq))
728
729 @patch.object(ceph_utils, 'local_unit')
730 def test_is_request_sent_legacy_newrq(self, mlocal_unit):
731 mlocal_unit.return_value = 'glance/0'
732 self.setup_client_relation(CEPH_CLIENT_RELATION_LEGACY)
733 rq = ceph_utils.CephBrokerRq()
734 rq.add_op_create_pool(name='glance', replica_count=4)
735 self.assertFalse(ceph_utils.is_request_sent(rq))
736
737 @patch.object(ceph_utils, 'local_unit')
738 def test_is_request_sent_legacy_pending(self, mlocal_unit):
739 mlocal_unit.return_value = 'glance/0'
740 rel = copy.deepcopy(CEPH_CLIENT_RELATION_LEGACY)
741 del rel['ceph:8']['ceph/0']['broker_rsp']
742 rq = ceph_utils.CephBrokerRq()
743 rq.add_op_create_pool(name='glance', replica_count=3)
744 self.assertTrue(ceph_utils.is_request_sent(rq))
745
746 @patch.object(ceph_utils, 'uuid')
747 @patch.object(ceph_utils, 'local_unit')
748 def test_is_request_complete(self, mlocal_unit, muuid):
749 muuid.uuid1.return_value = '0bc7dc54'
750 mlocal_unit.return_value = 'glance/0'
751 self.setup_client_relation(CEPH_CLIENT_RELATION)
752 rq = ceph_utils.CephBrokerRq()
753 rq.add_op_create_pool(name='glance', replica_count=3)
754 self.assertTrue(ceph_utils.is_request_complete(rq))
755
756 @patch.object(ceph_utils, 'local_unit')
757 def test_is_request_complete_newrq(self, mlocal_unit):
758 mlocal_unit.return_value = 'glance/0'
759 self.setup_client_relation(CEPH_CLIENT_RELATION)
760 rq = ceph_utils.CephBrokerRq()
761 rq.add_op_create_pool(name='glance', replica_count=4)
762 self.assertFalse(ceph_utils.is_request_complete(rq))
763
764 @patch.object(ceph_utils, 'local_unit')
765 def test_is_request_complete_pending(self, mlocal_unit):
766 mlocal_unit.return_value = 'glance/0'
767 rel = copy.deepcopy(CEPH_CLIENT_RELATION)
768 del rel['ceph:8']['ceph/0']['broker-rsp-glance-0']
769 self.setup_client_relation(rel)
770 rq = ceph_utils.CephBrokerRq()
771 rq.add_op_create_pool(name='glance', replica_count=3)
772 self.assertFalse(ceph_utils.is_request_complete(rq))
773
774 @patch.object(ceph_utils, 'local_unit')
775 def test_is_request_complete_legacy(self, mlocal_unit):
776 mlocal_unit.return_value = 'glance/0'
777 self.setup_client_relation(CEPH_CLIENT_RELATION_LEGACY)
778 rq = ceph_utils.CephBrokerRq()
779 rq.add_op_create_pool(name='glance', replica_count=3)
780 self.assertTrue(ceph_utils.is_request_complete(rq))
781
782 @patch.object(ceph_utils, 'local_unit')
783 def test_is_request_complete_legacy_newrq(self, mlocal_unit):
784 mlocal_unit.return_value = 'glance/0'
785 self.setup_client_relation(CEPH_CLIENT_RELATION_LEGACY)
786 rq = ceph_utils.CephBrokerRq()
787 rq.add_op_create_pool(name='glance', replica_count=4)
788 self.assertFalse(ceph_utils.is_request_complete(rq))
789
790 @patch.object(ceph_utils, 'local_unit')
791 def test_is_request_complete_legacy_pending(self, mlocal_unit):
792 mlocal_unit.return_value = 'glance/0'
793 rel = copy.deepcopy(CEPH_CLIENT_RELATION_LEGACY)
794 del rel['ceph:8']['ceph/0']['broker_rsp']
795 self.setup_client_relation(rel)
796 rq = ceph_utils.CephBrokerRq()
797 rq.add_op_create_pool(name='glance', replica_count=3)
798 self.assertFalse(ceph_utils.is_request_complete(rq))
799
800 def test_equivalent_broker_requests(self):
801 rq1 = ceph_utils.CephBrokerRq()
802 rq1.add_op_create_pool(name='glance', replica_count=4)
803 rq2 = ceph_utils.CephBrokerRq()
804 rq2.add_op_create_pool(name='glance', replica_count=4)
805 self.assertTrue(rq1 == rq2)
806
807 def test_equivalent_broker_requests_diff1(self):
808 rq1 = ceph_utils.CephBrokerRq()
809 rq1.add_op_create_pool(name='glance', replica_count=3)
810 rq2 = ceph_utils.CephBrokerRq()
811 rq2.add_op_create_pool(name='glance', replica_count=4)
812 self.assertFalse(rq1 == rq2)
813
814 def test_equivalent_broker_requests_diff2(self):
815 rq1 = ceph_utils.CephBrokerRq()
816 rq1.add_op_create_pool(name='glance', replica_count=3)
817 rq2 = ceph_utils.CephBrokerRq()
818 rq2.add_op_create_pool(name='cinder', replica_count=3)
819 self.assertFalse(rq1 == rq2)
820
821 def test_equivalent_broker_requests_diff3(self):
822 rq1 = ceph_utils.CephBrokerRq()
823 rq1.add_op_create_pool(name='glance', replica_count=3)
824 rq2 = ceph_utils.CephBrokerRq(api_version=2)
825 rq2.add_op_create_pool(name='glance', replica_count=3)
826 self.assertFalse(rq1 == rq2)
827
828 @patch.object(ceph_utils, 'uuid')
829 @patch.object(ceph_utils, 'local_unit')
830 def test_is_request_complete_for_rid(self, mlocal_unit, muuid):
831 muuid.uuid1.return_value = '0bc7dc54'
832 req = ceph_utils.CephBrokerRq()
833 req.add_op_create_pool(name='glance', replica_count=3)
834 mlocal_unit.return_value = 'glance/0'
835 self.setup_client_relation(CEPH_CLIENT_RELATION)
836 self.assertTrue(ceph_utils.is_request_complete_for_rid(req, 'ceph:8'))
837
838 @patch.object(ceph_utils, 'uuid')
839 @patch.object(ceph_utils, 'local_unit')
840 def test_is_request_complete_for_rid_newrq(self, mlocal_unit, muuid):
841 muuid.uuid1.return_value = 'a44c0fa6'
842 req = ceph_utils.CephBrokerRq()
843 req.add_op_create_pool(name='glance', replica_count=4)
844 mlocal_unit.return_value = 'glance/0'
845 self.setup_client_relation(CEPH_CLIENT_RELATION)
846 self.assertFalse(ceph_utils.is_request_complete_for_rid(req, 'ceph:8'))
847
848 @patch.object(ceph_utils, 'uuid')
849 @patch.object(ceph_utils, 'local_unit')
850 def test_is_request_complete_for_rid_failed(self, mlocal_unit, muuid):
851 muuid.uuid1.return_value = '0bc7dc54'
852 req = ceph_utils.CephBrokerRq()
853 req.add_op_create_pool(name='glance', replica_count=4)
854 mlocal_unit.return_value = 'glance/0'
855 rel = copy.deepcopy(CEPH_CLIENT_RELATION)
856 rel['ceph:8']['ceph/0']['broker-rsp-glance-0'] = '{"request-id": "0bc7dc54", "exit-code": 1}'
857 self.setup_client_relation(rel)
858 self.assertFalse(ceph_utils.is_request_complete_for_rid(req, 'ceph:8'))
859
860 @patch.object(ceph_utils, 'uuid')
861 @patch.object(ceph_utils, 'local_unit')
862 def test_is_request_complete_for_rid_pending(self, mlocal_unit, muuid):
863 muuid.uuid1.return_value = '0bc7dc54'
864 req = ceph_utils.CephBrokerRq()
865 req.add_op_create_pool(name='glance', replica_count=4)
866 mlocal_unit.return_value = 'glance/0'
867 rel = copy.deepcopy(CEPH_CLIENT_RELATION)
868 del rel['ceph:8']['ceph/0']['broker-rsp-glance-0']
869 self.setup_client_relation(rel)
870 self.assertFalse(ceph_utils.is_request_complete_for_rid(req, 'ceph:8'))
871
872 @patch.object(ceph_utils, 'uuid')
873 @patch.object(ceph_utils, 'local_unit')
874 def test_is_request_complete_for_rid_legacy(self, mlocal_unit, muuid):
875 muuid.uuid1.return_value = '0bc7dc54'
876 req = ceph_utils.CephBrokerRq()
877 req.add_op_create_pool(name='glance', replica_count=3)
878 mlocal_unit.return_value = 'glance/0'
879 self.setup_client_relation(CEPH_CLIENT_RELATION_LEGACY)
880 self.assertTrue(ceph_utils.is_request_complete_for_rid(req, 'ceph:8'))
881
882 @patch.object(ceph_utils, 'local_unit')
883 def test_get_broker_rsp_key(self, mlocal_unit):
884 mlocal_unit.return_value = 'glance/0'
885 self.assertEqual(ceph_utils.get_broker_rsp_key(), 'broker-rsp-glance-0')
886
887 @patch.object(ceph_utils, 'local_unit')
888 def test_send_request_if_needed(self, mlocal_unit):
889 mlocal_unit.return_value = 'glance/0'
890 self.setup_client_relation(CEPH_CLIENT_RELATION)
891 rq = ceph_utils.CephBrokerRq()
892 rq.add_op_create_pool(name='glance', replica_count=3)
893 ceph_utils.send_request_if_needed(rq)
894 self.relation_set.assert_has_calls([])
895
896 @patch.object(ceph_utils, 'uuid')
897 @patch.object(ceph_utils, 'local_unit')
898 def test_send_request_if_needed_newrq(self, mlocal_unit, muuid):
899 muuid.uuid1.return_value = 'de67511e'
900 mlocal_unit.return_value = 'glance/0'
901 self.setup_client_relation(CEPH_CLIENT_RELATION)
902 rq = ceph_utils.CephBrokerRq()
903 rq.add_op_create_pool(name='glance', replica_count=4)
904 ceph_utils.send_request_if_needed(rq)
905 actual = json.loads(self.relation_set.call_args_list[0][1]['broker_req'])
906 self.assertEqual(actual['api-version'], 1)
907 self.assertEqual(actual['request-id'], 'de67511e')
908 self.assertEqual(actual['ops'][0]['replicas'], 4)
909 self.assertEqual(actual['ops'][0]['op'], 'create-pool')
910 self.assertEqual(actual['ops'][0]['name'], 'glance')
582911
=== modified file 'tests/helpers.py'
--- tests/helpers.py 2014-11-25 15:07:02 +0000
+++ tests/helpers.py 2015-09-16 09:01:05 +0000
@@ -74,12 +74,12 @@
74 def __init__(self, relation_data):74 def __init__(self, relation_data):
75 self.relation_data = relation_data75 self.relation_data = relation_data
7676
77 def get(self, attr=None, unit=None, rid=None):77 def get(self, attribute=None, unit=None, rid=None):
78 if not rid or rid == 'foo:0':78 if not rid or rid == 'foo:0':
79 if attr is None:79 if attribute is None:
80 return self.relation_data80 return self.relation_data
81 elif attr in self.relation_data:81 elif attribute in self.relation_data:
82 return self.relation_data[attr]82 return self.relation_data[attribute]
83 return None83 return None
84 else:84 else:
85 if rid not in self.relation_data:85 if rid not in self.relation_data:
@@ -88,9 +88,9 @@
88 relation = self.relation_data[rid][unit]88 relation = self.relation_data[rid][unit]
89 except KeyError:89 except KeyError:
90 return None90 return None
91 if attr in relation:91 if attribute and attribute in relation:
92 return relation[attr]92 return relation[attribute]
93 return None93 return relation
9494
95 def relation_ids(self, relation=None):95 def relation_ids(self, relation=None):
96 return self.relation_data.keys()96 return self.relation_data.keys()

Subscribers

People subscribed via source and target branches