Merge lp:~hopem/charm-helpers/fix-lp1425999 into lp:charm-helpers

Proposed by Edward Hope-Morley
Status: Merged
Merged at revision: 327
Proposed branch: lp:~hopem/charm-helpers/fix-lp1425999
Merge into: lp:charm-helpers
Diff against target: 168 lines (+65/-15)
2 files modified
charmhelpers/contrib/database/mysql.py (+17/-12)
tests/contrib/database/test_mysql.py (+48/-3)
To merge this branch: bzr merge lp:~hopem/charm-helpers/fix-lp1425999
Reviewer Review Type Date Requested Status
Jorge Niedbalski (community) Approve
Review via email: mp+251158@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Jorge Niedbalski (niedbalski) wrote :

Hello Edward.

I found out that there is a few other places on which similar host<->ip logic
is being used. I just re-factored/moved this to the contrib.network.ip module, which
in my opinion is a better place for having this.

The proposal: https://code.launchpad.net/~niedbalski/charm-helpers/ip-host-translation/+merge/251189

I would suggest to review that and integrate your code according to the inline comment.

review: Needs Fixing
325. By Edward Hope-Morley

sync trunk

326. By Edward Hope-Morley

switch to ip.get_host_ip()

Revision history for this message
Edward Hope-Morley (hopem) wrote :

@jorge Fixed.

Revision history for this message
Jorge Niedbalski (niedbalski) wrote :

Hello Ed,

I fixed a few lint errors:

charmhelpers/contrib/database/mysql.py:3:1: F401 'socket' imported but unused
charmhelpers/contrib/database/mysql.py:17:1: F401 'WARNING' imported but unused
tests/contrib/database/test_mysql.py:72:66: W291 trailing whitespace

Merged.

