Merge lp:~thedac/charm-helpers/get-relation-ip into lp:charm-helpers

Proposed by David Ames
Status: Merged
Merged at revision: 709
Proposed branch: lp:~thedac/charm-helpers/get-relation-ip
Merge into: lp:charm-helpers
Diff against target: 134 lines (+105/-1)
2 files modified
charmhelpers/contrib/network/ip.py (+44/-1)
tests/contrib/network/test_ip.py (+61/-0)
To merge this branch: bzr merge lp:~thedac/charm-helpers/get-relation-ip
Reviewer Review Type Date Requested Status
James Page Approve
Review via email: mp+319143@code.launchpad.net

Description of the change

Add network space aware get_relation_ip

Check network-get --primary-address $RELATION unless overridden

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'charmhelpers/contrib/network/ip.py'
2--- charmhelpers/contrib/network/ip.py 2017-02-16 03:04:17 +0000
3+++ charmhelpers/contrib/network/ip.py 2017-03-06 23:53:30 +0000
4@@ -20,13 +20,19 @@
5
6 from functools import partial
7
8-from charmhelpers.core.hookenv import unit_get
9 from charmhelpers.fetch import apt_install, apt_update
10 from charmhelpers.core.hookenv import (
11+ config,
12 log,
13+ network_get_primary_address,
14+ unit_get,
15 WARNING,
16 )
17
18+from charmhelpers.core.host import (
19+ lsb_release,
20+)
21+
22 try:
23 import netifaces
24 except ImportError:
25@@ -511,3 +517,40 @@
26 cmd = ['nc', '-z', address, str(port)]
27 result = subprocess.call(cmd)
28 return not(bool(result))
29+
30+
31+def assert_charm_supports_ipv6():
32+ """Check whether we are able to support charms ipv6."""
33+ if lsb_release()['DISTRIB_CODENAME'].lower() < "trusty":
34+ raise Exception("IPv6 is not supported in the charms for Ubuntu "
35+ "versions less than Trusty 14.04")
36+
37+
38+def get_relation_ip(interface, config_override=None):
39+ """Return this unit's IP for the given relation.
40+
41+ Allow for an arbitrary interface to use with network-get to select an IP.
42+ Handle all address selection options including configuration parameter
43+ override and IPv6.
44+
45+ Usage: get_relation_ip('amqp', config_override='access-network')
46+
47+ @param interface: string name of the relation.
48+ @param config_override: string name of the config option for network
49+ override. Supports legacy network override configuration parameters.
50+ @raises Exception if prefer-ipv6 is configured but IPv6 unsupported.
51+ @returns IPv6 or IPv4 address
52+ """
53+
54+ fallback = get_host_ip(unit_get('private-address'))
55+ if config('prefer-ipv6'):
56+ assert_charm_supports_ipv6()
57+ return get_ipv6_addr()[0]
58+ elif config_override and config(config_override):
59+ return get_address_in_network(config(config_override),
60+ fallback)
61+ else:
62+ try:
63+ return network_get_primary_address(interface)
64+ except NotImplementedError:
65+ return fallback
66
67=== modified file 'tests/contrib/network/test_ip.py'
68--- tests/contrib/network/test_ip.py 2017-02-16 03:04:17 +0000
69+++ tests/contrib/network/test_ip.py 2017-03-06 23:53:30 +0000
70@@ -749,3 +749,64 @@
71 subprocess_call.return_value = 0
72 self.assertEqual(net_ip.port_has_listener('ip-address', 70), True)
73 subprocess_call.assert_called_with(['nc', '-z', 'ip-address', '70'])
74+
75+ @patch.object(net_ip, 'config')
76+ @patch.object(net_ip, 'network_get_primary_address')
77+ @patch.object(net_ip, 'get_address_in_network')
78+ @patch.object(net_ip, 'unit_get')
79+ @patch.object(net_ip, 'get_ipv6_addr')
80+ @patch.object(net_ip, 'assert_charm_supports_ipv6')
81+ def test_get_relation_ip(self, assert_charm_supports_ipv6, get_ipv6_addr,
82+ unit_get, get_address_in_network,
83+ network_get_primary_address, config):
84+ AMQP_IP = '10.200.1.1'
85+ OVERRIDE_AMQP_IP = '10.250.1.1'
86+ CLUSTER_IP = '10.100.1.1'
87+ OVERRIDE_CLUSTER_IP = '10.150.1.1'
88+ IPV6_IP = '2001:DB8::1'
89+ DEFAULT_IP = '172.16.1.1'
90+ assert_charm_supports_ipv6.return_value = True
91+ get_ipv6_addr.return_value = [IPV6_IP]
92+ unit_get.return_value = DEFAULT_IP
93+ get_address_in_network.return_value = DEFAULT_IP
94+ network_get_primary_address.return_value = DEFAULT_IP
95+
96+ # IPv6
97+ _config = {'prefer-ipv6': True,
98+ 'cluster-network': '10.100.1.0/24',
99+ 'access-network': '10.200.1.0/24'}
100+ config.side_effect = lambda key: _config.get(key)
101+ self.assertEqual(IPV6_IP, net_ip.get_relation_ip('amqp'))
102+
103+ # Overrides
104+ _config = {'prefer-ipv6': False,
105+ 'cluster-network': '10.100.1.0/24',
106+ 'access-network': '10.200.1.0/24'}
107+ config.side_effect = lambda key: _config.get(key)
108+
109+ get_address_in_network.return_value = OVERRIDE_AMQP_IP
110+ self.assertEqual(
111+ OVERRIDE_AMQP_IP,
112+ net_ip.get_relation_ip('amqp',
113+ config_override='access-network'))
114+
115+ get_address_in_network.return_value = OVERRIDE_CLUSTER_IP
116+ self.assertEqual(OVERRIDE_CLUSTER_IP,
117+ net_ip.get_relation_ip(
118+ 'cluster',
119+ config_override='cluster-network'))
120+
121+ # Network-get calls
122+ _config = {'prefer-ipv6': False,
123+ 'cluster-network': None,
124+ 'access-network': None}
125+ config.side_effect = lambda key: _config.get(key)
126+
127+ network_get_primary_address.return_value = AMQP_IP
128+ self.assertEqual(AMQP_IP, net_ip.get_relation_ip('amqp'))
129+
130+ network_get_primary_address.return_value = CLUSTER_IP
131+ self.assertEqual(CLUSTER_IP,
132+ net_ip.get_relation_ip(
133+ config_override='cluster-network',
134+ interface='cluster'))

Subscribers

People subscribed via source and target branches