Merge lp:~james-page/charm-helpers/is-relation-made into lp:charm-helpers

Proposed by James Page
Status: Merged
Merged at revision: 92
Proposed branch: lp:~james-page/charm-helpers/is-relation-made
Merge into: lp:charm-helpers
Diff against target: 260 lines (+109/-18)
7 files modified
charmhelpers/cli/host.py (+1/-0)
charmhelpers/contrib/ssl/__init__.py (+7/-8)
charmhelpers/core/hookenv.py (+20/-0)
charmhelpers/fetch/bzrurl.py (+1/-1)
tests/contrib/ssl/test_ssl.py (+1/-5)
tests/core/test_hookenv.py (+79/-0)
tests/fetch/test_bzrurl.py (+0/-4)
To merge this branch: bzr merge lp:~james-page/charm-helpers/is-relation-made
Reviewer Review Type Date Requested Status
James Page Needs Resubmitting
Adam Gandelman (community) Needs Fixing
Review via email: mp+191920@code.launchpad.net

Description of the change

Add is_relation_made helper for deep testing of relation state.

For example, the ceph charm only passes an auth key to clients once
its bootstrapped; until then the client can do anything:

  if is_relation_made('ceph:0', 'key'):
     configure_and_do_stuff()
  else:
     don_t()

Unit tests as well.

Thanks for looking.

To post a comment you must log in.
Revision history for this message
James Page (james-page) wrote :

I also tidied the majority of lint in the project;

make lint is a good check when reviewing merge proposals; don't think everyone has been doing that!

82. By James Page

Rebase against parent branch

83. By James Page

Rebase on parent

Revision history for this message
Adam Gandelman (gandelman-a) wrote :

This looks good, but any chance we can allow is_relation_made() to also take a list of keys? That way we could use the same for relations that require a bit more data, ie:

