Merge lp:~billy-olsen/charms/trusty/glance/backport-lp1398182 into lp:~openstack-charmers-archive/charms/trusty/glance/trunk

Proposed by Billy Olsen
Status: Merged
Merged at revision: 119
Proposed branch: lp:~billy-olsen/charms/trusty/glance/backport-lp1398182
Merge into: lp:~openstack-charmers-archive/charms/trusty/glance/trunk
Diff against target: 386 lines (+132/-59)
4 files modified
config.yaml (+12/-0)
hooks/charmhelpers/contrib/hahelpers/cluster.py (+25/-0)
hooks/charmhelpers/contrib/openstack/ip.py (+49/-44)
unit_tests/test_glance_relations.py (+46/-15)
To merge this branch: bzr merge lp:~billy-olsen/charms/trusty/glance/backport-lp1398182
Reviewer Review Type Date Requested Status
Corey Bryant Approve
Review via email: mp+262002@code.launchpad.net
To post a comment you must log in.
Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_lint_check #5405 glance for billy-olsen mp262002
    LINT OK: passed

Build: http://10.245.162.77:8080/job/charm_lint_check/5405/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_unit_test #5037 glance for billy-olsen mp262002
    UNIT OK: passed

Build: http://10.245.162.77:8080/job/charm_unit_test/5037/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_amulet_test #4648 glance for billy-olsen mp262002
    AMULET OK: passed

Build: http://10.245.162.77:8080/job/charm_amulet_test/4648/

Revision history for this message
Corey Bryant (corey.bryant) :
review: Approve
120. By Billy Olsen

Official c-h stable sync

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_lint_check #5463 glance for billy-olsen mp262002
    LINT OK: passed

Build: http://10.245.162.77:8080/job/charm_lint_check/5463/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_unit_test #5095 glance for billy-olsen mp262002
    UNIT OK: passed

Build: http://10.245.162.77:8080/job/charm_unit_test/5095/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_amulet_test #4667 glance for billy-olsen mp262002
    AMULET FAIL: amulet-test failed

AMULET Results (max last 2 lines):
make: *** [test] Error 124
ERROR:root:Make target returned non-zero.

Full amulet test output: http://paste.ubuntu.com/11738009/
Build: http://10.245.162.77:8080/job/charm_amulet_test/4667/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_amulet_test #4678 glance for billy-olsen mp262002
    AMULET OK: passed

