Merge lp:~xianghui/charm-helpers/support-ipv6 into lp:charm-helpers
- support-ipv6
- Merge into devel
Status: | Merged |
---|---|
Merged at revision: | 193 |
Proposed branch: | lp:~xianghui/charm-helpers/support-ipv6 |
Merge into: | lp:charm-helpers |
Diff against target: |
278 lines (+150/-14) 6 files modified
charmhelpers/contrib/network/ip.py (+19/-1) charmhelpers/contrib/openstack/context.py (+20/-4) charmhelpers/contrib/openstack/ip.py (+7/-3) charmhelpers/contrib/openstack/templates/haproxy.cfg (+3/-3) tests/contrib/network/test_ip.py (+47/-1) tests/contrib/openstack/test_os_contexts.py (+54/-2) |
To merge this branch: | bzr merge lp:~xianghui/charm-helpers/support-ipv6 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Edward Hope-Morley | Approve | ||
Review via email: mp+228637@code.launchpad.net |
Commit message
Description of the change
[Hui Xiang]
Allow rabbitmq-server client to get its ipv6 address.
(rabbitmq-server charm already set "hostname" with relation-set().)
Allow ceph-client to get ipv6 address from 'host-ip'.
(will let ceph to set "host-ip" with relation-set for clients)
Add get_ipv6_addr() funtion for ipv6.
Edward Hope-Morley (hopem) wrote : | # |
Hui, I'm getting some lint errors:
$ make lint
Checking for Python syntax...
charmhelpers/
charmhelpers/
charmhelpers/
tests/contrib/
make: *** [lint] Error 1
Also, could you please update/add unit tests to cover the change you are making.
Edward Hope-Morley (hopem) wrote : | # |
Currently getting the following unit test failures as well: https:/
Xiang Hui (xianghui) wrote : | # |
> Hui, I'm getting some lint errors:
>
> $ make lint
> Checking for Python syntax...
> charmhelpers/
> 'get_ipv6_addr'
> charmhelpers/
> charmhelpers/
> tests/contrib/
> make: *** [lint] Error 1
>
> Also, could you please update/add unit tests to cover the change you are
> making.
I don't know why the conflict deleted new added function "get_ipv6_addr()", will added on next patch, and except this error, other errors are not caused by my changes, if these strict lint rules applied to everyone?thanks.
Xiang Hui (xianghui) wrote : | # |
> Currently getting the following unit test failures as well:
> https:/
Just the first two errors "get_ipv6_add.." caused by my changes due to the conflict mis-deleted.
Edward Hope-Morley (hopem) wrote : | # |
If I remove all your changes I get no errors i.e. trunk has no errors.
Xiang Hui (xianghui) wrote : | # |
> If I remove all your changes I get no errors i.e. trunk has no errors.
Done, thanks for your efforts.
James Page (james-page) : | # |
Edward Hope-Morley (hopem) : | # |
Edward Hope-Morley (hopem) wrote : | # |
Couple of issues that need fixing.
Xiang Hui (xianghui) wrote : | # |
> Couple of issues that need fixing.
Thanks, done.
Preview Diff
1 | === modified file 'charmhelpers/contrib/network/ip.py' | |||
2 | --- charmhelpers/contrib/network/ip.py 2014-07-24 08:44:12 +0000 | |||
3 | +++ charmhelpers/contrib/network/ip.py 2014-08-06 03:04:25 +0000 | |||
4 | @@ -4,7 +4,7 @@ | |||
5 | 4 | 4 | ||
6 | 5 | from charmhelpers.fetch import apt_install | 5 | from charmhelpers.fetch import apt_install |
7 | 6 | from charmhelpers.core.hookenv import ( | 6 | from charmhelpers.core.hookenv import ( |
9 | 7 | ERROR, log, | 7 | ERROR, log, config, |
10 | 8 | ) | 8 | ) |
11 | 9 | 9 | ||
12 | 10 | try: | 10 | try: |
13 | @@ -154,3 +154,21 @@ | |||
14 | 154 | get_iface_for_address = partial(_get_for_address, key='iface') | 154 | get_iface_for_address = partial(_get_for_address, key='iface') |
15 | 155 | 155 | ||
16 | 156 | get_netmask_for_address = partial(_get_for_address, key='netmask') | 156 | get_netmask_for_address = partial(_get_for_address, key='netmask') |
17 | 157 | |||
18 | 158 | |||
19 | 159 | def get_ipv6_addr(iface="eth0"): | ||
20 | 160 | try: | ||
21 | 161 | iface_addrs = netifaces.ifaddresses(iface) | ||
22 | 162 | if netifaces.AF_INET6 not in iface_addrs: | ||
23 | 163 | raise Exception("Interface '%s' doesn't have an ipv6 address." % iface) | ||
24 | 164 | |||
25 | 165 | addresses = netifaces.ifaddresses(iface)[netifaces.AF_INET6] | ||
26 | 166 | ipv6_addr = [a['addr'] for a in addresses if not a['addr'].startswith('fe80') | ||
27 | 167 | and config('vip') != a['addr']] | ||
28 | 168 | if not ipv6_addr: | ||
29 | 169 | raise Exception("Interface '%s' doesn't have global ipv6 address." % iface) | ||
30 | 170 | |||
31 | 171 | return ipv6_addr[0] | ||
32 | 172 | |||
33 | 173 | except ValueError: | ||
34 | 174 | raise ValueError("Invalid interface '%s'" % iface) | ||
35 | 157 | 175 | ||
36 | === modified file 'charmhelpers/contrib/openstack/context.py' | |||
37 | --- charmhelpers/contrib/openstack/context.py 2014-07-28 11:28:49 +0000 | |||
38 | +++ charmhelpers/contrib/openstack/context.py 2014-08-06 03:04:25 +0000 | |||
39 | @@ -44,7 +44,10 @@ | |||
40 | 44 | neutron_plugin_attribute, | 44 | neutron_plugin_attribute, |
41 | 45 | ) | 45 | ) |
42 | 46 | 46 | ||
44 | 47 | from charmhelpers.contrib.network.ip import get_address_in_network | 47 | from charmhelpers.contrib.network.ip import ( |
45 | 48 | get_address_in_network, | ||
46 | 49 | get_ipv6_addr, | ||
47 | 50 | ) | ||
48 | 48 | 51 | ||
49 | 49 | CA_CERT_PATH = '/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt' | 52 | CA_CERT_PATH = '/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt' |
50 | 50 | 53 | ||
51 | @@ -401,9 +404,12 @@ | |||
52 | 401 | 404 | ||
53 | 402 | cluster_hosts = {} | 405 | cluster_hosts = {} |
54 | 403 | l_unit = local_unit().replace('/', '-') | 406 | l_unit = local_unit().replace('/', '-') |
58 | 404 | cluster_hosts[l_unit] = \ | 407 | if config('prefer-ipv6'): |
59 | 405 | get_address_in_network(config('os-internal-network'), | 408 | addr = get_ipv6_addr() |
60 | 406 | unit_get('private-address')) | 409 | else: |
61 | 410 | addr = unit_get('private-address') | ||
62 | 411 | cluster_hosts[l_unit] = get_address_in_network(config('os-internal-network'), | ||
63 | 412 | addr) | ||
64 | 407 | 413 | ||
65 | 408 | for rid in relation_ids('cluster'): | 414 | for rid in relation_ids('cluster'): |
66 | 409 | for unit in related_units(rid): | 415 | for unit in related_units(rid): |
67 | @@ -414,6 +420,16 @@ | |||
68 | 414 | ctxt = { | 420 | ctxt = { |
69 | 415 | 'units': cluster_hosts, | 421 | 'units': cluster_hosts, |
70 | 416 | } | 422 | } |
71 | 423 | |||
72 | 424 | if config('prefer-ipv6'): | ||
73 | 425 | ctxt['local_host'] = 'ip6-localhost' | ||
74 | 426 | ctxt['haproxy_host'] = '::' | ||
75 | 427 | ctxt['stat_port'] = ':::8888' | ||
76 | 428 | else: | ||
77 | 429 | ctxt['local_host'] = '127.0.0.1' | ||
78 | 430 | ctxt['haproxy_host'] = '0.0.0.0' | ||
79 | 431 | ctxt['stat_port'] = ':8888' | ||
80 | 432 | |||
81 | 417 | if len(cluster_hosts.keys()) > 1: | 433 | if len(cluster_hosts.keys()) > 1: |
82 | 418 | # Enable haproxy when we have enough peers. | 434 | # Enable haproxy when we have enough peers. |
83 | 419 | log('Ensuring haproxy enabled in /etc/default/haproxy.') | 435 | log('Ensuring haproxy enabled in /etc/default/haproxy.') |
84 | 420 | 436 | ||
85 | === modified file 'charmhelpers/contrib/openstack/ip.py' | |||
86 | --- charmhelpers/contrib/openstack/ip.py 2014-07-03 15:15:30 +0000 | |||
87 | +++ charmhelpers/contrib/openstack/ip.py 2014-08-06 03:04:25 +0000 | |||
88 | @@ -7,6 +7,7 @@ | |||
89 | 7 | get_address_in_network, | 7 | get_address_in_network, |
90 | 8 | is_address_in_network, | 8 | is_address_in_network, |
91 | 9 | is_ipv6, | 9 | is_ipv6, |
92 | 10 | get_ipv6_addr, | ||
93 | 10 | ) | 11 | ) |
94 | 11 | 12 | ||
95 | 12 | from charmhelpers.contrib.hahelpers.cluster import is_clustered | 13 | from charmhelpers.contrib.hahelpers.cluster import is_clustered |
96 | @@ -64,10 +65,13 @@ | |||
97 | 64 | vip): | 65 | vip): |
98 | 65 | resolved_address = vip | 66 | resolved_address = vip |
99 | 66 | else: | 67 | else: |
100 | 68 | if config('prefer-ipv6'): | ||
101 | 69 | fallback_addr = get_ipv6_addr() | ||
102 | 70 | else: | ||
103 | 71 | fallback_addr = unit_get(_address_map[endpoint_type]['fallback']) | ||
104 | 67 | resolved_address = get_address_in_network( | 72 | resolved_address = get_address_in_network( |
108 | 68 | config(_address_map[endpoint_type]['config']), | 73 | config(_address_map[endpoint_type]['config']), fallback_addr) |
109 | 69 | unit_get(_address_map[endpoint_type]['fallback']) | 74 | |
107 | 70 | ) | ||
110 | 71 | if resolved_address is None: | 75 | if resolved_address is None: |
111 | 72 | raise ValueError('Unable to resolve a suitable IP address' | 76 | raise ValueError('Unable to resolve a suitable IP address' |
112 | 73 | ' based on charm state and configuration') | 77 | ' based on charm state and configuration') |
113 | 74 | 78 | ||
114 | === modified file 'charmhelpers/contrib/openstack/templates/haproxy.cfg' | |||
115 | --- charmhelpers/contrib/openstack/templates/haproxy.cfg 2014-07-03 12:50:03 +0000 | |||
116 | +++ charmhelpers/contrib/openstack/templates/haproxy.cfg 2014-08-06 03:04:25 +0000 | |||
117 | @@ -1,6 +1,6 @@ | |||
118 | 1 | global | 1 | global |
121 | 2 | log 127.0.0.1 local0 | 2 | log {{ local_host }} local0 |
122 | 3 | log 127.0.0.1 local1 notice | 3 | log {{ local_host }} local1 notice |
123 | 4 | maxconn 20000 | 4 | maxconn 20000 |
124 | 5 | user haproxy | 5 | user haproxy |
125 | 6 | group haproxy | 6 | group haproxy |
126 | @@ -17,7 +17,7 @@ | |||
127 | 17 | timeout client 30000 | 17 | timeout client 30000 |
128 | 18 | timeout server 30000 | 18 | timeout server 30000 |
129 | 19 | 19 | ||
131 | 20 | listen stats :8888 | 20 | listen stats {{ stat_port }} |
132 | 21 | mode http | 21 | mode http |
133 | 22 | stats enable | 22 | stats enable |
134 | 23 | stats hide-version | 23 | stats hide-version |
135 | 24 | 24 | ||
136 | === modified file 'tests/contrib/network/test_ip.py' | |||
137 | --- tests/contrib/network/test_ip.py 2014-07-24 08:29:56 +0000 | |||
138 | +++ tests/contrib/network/test_ip.py 2014-08-06 03:04:25 +0000 | |||
139 | @@ -158,4 +158,50 @@ | |||
140 | 158 | def test_is_ipv6(self): | 158 | def test_is_ipv6(self): |
141 | 159 | self.assertFalse(net_ip.is_ipv6('myhost')) | 159 | self.assertFalse(net_ip.is_ipv6('myhost')) |
142 | 160 | self.assertFalse(net_ip.is_ipv6('172.4.5.5')) | 160 | self.assertFalse(net_ip.is_ipv6('172.4.5.5')) |
143 | 161 | self.assertTrue(net_ip.is_ipv6('2a01:348:2f4:0:685e:5748:ae62:209f')) | ||
144 | 162 | \ No newline at end of file | 161 | \ No newline at end of file |
145 | 162 | self.assertTrue(net_ip.is_ipv6('2a01:348:2f4:0:685e:5748:ae62:209f')) | ||
146 | 163 | |||
147 | 164 | @patch.object(netifaces, 'ifaddresses') | ||
148 | 165 | def test_get_ipv6_addr_no_ipv6(self, _ifaddresses): | ||
149 | 166 | DUMMY_ADDRESSES = { | ||
150 | 167 | 'eth0': { | ||
151 | 168 | 2: [{'addr': '192.168.1.55', | ||
152 | 169 | 'broadcast': '192.168.1.255', | ||
153 | 170 | 'netmask': '255.255.255.0'}] | ||
154 | 171 | } | ||
155 | 172 | } | ||
156 | 173 | |||
157 | 174 | def mock_ifaddresses(iface): | ||
158 | 175 | return DUMMY_ADDRESSES[iface] | ||
159 | 176 | |||
160 | 177 | _ifaddresses.side_effect = mock_ifaddresses | ||
161 | 178 | self.assertRaises(Exception, net_ip.get_ipv6_addr) | ||
162 | 179 | |||
163 | 180 | @patch.object(netifaces, 'ifaddresses') | ||
164 | 181 | def test_get_ipv6_addr_no_global_ipv6(self, _ifaddresses): | ||
165 | 182 | DUMMY_ADDRESSES = { | ||
166 | 183 | 'eth0': { | ||
167 | 184 | 10: [{'addr': 'fe80::3e97:eff:fe8b:1cf7%eth0', | ||
168 | 185 | 'netmask': 'ffff:ffff:ffff:ffff::'}], | ||
169 | 186 | } | ||
170 | 187 | } | ||
171 | 188 | |||
172 | 189 | def mock_ifaddresses(iface): | ||
173 | 190 | return DUMMY_ADDRESSES[iface] | ||
174 | 191 | |||
175 | 192 | _ifaddresses.side_effect = mock_ifaddresses | ||
176 | 193 | self.assertRaises(Exception, net_ip.get_ipv6_addr) | ||
177 | 194 | |||
178 | 195 | @patch.object(netifaces, 'ifaddresses') | ||
179 | 196 | def test_get_ipv6_addr_invalid_nic(self, _ifaddresses): | ||
180 | 197 | DUMMY_ADDRESSES = { | ||
181 | 198 | 'eth0': { | ||
182 | 199 | 10: [{'addr': 'fe80::3e97:eff:fe8b:1cf7%eth0', | ||
183 | 200 | 'netmask': 'ffff:ffff:ffff:ffff::'}], | ||
184 | 201 | } | ||
185 | 202 | } | ||
186 | 203 | |||
187 | 204 | def mock_ifaddresses(iface): | ||
188 | 205 | return DUMMY_ADDRESSES[iface] | ||
189 | 206 | |||
190 | 207 | _ifaddresses.side_effect = ValueError() | ||
191 | 208 | self.assertRaises(ValueError, net_ip.get_ipv6_addr, 'eth1') | ||
192 | 163 | 209 | ||
193 | === modified file 'tests/contrib/openstack/test_os_contexts.py' | |||
194 | --- tests/contrib/openstack/test_os_contexts.py 2014-07-28 11:28:49 +0000 | |||
195 | +++ tests/contrib/openstack/test_os_contexts.py 2014-08-06 03:04:25 +0000 | |||
196 | @@ -315,7 +315,8 @@ | |||
197 | 315 | 'time', | 315 | 'time', |
198 | 316 | 'https', | 316 | 'https', |
199 | 317 | 'get_address_in_network', | 317 | 'get_address_in_network', |
201 | 318 | 'local_unit' | 318 | 'local_unit', |
202 | 319 | 'get_ipv6_addr' | ||
203 | 319 | ] | 320 | ] |
204 | 320 | 321 | ||
205 | 321 | 322 | ||
206 | @@ -835,6 +836,52 @@ | |||
207 | 835 | self.relation_get.side_effect = relation.get | 836 | self.relation_get.side_effect = relation.get |
208 | 836 | self.related_units.side_effect = relation.relation_units | 837 | self.related_units.side_effect = relation.relation_units |
209 | 837 | self.get_address_in_network.return_value = 'cluster-peer0.localnet' | 838 | self.get_address_in_network.return_value = 'cluster-peer0.localnet' |
210 | 839 | self.config.return_value = False | ||
211 | 840 | haproxy = context.HAProxyContext() | ||
212 | 841 | with patch_open() as (_open, _file): | ||
213 | 842 | result = haproxy() | ||
214 | 843 | ex = { | ||
215 | 844 | 'units': { | ||
216 | 845 | 'peer-0': 'cluster-peer0.localnet', | ||
217 | 846 | 'peer-1': 'cluster-peer1.localnet', | ||
218 | 847 | 'peer-2': 'cluster-peer2.localnet', | ||
219 | 848 | }, | ||
220 | 849 | |||
221 | 850 | 'local_host': '127.0.0.1', | ||
222 | 851 | 'haproxy_host': '0.0.0.0', | ||
223 | 852 | 'stat_port': ':8888', | ||
224 | 853 | } | ||
225 | 854 | # the context gets generated. | ||
226 | 855 | self.assertEquals(ex, result) | ||
227 | 856 | # and /etc/default/haproxy is updated. | ||
228 | 857 | self.assertEquals(_file.write.call_args_list, | ||
229 | 858 | [call('ENABLED=1\n')]) | ||
230 | 859 | |||
231 | 860 | @patch('charmhelpers.contrib.openstack.context.unit_get') | ||
232 | 861 | @patch('charmhelpers.contrib.openstack.context.local_unit') | ||
233 | 862 | @patch('charmhelpers.contrib.openstack.context.get_ipv6_addr') | ||
234 | 863 | def test_haproxy_context_with_data_ipv6( | ||
235 | 864 | self, local_unit, unit_get, get_ipv6_addr): | ||
236 | 865 | '''Test haproxy context with all relation data''' | ||
237 | 866 | cluster_relation = { | ||
238 | 867 | 'cluster:0': { | ||
239 | 868 | 'peer/1': { | ||
240 | 869 | 'private-address': 'cluster-peer1.localnet', | ||
241 | 870 | }, | ||
242 | 871 | 'peer/2': { | ||
243 | 872 | 'private-address': 'cluster-peer2.localnet', | ||
244 | 873 | }, | ||
245 | 874 | }, | ||
246 | 875 | } | ||
247 | 876 | |||
248 | 877 | unit_get.return_value = 'peer/0' | ||
249 | 878 | relation = FakeRelation(cluster_relation) | ||
250 | 879 | self.relation_ids.side_effect = relation.relation_ids | ||
251 | 880 | self.relation_get.side_effect = relation.get | ||
252 | 881 | self.related_units.side_effect = relation.relation_units | ||
253 | 882 | self.get_address_in_network.return_value = 'cluster-peer0.localnet' | ||
254 | 883 | self.get_ipv6_addr.return_value = 'cluster-peer0.localnet' | ||
255 | 884 | self.config.side_effect = [True, None, True] | ||
256 | 838 | haproxy = context.HAProxyContext() | 885 | haproxy = context.HAProxyContext() |
257 | 839 | with patch_open() as (_open, _file): | 886 | with patch_open() as (_open, _file): |
258 | 840 | result = haproxy() | 887 | result = haproxy() |
259 | @@ -843,7 +890,11 @@ | |||
260 | 843 | 'peer-0': 'cluster-peer0.localnet', | 890 | 'peer-0': 'cluster-peer0.localnet', |
261 | 844 | 'peer-1': 'cluster-peer1.localnet', | 891 | 'peer-1': 'cluster-peer1.localnet', |
262 | 845 | 'peer-2': 'cluster-peer2.localnet' | 892 | 'peer-2': 'cluster-peer2.localnet' |
264 | 846 | } | 893 | }, |
265 | 894 | |||
266 | 895 | 'local_host': 'ip6-localhost', | ||
267 | 896 | 'haproxy_host': '::', | ||
268 | 897 | 'stat_port': ':::8888', | ||
269 | 847 | } | 898 | } |
270 | 848 | # the context gets generated. | 899 | # the context gets generated. |
271 | 849 | self.assertEquals(ex, result) | 900 | self.assertEquals(ex, result) |
272 | @@ -876,6 +927,7 @@ | |||
273 | 876 | self.relation_ids.side_effect = relation.relation_ids | 927 | self.relation_ids.side_effect = relation.relation_ids |
274 | 877 | self.relation_get.side_effect = relation.get | 928 | self.relation_get.side_effect = relation.get |
275 | 878 | self.related_units.side_effect = relation.relation_units | 929 | self.related_units.side_effect = relation.relation_units |
276 | 930 | self.config.return_value = False | ||
277 | 879 | haproxy = context.HAProxyContext() | 931 | haproxy = context.HAProxyContext() |
278 | 880 | self.assertEquals({}, haproxy()) | 932 | self.assertEquals({}, haproxy()) |
279 | 881 | 933 |
Need to fx merge conflict.