Revision history for this message
Jorge Niedbalski (niedbalski) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'charmhelpers/contrib/database/mysql.py'
2--- charmhelpers/contrib/database/mysql.py 2015-02-26 16:05:44 +0000
3+++ charmhelpers/contrib/database/mysql.py 2015-02-27 10:03:09 +0000
4@@ -15,14 +15,15 @@
5 write_file
6 )
7 from charmhelpers.core.hookenv import (
8+ config as config_get,
9 relation_get,
10 related_units,
11 unit_get,
12 log,
13 DEBUG,
14 INFO,
15+ WARNING,
16 )
17-from charmhelpers.core.hookenv import config as config_get
18 from charmhelpers.fetch import (
19 apt_install,
20 apt_update,
21@@ -32,6 +33,7 @@
22 peer_store,
23 peer_retrieve,
24 )
25+from charmhelpers.contrib.network.ip import get_host_ip
26
27 try:
28 import MySQLdb
29@@ -220,6 +222,18 @@
30 """Retrieve or generate mysql root password for service units."""
31 return self.get_mysql_password(username=None, password=password)
32
33+ def normalize_address(self, hostname):
34+ """Ensure that address returned is an IP address (i.e. not fqdn)"""
35+ if config_get('prefer-ipv6'):
36+ # TODO: add support for ipv6 dns
37+ return hostname
38+
39+ if hostname != unit_get('private-address'):
40+ return get_host_ip(hostname, fallback=hostname)
41+
42+ # Otherwise assume localhost
43+ return '127.0.0.1'
44+
45 def get_allowed_units(self, database, username, relation_id=None):
46 """Get list of units with access grants for database with username.
47
48@@ -247,6 +261,7 @@
49
50 if hosts:
51 for host in hosts:
52+ host = self.normalize_address(host)
53 if self.grant_exists(database, username, host):
54 log("Grant exists for host '%s' on db '%s'" %
55 (host, database), level=DEBUG)
56@@ -262,21 +277,11 @@
57
58 def configure_db(self, hostname, database, username, admin=False):
59 """Configure access to database for username from hostname."""
60- if config_get('prefer-ipv6'):
61- remote_ip = hostname
62- elif hostname != unit_get('private-address'):
63- try:
64- remote_ip = socket.gethostbyname(hostname)
65- except Exception:
66- # socket.gethostbyname doesn't support ipv6
67- remote_ip = hostname
68- else:
69- remote_ip = '127.0.0.1'
70-
71 self.connect(password=self.get_mysql_root_password())
72 if not self.database_exists(database):
73 self.create_database(database)
74
75+ remote_ip = self.normalize_address(hostname)
76 password = self.get_mysql_password(username)
77 if not self.grant_exists(database, username, remote_ip):
78 if not admin:
79
80=== modified file 'tests/contrib/database/test_mysql.py'
81--- tests/contrib/database/test_mysql.py 2015-02-25 19:15:53 +0000
82+++ tests/contrib/database/test_mysql.py 2015-02-27 10:03:09 +0000
83@@ -11,6 +11,7 @@
84 def setUp(self):
85 super(MysqlTests, self).setUp()
86
87+ @mock.patch.object(mysql.MySQLHelper, 'normalize_address')
88 @mock.patch.object(mysql.MySQLHelper, 'get_mysql_password')
89 @mock.patch.object(mysql.MySQLHelper, 'grant_exists')
90 @mock.patch.object(mysql, 'relation_get')
91@@ -19,7 +20,11 @@
92 def test_get_allowed_units(self, mock_log, mock_related_units,
93 mock_relation_get,
94 mock_grant_exists,
95- mock_get_password):
96+ mock_get_password,
97+ mock_normalize_address):
98+
99+ # echo
100+ mock_normalize_address.side_effect = lambda addr: addr
101
102 def mock_rel_get(unit, rid):
103 if unit == 'unit/0':
104@@ -54,6 +59,44 @@
105 helper.grant_exists.assert_has_calls(calls)
106 self.assertEqual(units, set(['unit/0', 'unit/1', 'unit/2']))
107
108+ @mock.patch('charmhelpers.contrib.network.ip.socket')
109+ @mock.patch.object(mysql, 'unit_get')
110+ @mock.patch.object(mysql, 'config_get')
111+ @mock.patch.object(mysql, 'log')
112+ def test_normalize_address(self, mock_log, mock_config_get, mock_unit_get,
113+ mock_socket):
114+ helper = mysql.MySQLHelper('foo', 'bar', host='hostA')
115+ # prefer-ipv6
116+ mock_config_get.return_value = False
117+ # echo
118+ mock_socket.gethostbyname.side_effect = lambda addr: addr
119+
120+ mock_unit_get.return_value = '10.0.0.1'
121+ out = helper.normalize_address('10.0.0.1')
122+ self.assertEqual('127.0.0.1', out)
123+ mock_config_get.assert_called_with('prefer-ipv6')
124+
125+ mock_unit_get.return_value = '10.0.0.1'
126+ out = helper.normalize_address('10.0.0.2')
127+ self.assertEqual('10.0.0.2', out)
128+ mock_config_get.assert_called_with('prefer-ipv6')
129+
130+ out = helper.normalize_address('2001:db8:1::1')
131+ self.assertEqual('2001:db8:1::1', out)
132+ mock_config_get.assert_called_with('prefer-ipv6')
133+
134+ mock_socket.gethostbyname.side_effect = Exception
135+ out = helper.normalize_address('unresolvable')
136+ self.assertEqual('unresolvable', out)
137+ mock_config_get.assert_called_with('prefer-ipv6')
138+
139+ # prefer-ipv6
140+ mock_config_get.return_value = True
141+ mock_socket.gethostbyname.side_effect = 'other'
142+ out = helper.normalize_address('unresolvable')
143+ self.assertEqual('unresolvable', out)
144+ mock_config_get.assert_called_with('prefer-ipv6')
145+
146
147 class PerconaTests(unittest.TestCase):
148
149@@ -62,7 +105,8 @@
150
151 @mock.patch.object(mysql.PerconaClusterHelper, 'get_mem_total')
152 @mock.patch.object(mysql, 'config_get')
153- def test_parse_config_innodb_pool_fixed(self, config, mem):
154+ @mock.patch.object(mysql, 'log')
155+ def test_parse_config_innodb_pool_fixed(self, log, config, mem):
156 mem.return_value = "100G"
157 config.return_value = {
158 'innodb-buffer-pool-size': "50%",
159@@ -76,7 +120,8 @@
160
161 @mock.patch.object(mysql.PerconaClusterHelper, 'get_mem_total')
162 @mock.patch.object(mysql, 'config_get')
163- def test_parse_config_innodb_pool_not_set(self, config, mem):
164+ @mock.patch.object(mysql, 'log')
165+ def test_parse_config_innodb_pool_not_set(self, mog, config, mem):
166 mem.return_value = "100G"
167 config.return_value = {
168 'innodb-buffer-pool-size': '',

Subscribers

People subscribed via source and target branches