keys = ['password, 'db-host']
if is_relation_made('shared-db:0', settings):
    configure_db()

Revision history for this message
Adam Gandelman (gandelman-a) wrote :

Also, I think the current behavior of relation_get() will cause this to evalutate as True even if the relation setting has not been set:

if relation_get(key, rid=r_id, unit=unit):
   return True

Might be a good idea to also check whatever relation_get() returns != ''

review: Needs Fixing
84. By James Page

Add support for multiple key checks in is_relation_made

85. By James Page

Rework a bit for lists

Revision history for this message
James Page (james-page) wrote :

relation_get for a missing key should always return None so I think that is OK.

I updated to support lists as well as single strings as keys.

review: Needs Resubmitting

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'charmhelpers/cli/host.py'
--- charmhelpers/cli/host.py 2013-06-20 15:03:24 +0000
+++ charmhelpers/cli/host.py 2013-10-21 22:54:42 +0000
@@ -7,6 +7,7 @@
7 "List mounts"7 "List mounts"
8 return host.mounts()8 return host.mounts()
99
10
10@cmdline.subcommand_builder('service', description="Control system services")11@cmdline.subcommand_builder('service', description="Control system services")
11def service(subparser):12def service(subparser):
12 subparser.add_argument("action", help="The action to perform (start, stop, etc...)")13 subparser.add_argument("action", help="The action to perform (start, stop, etc...)")
1314
=== modified file 'charmhelpers/contrib/ssl/__init__.py'
--- charmhelpers/contrib/ssl/__init__.py 2013-08-28 09:12:05 +0000
+++ charmhelpers/contrib/ssl/__init__.py 2013-10-21 22:54:42 +0000
@@ -34,7 +34,7 @@
34 cmd = ["/usr/bin/openssl", "req", "-new", "-newkey",34 cmd = ["/usr/bin/openssl", "req", "-new", "-newkey",
35 "rsa:{}".format(keysize), "-days", "365", "-nodes", "-x509",35 "rsa:{}".format(keysize), "-days", "365", "-nodes", "-x509",
36 "-keyout", keyfile,36 "-keyout", keyfile,
37 "-out", certfile, "-config", config]37 "-out", certfile, "-config", config]
38 elif subject:38 elif subject:
39 ssl_subject = ""39 ssl_subject = ""
40 if "country" in subject:40 if "country" in subject:
@@ -50,8 +50,8 @@
50 if "cn" in subject:50 if "cn" in subject:
51 ssl_subject = ssl_subject + "/CN={}".format(subject["cn"])51 ssl_subject = ssl_subject + "/CN={}".format(subject["cn"])
52 else:52 else:
53 hookenv.log("When using \"subject\" argument you must " \53 hookenv.log("When using \"subject\" argument you must "
54 "provide \"cn\" field at very least")54 "provide \"cn\" field at very least")
55 return False55 return False
56 if "email" in subject:56 if "email" in subject:
57 ssl_subject = ssl_subject + "/emailAddress={}".format(subject["email"])57 ssl_subject = ssl_subject + "/emailAddress={}".format(subject["email"])
@@ -59,16 +59,16 @@
59 cmd = ["/usr/bin/openssl", "req", "-new", "-newkey",59 cmd = ["/usr/bin/openssl", "req", "-new", "-newkey",
60 "rsa:{}".format(keysize), "-days", "365", "-nodes", "-x509",60 "rsa:{}".format(keysize), "-days", "365", "-nodes", "-x509",
61 "-keyout", keyfile,61 "-keyout", keyfile,
62 "-out", certfile, "-subj", ssl_subject]62 "-out", certfile, "-subj", ssl_subject]
63 elif cn:63 elif cn:
64 cmd = ["/usr/bin/openssl", "req", "-new", "-newkey",64 cmd = ["/usr/bin/openssl", "req", "-new", "-newkey",
65 "rsa:{}".format(keysize), "-days", "365", "-nodes", "-x509",65 "rsa:{}".format(keysize), "-days", "365", "-nodes", "-x509",
66 "-keyout", keyfile,66 "-keyout", keyfile,
67 "-out", certfile, "-subj", "/CN={}".format(cn)]67 "-out", certfile, "-subj", "/CN={}".format(cn)]
6868
69 if not cmd:69 if not cmd:
70 hookenv.log("No config, subject or cn provided," \70 hookenv.log("No config, subject or cn provided,"
71 "unable to generate self signed SSL certificates")71 "unable to generate self signed SSL certificates")
72 return False72 return False
73 try:73 try:
74 subprocess.check_call(cmd)74 subprocess.check_call(cmd)
@@ -76,4 +76,3 @@
76 except Exception as e:76 except Exception as e:
77 print "Execution of openssl command failed:\n{}".format(e)77 print "Execution of openssl command failed:\n{}".format(e)
78 return False78 return False
79
8079
=== modified file 'charmhelpers/core/hookenv.py'
--- charmhelpers/core/hookenv.py 2013-10-21 08:34:03 +0000
+++ charmhelpers/core/hookenv.py 2013-10-21 22:54:42 +0000
@@ -285,6 +285,26 @@
285 return rels285 return rels
286286
287287
288@cached
289def is_relation_made(relation, keys='private-address'):
290 '''
291 Determine whether a relation is established by checking for
292 presence of key(s). If a list of keys is provided, they
293 must all be present for the relation to be identified as made
294 '''
295 if isinstance(keys, str):
296 keys = [keys]
297 for r_id in relation_ids(relation):
298 for unit in related_units(r_id):
299 context = {}
300 for k in keys:
301 context[k] = relation_get(k, rid=r_id,
302 unit=unit)
303 if None not in context.values():
304 return True
305 return False
306
307
288def open_port(port, protocol="TCP"):308def open_port(port, protocol="TCP"):
289 """Open a service network port"""309 """Open a service network port"""
290 _args = ['open-port']310 _args = ['open-port']
291311
=== modified file 'charmhelpers/fetch/bzrurl.py'
--- charmhelpers/fetch/bzrurl.py 2013-08-22 10:19:51 +0000
+++ charmhelpers/fetch/bzrurl.py 2013-10-21 22:54:42 +0000
@@ -12,6 +12,7 @@
12 apt_install("python-bzrlib")12 apt_install("python-bzrlib")
13 from bzrlib.branch import Branch13 from bzrlib.branch import Branch
1414
15
15class BzrUrlFetchHandler(BaseFetchHandler):16class BzrUrlFetchHandler(BaseFetchHandler):
16 """Handler for bazaar branches via generic and lp URLs"""17 """Handler for bazaar branches via generic and lp URLs"""
17 def can_handle(self, source):18 def can_handle(self, source):
@@ -46,4 +47,3 @@
46 except OSError as e:47 except OSError as e:
47 raise UnhandledSource(e.strerror)48 raise UnhandledSource(e.strerror)
48 return dest_dir49 return dest_dir
49
5050
=== modified file 'tests/contrib/ssl/test_ssl.py'
--- tests/contrib/ssl/test_ssl.py 2013-08-27 17:08:44 +0000
+++ tests/contrib/ssl/test_ssl.py 2013-10-21 22:54:42 +0000
@@ -1,6 +1,4 @@
1import subprocess1from mock import patch
2
3from mock import patch, call, MagicMock
4from testtools import TestCase2from testtools import TestCase
53
6from charmhelpers.contrib import ssl4from charmhelpers.contrib import ssl
@@ -39,7 +37,6 @@
39 result = ssl.generate_selfsigned("mykey.key", "mycert.crt", subject=subject)37 result = ssl.generate_selfsigned("mykey.key", "mycert.crt", subject=subject)
40 self.assertFalse(result)38 self.assertFalse(result)
4139
42
43 @patch('subprocess.check_call')40 @patch('subprocess.check_call')
44 def test_generate_selfsigned_file(self, mock_call):41 def test_generate_selfsigned_file(self, mock_call):
45 ssl.generate_selfsigned("mykey.key", "mycert.crt", config="test.cnf")42 ssl.generate_selfsigned("mykey.key", "mycert.crt", config="test.cnf")
@@ -49,7 +46,6 @@
49 'mykey.key', '-out', 'mycert.crt',46 'mykey.key', '-out', 'mycert.crt',
50 '-config', 'test.cnf'])47 '-config', 'test.cnf'])
5148
52
53 @patch('subprocess.check_call')49 @patch('subprocess.check_call')
54 def test_generate_selfsigned_cn_key(self, mock_call):50 def test_generate_selfsigned_cn_key(self, mock_call):
55 ssl.generate_selfsigned("mykey.key", "mycert.crt", keysize="2048", cn="mysite.example.com")51 ssl.generate_selfsigned("mykey.key", "mycert.crt", keysize="2048", cn="mysite.example.com")
5652
=== modified file 'tests/core/test_hookenv.py'
--- tests/core/test_hookenv.py 2013-10-21 08:34:03 +0000
+++ tests/core/test_hookenv.py 2013-10-21 22:54:42 +0000
@@ -498,6 +498,85 @@
498 },498 },
499 })499 })
500500
501 @patch('charmhelpers.core.hookenv.relation_ids')
502 @patch('charmhelpers.core.hookenv.related_units')
503 @patch('charmhelpers.core.hookenv.relation_get')
504 def test_is_relation_made(self, relation_get, related_units,
505 relation_ids):
506 relation_get.return_value = 'hostname'
507 related_units.return_value = ['test/1']
508 relation_ids.return_value = ['test:0']
509 self.assertTrue(hookenv.is_relation_made('test'))
510 relation_get.assert_called_with('private-address',
511 rid='test:0', unit='test/1')
512
513 @patch('charmhelpers.core.hookenv.relation_ids')
514 @patch('charmhelpers.core.hookenv.related_units')
515 @patch('charmhelpers.core.hookenv.relation_get')
516 def test_is_relation_made_multi_unit(self, relation_get, related_units,
517 relation_ids):
518 relation_get.side_effect = [None, 'hostname']
519 related_units.return_value = ['test/1', 'test/2']
520 relation_ids.return_value = ['test:0']
521 self.assertTrue(hookenv.is_relation_made('test'))
522
523 @patch('charmhelpers.core.hookenv.relation_ids')
524 @patch('charmhelpers.core.hookenv.related_units')
525 @patch('charmhelpers.core.hookenv.relation_get')
526 def test_is_relation_made_different_key(self,
527 relation_get, related_units,
528 relation_ids):
529 relation_get.return_value = 'hostname'
530 related_units.return_value = ['test/1']
531 relation_ids.return_value = ['test:0']
532 self.assertTrue(hookenv.is_relation_made('test', keys='auth'))
533 relation_get.assert_called_with('auth',
534 rid='test:0', unit='test/1')
535
536 @patch('charmhelpers.core.hookenv.relation_ids')
537 @patch('charmhelpers.core.hookenv.related_units')
538 @patch('charmhelpers.core.hookenv.relation_get')
539 def test_is_relation_made_multiple_keys(self,
540 relation_get, related_units,
541 relation_ids):
542 relation_get.side_effect = ['password', 'hostname']
543 related_units.return_value = ['test/1']
544 relation_ids.return_value = ['test:0']
545 self.assertTrue(hookenv.is_relation_made('test',
546 keys=['auth', 'host']))
547 relation_get.assert_has_calls(
548 [call('auth', rid='test:0', unit='test/1'),
549 call('host', rid='test:0', unit='test/1')]
550 )
551
552 @patch('charmhelpers.core.hookenv.relation_ids')
553 @patch('charmhelpers.core.hookenv.related_units')
554 @patch('charmhelpers.core.hookenv.relation_get')
555 def test_is_relation_made_not_made(self,
556 relation_get, related_units,
557 relation_ids):
558 relation_get.return_value = None
559 related_units.return_value = ['test/1']
560 relation_ids.return_value = ['test:0']
561 self.assertFalse(hookenv.is_relation_made('test'))
562
563 @patch('charmhelpers.core.hookenv.relation_ids')
564 @patch('charmhelpers.core.hookenv.related_units')
565 @patch('charmhelpers.core.hookenv.relation_get')
566 def test_is_relation_made_not_made_multiple_keys(self,
567 relation_get,
568 related_units,
569 relation_ids):
570 relation_get.side_effect = ['password', None]
571 related_units.return_value = ['test/1']
572 relation_ids.return_value = ['test:0']
573 self.assertFalse(hookenv.is_relation_made('test',
574 keys=['auth', 'host']))
575 relation_get.assert_has_calls(
576 [call('auth', rid='test:0', unit='test/1'),
577 call('host', rid='test:0', unit='test/1')]
578 )
579
501 @patch('charmhelpers.core.hookenv.config')580 @patch('charmhelpers.core.hookenv.config')
502 @patch('charmhelpers.core.hookenv.relation_type')581 @patch('charmhelpers.core.hookenv.relation_type')
503 @patch('charmhelpers.core.hookenv.local_unit')582 @patch('charmhelpers.core.hookenv.local_unit')
504583
=== modified file 'tests/fetch/test_bzrurl.py'
--- tests/fetch/test_bzrurl.py 2013-08-21 11:45:37 +0000
+++ tests/fetch/test_bzrurl.py 2013-10-21 22:54:42 +0000
@@ -41,7 +41,6 @@
41 )41 )
42 self.fh = bzrurl.BzrUrlFetchHandler()42 self.fh = bzrurl.BzrUrlFetchHandler()
4343
44
45 def test_handles_bzr_urls(self):44 def test_handles_bzr_urls(self):
46 for url in self.valid_urls:45 for url in self.valid_urls:
47 result = self.fh.can_handle(url)46 result = self.fh.can_handle(url)
@@ -50,7 +49,6 @@
50 result = self.fh.can_handle(url)49 result = self.fh.can_handle(url)
51 self.assertNotEqual(result, True, url)50 self.assertNotEqual(result, True, url)
5251
53
54 @patch('bzrlib.branch.Branch.open')52 @patch('bzrlib.branch.Branch.open')
55 def test_branch(self, _open):53 def test_branch(self, _open):
56 dest_path = "/destination/path"54 dest_path = "/destination/path"
@@ -65,7 +63,6 @@
65 with patch.dict('os.environ', {'CHARM_DIR': 'foo'}):63 with patch.dict('os.environ', {'CHARM_DIR': 'foo'}):
66 self.assertRaises(UnhandledSource, self.fh.branch, url, dest_path)64 self.assertRaises(UnhandledSource, self.fh.branch, url, dest_path)
6765
68
69 @patch('charmhelpers.fetch.bzrurl.mkdir')66 @patch('charmhelpers.fetch.bzrurl.mkdir')
70 def test_installs(self, _mkdir):67 def test_installs(self, _mkdir):
71 self.fh.branch = MagicMock()68 self.fh.branch = MagicMock()
@@ -77,4 +74,3 @@
77 where = self.fh.install(url)74 where = self.fh.install(url)
78 self.assertEqual(where, dest)75 self.assertEqual(where, dest)
79 _mkdir.assert_called_with(where, perms=0755)76 _mkdir.assert_called_with(where, perms=0755)
80

Subscribers

People subscribed via source and target branches