Build: http://10.245.162.77:8080/job/charm_amulet_test/4678/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'config.yaml'
2--- config.yaml 2015-04-01 16:48:59 +0000
3+++ config.yaml 2015-06-18 23:26:56 +0000
4@@ -176,6 +176,18 @@
5 192.168.0.0/24)
6 .
7 This network will be used for public endpoints.
8+ os-public-hostname:
9+ type: string
10+ default:
11+ description: |
12+ The hostname or address of the public endpoints created for glance
13+ in the keystone identity provider.
14+ .
15+ This value will be used for public endpoints. For example, an
16+ os-public-hostname set to 'glance.example.com' with ssl enabled will
17+ create a public endpoint for glance of:
18+ .
19+ https://glance.example.com:9292/
20 prefer-ipv6:
21 type: boolean
22 default: False
23
24=== modified file 'hooks/charmhelpers/contrib/hahelpers/cluster.py'
25--- hooks/charmhelpers/contrib/hahelpers/cluster.py 2015-03-20 17:15:02 +0000
26+++ hooks/charmhelpers/contrib/hahelpers/cluster.py 2015-06-18 23:26:56 +0000
27@@ -52,6 +52,8 @@
28 bool_from_string,
29 )
30
31+DC_RESOURCE_NAME = 'DC'
32+
33
34 class HAIncompleteConfig(Exception):
35 pass
36@@ -95,6 +97,27 @@
37 return False
38
39
40+def is_crm_dc():
41+ """
42+ Determine leadership by querying the pacemaker Designated Controller
43+ """
44+ cmd = ['crm', 'status']
45+ try:
46+ status = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
47+ if not isinstance(status, six.text_type):
48+ status = six.text_type(status, "utf-8")
49+ except subprocess.CalledProcessError:
50+ return False
51+ current_dc = ''
52+ for line in status.split('\n'):
53+ if line.startswith('Current DC'):
54+ # Current DC: juju-lytrusty-machine-2 (168108163) - partition with quorum
55+ current_dc = line.split(':')[1].split()[0]
56+ if current_dc == get_unit_hostname():
57+ return True
58+ return False
59+
60+
61 @retry_on_exception(5, base_delay=2, exc_type=CRMResourceNotFound)
62 def is_crm_leader(resource, retry=False):
63 """
64@@ -104,6 +127,8 @@
65 We allow this operation to be retried to avoid the possibility of getting a
66 false negative. See LP #1396246 for more info.
67 """
68+ if resource == DC_RESOURCE_NAME:
69+ return is_crm_dc()
70 cmd = ['crm', 'resource', 'show', resource]
71 try:
72 status = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
73
74=== modified file 'hooks/charmhelpers/contrib/openstack/ip.py'
75--- hooks/charmhelpers/contrib/openstack/ip.py 2015-03-20 17:15:02 +0000
76+++ hooks/charmhelpers/contrib/openstack/ip.py 2015-06-18 23:26:56 +0000
77@@ -17,6 +17,7 @@
78 from charmhelpers.core.hookenv import (
79 config,
80 unit_get,
81+ service_name,
82 )
83 from charmhelpers.contrib.network.ip import (
84 get_address_in_network,
85@@ -26,8 +27,6 @@
86 )
87 from charmhelpers.contrib.hahelpers.cluster import is_clustered
88
89-from functools import partial
90-
91 PUBLIC = 'public'
92 INTERNAL = 'int'
93 ADMIN = 'admin'
94@@ -35,15 +34,18 @@
95 ADDRESS_MAP = {
96 PUBLIC: {
97 'config': 'os-public-network',
98- 'fallback': 'public-address'
99+ 'fallback': 'public-address',
100+ 'override': 'os-public-hostname',
101 },
102 INTERNAL: {
103 'config': 'os-internal-network',
104- 'fallback': 'private-address'
105+ 'fallback': 'private-address',
106+ 'override': 'os-internal-hostname',
107 },
108 ADMIN: {
109 'config': 'os-admin-network',
110- 'fallback': 'private-address'
111+ 'fallback': 'private-address',
112+ 'override': 'os-admin-hostname',
113 }
114 }
115
116@@ -57,15 +59,50 @@
117 :param endpoint_type: str endpoint type to resolve.
118 :param returns: str base URL for services on the current service unit.
119 """
120- scheme = 'http'
121- if 'https' in configs.complete_contexts():
122- scheme = 'https'
123+ scheme = _get_scheme(configs)
124+
125 address = resolve_address(endpoint_type)
126 if is_ipv6(address):
127 address = "[{}]".format(address)
128+
129 return '%s://%s' % (scheme, address)
130
131
132+def _get_scheme(configs):
133+ """Returns the scheme to use for the url (either http or https)
134+ depending upon whether https is in the configs value.
135+
136+ :param configs: OSTemplateRenderer config templating object to inspect
137+ for a complete https context.
138+ :returns: either 'http' or 'https' depending on whether https is
139+ configured within the configs context.
140+ """
141+ scheme = 'http'
142+ if configs and 'https' in configs.complete_contexts():
143+ scheme = 'https'
144+ return scheme
145+
146+
147+def _get_address_override(endpoint_type=PUBLIC):
148+ """Returns any address overrides that the user has defined based on the
149+ endpoint type.
150+
151+ Note: this function allows for the service name to be inserted into the
152+ address if the user specifies {service_name}.somehost.org.
153+
154+ :param endpoint_type: the type of endpoint to retrieve the override
155+ value for.
156+ :returns: any endpoint address or hostname that the user has overridden
157+ or None if an override is not present.
158+ """
159+ override_key = ADDRESS_MAP[endpoint_type]['override']
160+ addr_override = config(override_key)
161+ if not addr_override:
162+ return None
163+ else:
164+ return addr_override.format(service_name=service_name())
165+
166+
167 def resolve_address(endpoint_type=PUBLIC):
168 """Return unit address depending on net config.
169
170@@ -77,7 +114,10 @@
171
172 :param endpoint_type: Network endpoing type
173 """
174- resolved_address = None
175+ resolved_address = _get_address_override(endpoint_type)
176+ if resolved_address:
177+ return resolved_address
178+
179 vips = config('vip')
180 if vips:
181 vips = vips.split()
182@@ -109,38 +149,3 @@
183 "clustered=%s)" % (net_type, clustered))
184
185 return resolved_address
186-
187-
188-def endpoint_url(configs, url_template, port, endpoint_type=PUBLIC,
189- override=None):
190- """Returns the correct endpoint URL to advertise to Keystone.
191-
192- This method provides the correct endpoint URL which should be advertised to
193- the keystone charm for endpoint creation. This method allows for the url to
194- be overridden to force a keystone endpoint to have specific URL for any of
195- the defined scopes (admin, internal, public).
196-
197- :param configs: OSTemplateRenderer config templating object to inspect
198- for a complete https context.
199- :param url_template: str format string for creating the url template. Only
200- two values will be passed - the scheme+hostname
201- returned by the canonical_url and the port.
202- :param endpoint_type: str endpoint type to resolve.
203- :param override: str the name of the config option which overrides the
204- endpoint URL defined by the charm itself. None will
205- disable any overrides (default).
206- """
207- if override:
208- # Return any user-defined overrides for the keystone endpoint URL.
209- user_value = config(override)
210- if user_value:
211- return user_value.strip()
212-
213- return url_template % (canonical_url(configs, endpoint_type), port)
214-
215-
216-public_endpoint = partial(endpoint_url, endpoint_type=PUBLIC)
217-
218-internal_endpoint = partial(endpoint_url, endpoint_type=INTERNAL)
219-
220-admin_endpoint = partial(endpoint_url, endpoint_type=ADMIN)
221
222=== modified file 'unit_tests/test_glance_relations.py'
223--- unit_tests/test_glance_relations.py 2015-04-21 15:33:15 +0000
224+++ unit_tests/test_glance_relations.py 2015-06-18 23:26:56 +0000
225@@ -24,7 +24,6 @@
226 TO_PATCH = [
227 # charmhelpers.core.hookenv
228 'Hooks',
229- 'canonical_url',
230 'config',
231 'juju_log',
232 'is_relation_made',
233@@ -316,8 +315,9 @@
234 )
235 self.migrate_database.assert_called_with()
236
237- def test_image_service_joined_leader(self):
238- self.canonical_url.return_value = 'http://glancehost'
239+ @patch.object(relations, 'canonical_url')
240+ def test_image_service_joined_leader(self, _canonical_url):
241+ _canonical_url.return_value = 'http://glancehost'
242 relations.image_service_joined()
243 args = {
244 'glance-api-server': 'http://glancehost:9292',
245@@ -325,8 +325,9 @@
246 }
247 self.relation_set.assert_called_with(**args)
248
249- def test_image_service_joined_specified_interface(self):
250- self.canonical_url.return_value = 'http://glancehost'
251+ @patch.object(relations, 'canonical_url')
252+ def test_image_service_joined_specified_interface(self, _canonical_url):
253+ _canonical_url.return_value = 'http://glancehost'
254 relations.image_service_joined(relation_id='image-service:1')
255 args = {
256 'glance-api-server': 'http://glancehost:9292',
257@@ -413,10 +414,12 @@
258 for c in [call('/etc/glance/glance.conf')]:
259 self.assertNotIn(c, configs.write.call_args_list)
260
261+ @patch("charmhelpers.core.host.service")
262 @patch("glance_relations.relation_get", autospec=True)
263 @patch.object(relations, 'CONFIGS')
264 def test_ceph_changed_with_key_and_relation_data(self, configs,
265- mock_relation_get):
266+ mock_relation_get,
267+ mock_service):
268 configs.complete_contexts = MagicMock()
269 configs.complete_contexts.return_value = ['ceph']
270 configs.write = MagicMock()
271@@ -435,8 +438,9 @@
272 self.delete_keyring.assert_called_with(service='glance')
273 self.assertTrue(configs.write_all.called)
274
275- def test_keystone_joined(self):
276- self.canonical_url.return_value = 'http://glancehost'
277+ @patch.object(relations, 'canonical_url')
278+ def test_keystone_joined(self, _canonical_url):
279+ _canonical_url.return_value = 'http://glancehost'
280 relations.keystone_joined()
281 ex = {
282 'region': 'RegionOne',
283@@ -448,8 +452,9 @@
284 }
285 self.relation_set.assert_called_with(**ex)
286
287- def test_keystone_joined_with_relation_id(self):
288- self.canonical_url.return_value = 'http://glancehost'
289+ @patch.object(relations, 'canonical_url')
290+ def test_keystone_joined_with_relation_id(self, _canonical_url):
291+ _canonical_url.return_value = 'http://glancehost'
292 relations.keystone_joined(relation_id='identity-service:0')
293 ex = {
294 'region': 'RegionOne',
295@@ -461,6 +466,26 @@
296 }
297 self.relation_set.assert_called_with(**ex)
298
299+ @patch('charmhelpers.contrib.openstack.ip.is_clustered')
300+ @patch('charmhelpers.contrib.openstack.ip.unit_get')
301+ @patch('charmhelpers.contrib.openstack.ip.config')
302+ def test_keystone_joined_public_endpoint(self, _config, _unit_get,
303+ _is_clustered):
304+ _unit_get.return_value = 'glancehost'
305+ _is_clustered.return_value = False
306+ self.test_config.set('os-public-hostname', 'glance.example.com')
307+ _config.side_effect = self.test_config.get
308+ relations.keystone_joined()
309+ ex = {
310+ 'region': 'RegionOne',
311+ 'public_url': 'http://glance.example.com:9292',
312+ 'admin_url': 'http://glancehost:9292',
313+ 'service': 'glance',
314+ 'internal_url': 'http://glancehost:9292',
315+ 'relation_id': None,
316+ }
317+ self.relation_set.assert_called_with(**ex)
318+
319 @patch.object(relations, 'CONFIGS')
320 def test_keystone_changes_incomplete(self, configs):
321 configs.complete_contexts.return_value = []
322@@ -566,9 +591,11 @@
323 call('/etc/haproxy/haproxy.cfg')],
324 configs.write.call_args_list)
325
326+ @patch.object(relations, 'canonical_url')
327 @patch.object(relations, 'relation_set')
328 @patch.object(relations, 'CONFIGS')
329- def test_cluster_changed_with_ipv6(self, configs, relation_set):
330+ def test_cluster_changed_with_ipv6(self, configs, relation_set,
331+ _canonical_url):
332 self.test_config.set('prefer-ipv6', True)
333 configs.complete_contexts = MagicMock()
334 configs.complete_contexts.return_value = ['cluster']
335@@ -679,10 +706,11 @@
336 'ha_changed: hacluster subordinate is not fully clustered.'
337 )
338
339+ @patch.object(relations, 'canonical_url')
340 @patch.object(relations, 'keystone_joined')
341 @patch.object(relations, 'CONFIGS')
342 def test_configure_https_enable_with_identity_service(
343- self, configs, keystone_joined):
344+ self, configs, keystone_joined, _canonical_url):
345 configs.complete_contexts = MagicMock()
346 configs.complete_contexts.return_value = ['https']
347 configs.write = MagicMock()
348@@ -693,10 +721,11 @@
349 self.check_call.assert_called_has_calls(calls)
350 keystone_joined.assert_called_with(relation_id='identity-service:0')
351
352+ @patch.object(relations, 'canonical_url')
353 @patch.object(relations, 'keystone_joined')
354 @patch.object(relations, 'CONFIGS')
355 def test_configure_https_disable_with_keystone_joined(
356- self, configs, keystone_joined):
357+ self, configs, keystone_joined, _canonical_url):
358 configs.complete_contexts = MagicMock()
359 configs.complete_contexts.return_value = ['']
360 configs.write = MagicMock()
361@@ -707,10 +736,11 @@
362 self.check_call.assert_called_has_calls(calls)
363 keystone_joined.assert_called_with(relation_id='identity-service:0')
364
365+ @patch.object(relations, 'canonical_url')
366 @patch.object(relations, 'image_service_joined')
367 @patch.object(relations, 'CONFIGS')
368 def test_configure_https_enable_with_image_service(
369- self, configs, image_service_joined):
370+ self, configs, image_service_joined, _canonical_url):
371 configs.complete_contexts = MagicMock()
372 configs.complete_contexts.return_value = ['https']
373 configs.write = MagicMock()
374@@ -721,10 +751,11 @@
375 self.check_call.assert_called_has_calls(calls)
376 image_service_joined.assert_called_with(relation_id='image-service:0')
377
378+ @patch.object(relations, 'canonical_url')
379 @patch.object(relations, 'image_service_joined')
380 @patch.object(relations, 'CONFIGS')
381 def test_configure_https_disable_with_image_service(
382- self, configs, image_service_joined):
383+ self, configs, image_service_joined, _canonical_url):
384 configs.complete_contexts = MagicMock()
385 configs.complete_contexts.return_value = ['']
386 configs.write = MagicMock()

Subscribers

People subscribed via source and target branches