Merge lp:~billy-olsen/charm-helpers/better-address-endpoint-overrides into lp:charm-helpers

Proposed by Billy Olsen
Status: Merged
Merged at revision: 383
Proposed branch: lp:~billy-olsen/charm-helpers/better-address-endpoint-overrides
Merge into: lp:charm-helpers
Diff against target: 224 lines (+75/-73)
2 files modified
charmhelpers/contrib/openstack/ip.py (+49/-44)
tests/contrib/openstack/test_ip.py (+26/-29)
To merge this branch: bzr merge lp:~billy-olsen/charm-helpers/better-address-endpoint-overrides
Reviewer Review Type Date Requested Status
Jorge Niedbalski (community) Approve
Felipe Reyes Pending
charmers Pending
Edward Hope-Morley Pending
Review via email: mp+261000@code.launchpad.net

This proposal supersedes a proposal from 2015-05-29.

To post a comment you must log in.
387. By Billy Olsen

Add templating to the os-public-hostname override per jjo's bug comment.

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

Thanks billy for the proposal.

I think this approach is much simpler, +1 from my side.

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

The jinja package requires to be installed on the system, in case of partial importing of this helper, this will not work. Please see: charmhelpers.core.templating. I

This could be replaced by a standard string replacement. see pydoc format.

Thanks billy.

review: Needs Fixing
388. By Billy Olsen

Per niedbalski's review remove jinja2 dependency and use simple string
formatting. Additionally break out the override check into its own
function.

Revision history for this message
Billy Olsen (billy-olsen) :
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
=== modified file 'charmhelpers/contrib/openstack/ip.py'
--- charmhelpers/contrib/openstack/ip.py 2015-02-12 22:30:09 +0000
+++ charmhelpers/contrib/openstack/ip.py 2015-06-04 22:17:24 +0000
@@ -17,6 +17,7 @@
17from charmhelpers.core.hookenv import (17from charmhelpers.core.hookenv import (
18 config,18 config,
19 unit_get,19 unit_get,
20 service_name,
20)21)
21from charmhelpers.contrib.network.ip import (22from charmhelpers.contrib.network.ip import (
22 get_address_in_network,23 get_address_in_network,
@@ -26,8 +27,6 @@
26)27)
27from charmhelpers.contrib.hahelpers.cluster import is_clustered28from charmhelpers.contrib.hahelpers.cluster import is_clustered
2829
29from functools import partial
30
31PUBLIC = 'public'30PUBLIC = 'public'
32INTERNAL = 'int'31INTERNAL = 'int'
33ADMIN = 'admin'32ADMIN = 'admin'
@@ -35,15 +34,18 @@
35ADDRESS_MAP = {34ADDRESS_MAP = {
36 PUBLIC: {35 PUBLIC: {
37 'config': 'os-public-network',36 'config': 'os-public-network',
38 'fallback': 'public-address'37 'fallback': 'public-address',
38 'override': 'os-public-hostname',
39 },39 },
40 INTERNAL: {40 INTERNAL: {
41 'config': 'os-internal-network',41 'config': 'os-internal-network',
42 'fallback': 'private-address'42 'fallback': 'private-address',
43 'override': 'os-internal-hostname',
43 },44 },
44 ADMIN: {45 ADMIN: {
45 'config': 'os-admin-network',46 'config': 'os-admin-network',
46 'fallback': 'private-address'47 'fallback': 'private-address',
48 'override': 'os-admin-hostname',
47 }49 }
48}50}
4951
@@ -57,15 +59,50 @@
57 :param endpoint_type: str endpoint type to resolve.59 :param endpoint_type: str endpoint type to resolve.
58 :param returns: str base URL for services on the current service unit.60 :param returns: str base URL for services on the current service unit.
59 """61 """
60 scheme = 'http'62 scheme = _get_scheme(configs)
61 if 'https' in configs.complete_contexts():63
62 scheme = 'https'
63 address = resolve_address(endpoint_type)64 address = resolve_address(endpoint_type)
64 if is_ipv6(address):65 if is_ipv6(address):
65 address = "[{}]".format(address)66 address = "[{}]".format(address)
67
66 return '%s://%s' % (scheme, address)68 return '%s://%s' % (scheme, address)
6769
6870
71def _get_scheme(configs):
72 """Returns the scheme to use for the url (either http or https)
73 depending upon whether https is in the configs value.
74
75 :param configs: OSTemplateRenderer config templating object to inspect
76 for a complete https context.
77 :returns: either 'http' or 'https' depending on whether https is
78 configured within the configs context.
79 """
80 scheme = 'http'
81 if configs and 'https' in configs.complete_contexts():
82 scheme = 'https'
83 return scheme
84
85
86def _get_address_override(endpoint_type=PUBLIC):
87 """Returns any address overrides that the user has defined based on the
88 endpoint type.
89
90 Note: this function allows for the service name to be inserted into the
91 address if the user specifies {service_name}.somehost.org.
92
93 :param endpoint_type: the type of endpoint to retrieve the override
94 value for.
95 :returns: any endpoint address or hostname that the user has overridden
96 or None if an override is not present.
97 """
98 override_key = ADDRESS_MAP[endpoint_type]['override']
99 addr_override = config(override_key)
100 if not addr_override:
101 return None
102 else:
103 return addr_override.format(service_name=service_name())
104
105
69def resolve_address(endpoint_type=PUBLIC):106def resolve_address(endpoint_type=PUBLIC):
70 """Return unit address depending on net config.107 """Return unit address depending on net config.
71108
@@ -77,7 +114,10 @@
77114
78 :param endpoint_type: Network endpoing type115 :param endpoint_type: Network endpoing type
79 """116 """
80 resolved_address = None117 resolved_address = _get_address_override(endpoint_type)
118 if resolved_address:
119 return resolved_address
120
81 vips = config('vip')121 vips = config('vip')
82 if vips:122 if vips:
83 vips = vips.split()123 vips = vips.split()
@@ -109,38 +149,3 @@
109 "clustered=%s)" % (net_type, clustered))149 "clustered=%s)" % (net_type, clustered))
110150
111 return resolved_address151 return resolved_address
112
113
114def endpoint_url(configs, url_template, port, endpoint_type=PUBLIC,
115 override=None):
116 """Returns the correct endpoint URL to advertise to Keystone.
117
118 This method provides the correct endpoint URL which should be advertised to
119 the keystone charm for endpoint creation. This method allows for the url to
120 be overridden to force a keystone endpoint to have specific URL for any of
121 the defined scopes (admin, internal, public).
122
123 :param configs: OSTemplateRenderer config templating object to inspect
124 for a complete https context.
125 :param url_template: str format string for creating the url template. Only
126 two values will be passed - the scheme+hostname
127 returned by the canonical_url and the port.
128 :param endpoint_type: str endpoint type to resolve.
129 :param override: str the name of the config option which overrides the
130 endpoint URL defined by the charm itself. None will
131 disable any overrides (default).
132 """
133 if override:
134 # Return any user-defined overrides for the keystone endpoint URL.
135 user_value = config(override)
136 if user_value:
137 return user_value.strip()
138
139 return url_template % (canonical_url(configs, endpoint_type), port)
140
141
142public_endpoint = partial(endpoint_url, endpoint_type=PUBLIC)
143
144internal_endpoint = partial(endpoint_url, endpoint_type=INTERNAL)
145
146admin_endpoint = partial(endpoint_url, endpoint_type=ADMIN)
147152
=== modified file 'tests/contrib/openstack/test_ip.py'
--- tests/contrib/openstack/test_ip.py 2015-02-12 22:30:09 +0000
+++ tests/contrib/openstack/test_ip.py 2015-06-04 22:17:24 +0000
@@ -7,7 +7,8 @@
7 'config',7 'config',
8 'unit_get',8 'unit_get',
9 'get_address_in_network',9 'get_address_in_network',
10 'is_clustered'10 'is_clustered',
11 'service_name',
11]12]
1213
1314
@@ -94,6 +95,25 @@
94 self.test_config.set('vip', '10.5.3.1')95 self.test_config.set('vip', '10.5.3.1')
95 self.assertRaises(ValueError, ip.resolve_address)96 self.assertRaises(ValueError, ip.resolve_address)
9697
98 def test_resolve_address_override(self):
99 self.test_config.set('os-public-hostname', 'public.example.com')
100 addr = ip.resolve_address()
101 self.assertEqual('public.example.com', addr)
102
103 def test_resolve_address_override_template(self):
104 self.test_config.set('os-public-hostname',
105 '{service_name}.example.com')
106 self.service_name.return_value = 'foo'
107 addr = ip.resolve_address()
108 self.assertEqual('foo.example.com', addr)
109
110 @patch.object(ip, 'get_ipv6_addr', lambda *args, **kwargs: ['::1'])
111 def test_resolve_address_ipv6_fallback(self):
112 self.test_config.set('prefer-ipv6', True)
113 self.is_clustered.return_value = False
114 ip.resolve_address()
115 self.get_address_in_network.assert_called_with(None, '::1')
116
97 @patch.object(ip, 'resolve_address')117 @patch.object(ip, 'resolve_address')
98 def test_canonical_url_http(self, resolve_address):118 def test_canonical_url_http(self, resolve_address):
99 resolve_address.return_value = 'unit1'119 resolve_address.return_value = 'unit1'
@@ -110,31 +130,8 @@
110 self.assertTrue(ip.canonical_url(configs),130 self.assertTrue(ip.canonical_url(configs),
111 'https://unit1')131 'https://unit1')
112132
113 def test_endpoint_url(self):133 @patch.object(ip, 'is_ipv6', lambda *args: True)
114 exp_url = 'https://public.example.com'134 @patch.object(ip, 'resolve_address')
115 self.test_config.set('public-url', exp_url)135 def test_canonical_url_ipv6(self, resolve_address):
116 configs = MagicMock()136 resolve_address.return_value = 'unit1'
117 configs.complete_contexts.return_value = ['https']137 self.assertTrue(ip.canonical_url(None), 'http://[unit1]')
118 endpoint = ip.endpoint_url(configs, '%s:%s', 443, ip.PUBLIC,
119 'public-url')
120 self.assertEqual(exp_url, endpoint)
121
122 @patch.object(ip, 'resolve_address')
123 def test_endpoint_url_no_override(self, resolve_address):
124 resolve_address.return_value = 'unit1'
125 configs = MagicMock()
126 configs.complete_contexts.return_value = ['https']
127 endpoint = ip.endpoint_url(configs, '%s:%s/v1/AUTH_$(tenant_id)s', 443,
128 ip.INTERNAL, 'internal-url')
129 self.assertEqual('https://unit1:443/v1/AUTH_$(tenant_id)s', endpoint)
130
131 @patch.object(ip, 'resolve_address')
132 @patch.object(ip, 'is_ipv6')
133 def test_endpoint_url_no_override_ipv6(self, is_ipv6, resolve_address):
134 resolve_address.return_value = 'unit1'
135 is_ipv6.return_value = True
136 configs = MagicMock()
137 configs.complete_contexts.return_value = ['https']
138 endpoint = ip.endpoint_url(configs, '%s:%s', 443,
139 ip.ADMIN, 'admin-url')
140 self.assertEquals('https://[unit1]:443', endpoint)

Subscribers

People subscribed via source and target branches