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

Proposed by Billy Olsen
Status: Merged
Merged at revision: 165
Proposed branch: lp:~billy-olsen/charms/trusty/nova-cloud-controller/backport-lp1398182
Merge into: lp:~openstack-charmers-archive/charms/trusty/nova-cloud-controller/trunk
Diff against target: 506 lines (+151/-69) (has conflicts)
5 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_nova_cc_contexts.py (+8/-4)
unit_tests/test_nova_cc_hooks.py (+57/-21)
Text conflict in unit_tests/test_nova_cc_hooks.py
To merge this branch: bzr merge lp:~billy-olsen/charms/trusty/nova-cloud-controller/backport-lp1398182
Reviewer Review Type Date Requested Status
Corey Bryant (community) Approve
Review via email: mp+262006@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 #5409 nova-cloud-controller for billy-olsen mp262006
    LINT OK: passed

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

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

charm_unit_test #5041 nova-cloud-controller for billy-olsen mp262006
    UNIT OK: passed

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

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

charm_amulet_test #4652 nova-cloud-controller for billy-olsen mp262006
    AMULET FAIL: amulet-test failed

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

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

Revision history for this message
Corey Bryant (corey.bryant) :
review: Approve
Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_amulet_test #4663 nova-cloud-controller for billy-olsen mp262006
    AMULET OK: passed

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

165. By Billy Olsen

Official c-h stable sync

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-20 10:21:36 +0000
3+++ config.yaml 2015-06-18 23:39:46 +0000
4@@ -230,6 +230,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 provided by the
13+ nova-cloud-controller in the keystone identity provider.
14+ .
15+ This value will be used for public endpoints. For example, an
16+ os-public-hostname set to 'ncc.example.com' with ssl enabled will
17+ create public endpoints such as:
18+ .
19+ https://ncc.example.com:8775/v2/$(tenant_id)s
20 service-guard:
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-16 14:17:04 +0000
26+++ hooks/charmhelpers/contrib/hahelpers/cluster.py 2015-06-18 23:39:46 +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-31 14:56:11 +0000
76+++ hooks/charmhelpers/contrib/openstack/ip.py 2015-06-18 23:39:46 +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_nova_cc_contexts.py'
223--- unit_tests/test_nova_cc_contexts.py 2015-04-20 10:21:36 +0000
224+++ unit_tests/test_nova_cc_contexts.py 2015-06-18 23:39:46 +0000
225@@ -90,11 +90,13 @@
226 self.assertEqual({'memcached_servers': "%s:11211" % (formated_ip, )},
227 instance_console())
228
229+ @mock.patch('charmhelpers.contrib.openstack.neutron.os_release')
230 @mock.patch.object(context, 'use_local_neutron_api')
231 @mock.patch('charmhelpers.contrib.openstack.ip.config')
232 @mock.patch('charmhelpers.contrib.openstack.ip.is_clustered')
233 def test_neutron_context_single_vip(self, mock_is_clustered, mock_config,
234- mock_use_local_neutron_api):
235+ mock_use_local_neutron_api,
236+ _os_release):
237 mock_use_local_neutron_api.return_value = True
238 self.https.return_value = False
239 mock_is_clustered.return_value = True
240@@ -102,7 +104,7 @@
241 'os-internal-network': '10.0.0.1/24',
242 'os-admin-network': '10.0.1.0/24',
243 'os-public-network': '10.0.2.0/24'}
244- mock_config.side_effect = lambda key: config[key]
245+ mock_config.side_effect = lambda key: config.get(key)
246
247 mock_use_local_neutron_api.return_value = False
248 ctxt = context.NeutronCCContext()()
249@@ -114,18 +116,20 @@
250 self.assertEqual(ctxt['nova_url'], 'http://10.0.0.1:8774/v2')
251 self.assertEqual(ctxt['neutron_url'], 'http://10.0.0.1:9696')
252
253+ @mock.patch('charmhelpers.contrib.openstack.neutron.os_release')
254 @mock.patch.object(context, 'use_local_neutron_api')
255 @mock.patch('charmhelpers.contrib.openstack.ip.config')
256 @mock.patch('charmhelpers.contrib.openstack.ip.is_clustered')
257 def test_neutron_context_multi_vip(self, mock_is_clustered, mock_config,
258- mock_use_local_neutron_api):
259+ mock_use_local_neutron_api,
260+ _os_release):
261 self.https.return_value = False
262 mock_is_clustered.return_value = True
263 config = {'vip': '10.0.0.1 10.0.1.1 10.0.2.1',
264 'os-internal-network': '10.0.1.0/24',
265 'os-admin-network': '10.0.0.0/24',
266 'os-public-network': '10.0.2.0/24'}
267- mock_config.side_effect = lambda key: config[key]
268+ mock_config.side_effect = lambda key: config.get(key)
269
270 mock_use_local_neutron_api.return_value = False
271 ctxt = context.NeutronCCContext()()
272
273=== modified file 'unit_tests/test_nova_cc_hooks.py'
274--- unit_tests/test_nova_cc_hooks.py 2015-06-15 09:50:18 +0000
275+++ unit_tests/test_nova_cc_hooks.py 2015-06-18 23:39:46 +0000
276@@ -25,13 +25,13 @@
277 'api_port',
278 'apt_update',
279 'apt_install',
280- 'canonical_url',
281 'configure_installation_source',
282 'charm_dir',
283 'do_openstack_upgrade',
284 'openstack_upgrade_available',
285 'cmd_all_services',
286 'config',
287+ 'determine_endpoints',
288 'determine_packages',
289 'determine_ports',
290 'disable_services',
291@@ -114,7 +114,12 @@
292 self.assertTrue(self.save_script_rc.called)
293 mock_filter_packages.assert_called_with([])
294
295+<<<<<<< TREE
296 @patch.object(hooks, 'filter_installed_packages')
297+=======
298+ @patch('charmhelpers.contrib.openstack.ip.service_name',
299+ lambda *args: 'nova-cloud-controller')
300+>>>>>>> MERGE-SOURCE
301 @patch.object(hooks, 'cluster_joined')
302 @patch.object(hooks, 'identity_joined')
303 @patch.object(hooks, 'neutron_api_relation_joined')
304@@ -193,9 +198,11 @@
305 self.assertEquals(sorted(self.relation_set.call_args_list),
306 sorted(expected_relations))
307
308+ @patch.object(hooks, 'canonical_url')
309 @patch.object(utils, 'config')
310 @patch.object(hooks, '_auth_config')
311- def test_compute_joined_neutron(self, auth_config, _util_config):
312+ def test_compute_joined_neutron(self, auth_config, _util_config,
313+ _canonical_url):
314 _util_config.return_value = None
315 self.is_relation_made.return_value = False
316 self.network_manager.return_value = 'neutron'
317@@ -203,7 +210,7 @@
318 self.keystone_ca_cert_b64.return_value = 'foocert64'
319 self.volume_service.return_value = 'cinder'
320 self.unit_get.return_value = 'nova-cc-host1'
321- self.canonical_url.return_value = 'http://nova-cc-host1'
322+ _canonical_url.return_value = 'http://nova-cc-host1'
323 self.api_port.return_value = '9696'
324 self.neutron_plugin.return_value = 'nvp'
325 auth_config.return_value = FAKE_KS_AUTH_CFG
326@@ -222,11 +229,12 @@
327 quantum_plugin='nvp',
328 network_manager='neutron', **FAKE_KS_AUTH_CFG)
329
330+ @patch.object(hooks, 'canonical_url')
331 @patch.object(utils, 'config')
332 @patch.object(hooks, 'NeutronAPIContext')
333 @patch.object(hooks, '_auth_config')
334 def test_compute_joined_neutron_api_rel(self, auth_config, napi,
335- _util_config):
336+ _util_config, _canonical_url):
337 def mock_NeutronAPIContext():
338 return {
339 'neutron_plugin': 'bob',
340@@ -241,7 +249,7 @@
341 self.keystone_ca_cert_b64.return_value = 'foocert64'
342 self.volume_service.return_value = 'cinder'
343 self.unit_get.return_value = 'nova-cc-host1'
344- self.canonical_url.return_value = 'http://nova-cc-host1'
345+ _canonical_url.return_value = 'http://nova-cc-host1'
346 self.api_port.return_value = '9696'
347 self.neutron_plugin.return_value = 'nvp'
348 auth_config.return_value = FAKE_KS_AUTH_CFG
349@@ -259,13 +267,14 @@
350 quantum_plugin='bob',
351 network_manager='neutron', **FAKE_KS_AUTH_CFG)
352
353+ @patch.object(hooks, 'canonical_url')
354 @patch.object(hooks, '_auth_config')
355- def test_nova_vmware_joined(self, auth_config):
356+ def test_nova_vmware_joined(self, auth_config, _canonical_url):
357 auth_config.return_value = FAKE_KS_AUTH_CFG
358 # quantum-security-groups, plugin
359 self.neutron_plugin.return_value = 'nvp'
360 self.network_manager.return_value = 'neutron'
361- self.canonical_url.return_value = 'http://nova-cc-host1'
362+ _canonical_url.return_value = 'http://nova-cc-host1'
363 self.api_port.return_value = '9696'
364 hooks.nova_vmware_relation_joined()
365 self.relation_set.assert_called_with(
366@@ -283,6 +292,25 @@
367 nova_hostname='nova.foohost.com')
368 self.unit_get.assert_called_with('private-address')
369
370+ @patch('charmhelpers.contrib.openstack.ip.service_name',
371+ lambda *args: 'nova-cloud-controller')
372+ @patch('charmhelpers.contrib.openstack.ip.unit_get')
373+ @patch('charmhelpers.contrib.openstack.ip.is_clustered')
374+ @patch('charmhelpers.contrib.openstack.ip.config')
375+ def test_identity_joined(self, _ip_config, _is_clustered, _unit_get):
376+ _is_clustered.return_value = False
377+ _unit_get.return_value = '127.0.0.1'
378+ _ip_config.side_effect = self.test_config.get
379+
380+ self.test_config.set('os-public-hostname', 'ncc.example.com')
381+ hooks.identity_joined()
382+
383+ self.determine_endpoints.asssert_called_with(
384+ public_url='http://ncc.example.com',
385+ internal_url='http://127.0.0.1',
386+ admin_url='http://127.0.0.1'
387+ )
388+
389 def test_postgresql_nova_db_joined(self):
390 self.is_relation_made.return_value = False
391 hooks.pgsql_nova_db_joined()
392@@ -447,9 +475,10 @@
393 call('/etc/neutron/neutron.conf')])
394 cell_joined.assert_called_with(rid='nova-cell-api/0')
395
396- def test_nova_cell_relation_joined(self):
397+ @patch.object(hooks, 'canonical_url')
398+ def test_nova_cell_relation_joined(self, _canonical_url):
399 self.uuid.uuid4.return_value = 'bob'
400- self.canonical_url.return_value = 'http://novaurl'
401+ _canonical_url.return_value = 'http://novaurl'
402 hooks.nova_cell_relation_joined(rid='rid',
403 remote_restart=True)
404 self.relation_set.assert_called_with(restart_trigger='bob',
405@@ -468,19 +497,20 @@
406 }
407 self.assertEquals(hooks.get_cell_type(), 'parent')
408
409+ @patch.object(hooks, 'canonical_url')
410 @patch.object(os, 'rename')
411 @patch.object(os.path, 'isfile')
412 @patch.object(hooks, 'CONFIGS')
413 @patch.object(hooks, 'get_cell_type')
414 def test_neutron_api_relation_joined(self, get_cell_type, configs, isfile,
415- rename):
416+ rename, _canonical_url):
417 neutron_conf = '/etc/neutron/neutron.conf'
418 nova_url = 'http://novaurl:8774/v2'
419 isfile.return_value = True
420 self.service_running.return_value = True
421 _identity_joined = self.patch('identity_joined')
422 self.relation_ids.return_value = ['relid']
423- self.canonical_url.return_value = 'http://novaurl'
424+ _canonical_url.return_value = 'http://novaurl'
425 get_cell_type.return_value = 'parent'
426 self.uuid.uuid4.return_value = 'bob'
427 with patch_open() as (_open, _file):
428@@ -517,11 +547,12 @@
429 self.assertTrue(_compute_joined.called)
430 self.assertTrue(_quantum_joined.called)
431
432+ @patch.object(hooks, 'canonical_url')
433 @patch.object(utils, 'config')
434- def test_console_settings_vnc(self, _utils_config):
435+ def test_console_settings_vnc(self, _utils_config, _canonical_url):
436 _utils_config.return_value = 'vnc'
437 _cc_host = "nova-cc-host1"
438- self.canonical_url.return_value = 'http://' + _cc_host
439+ _canonical_url.return_value = 'http://' + _cc_host
440 _con_sets = hooks.console_settings()
441 console_settings = {
442 'console_proxy_novnc_address': 'http://%s:6080/vnc_auto.html' %
443@@ -537,11 +568,12 @@
444 }
445 self.assertEqual(_con_sets, console_settings)
446
447+ @patch.object(hooks, 'canonical_url')
448 @patch.object(utils, 'config')
449- def test_console_settings_xvpvnc(self, _utils_config):
450+ def test_console_settings_xvpvnc(self, _utils_config, _canonical_url):
451 _utils_config.return_value = 'xvpvnc'
452 _cc_host = "nova-cc-host1"
453- self.canonical_url.return_value = 'http://' + _cc_host
454+ _canonical_url.return_value = 'http://' + _cc_host
455 _con_sets = hooks.console_settings()
456 console_settings = {
457 'console_access_protocol': 'xvpvnc',
458@@ -553,11 +585,12 @@
459 }
460 self.assertEqual(_con_sets, console_settings)
461
462+ @patch.object(hooks, 'canonical_url')
463 @patch.object(utils, 'config')
464- def test_console_settings_novnc(self, _utils_config):
465+ def test_console_settings_novnc(self, _utils_config, _canonical_url):
466 _utils_config.return_value = 'novnc'
467 _cc_host = "nova-cc-host1"
468- self.canonical_url.return_value = 'http://' + _cc_host
469+ _canonical_url.return_value = 'http://' + _cc_host
470 _con_sets = hooks.console_settings()
471 console_settings = {
472 'console_proxy_novnc_address': 'http://%s:6080/vnc_auto.html' %
473@@ -569,11 +602,12 @@
474 }
475 self.assertEqual(_con_sets, console_settings)
476
477+ @patch.object(hooks, 'canonical_url')
478 @patch.object(utils, 'config')
479- def test_console_settings_spice(self, _utils_config):
480+ def test_console_settings_spice(self, _utils_config, _canonical_url):
481 _utils_config.return_value = 'spice'
482 _cc_host = "nova-cc-host1"
483- self.canonical_url.return_value = 'http://' + _cc_host
484+ _canonical_url.return_value = 'http://' + _cc_host
485 _con_sets = hooks.console_settings()
486 console_settings = {
487 'console_proxy_spice_address': 'http://%s:6082/spice_auto.html' %
488@@ -585,14 +619,16 @@
489 }
490 self.assertEqual(_con_sets, console_settings)
491
492+ @patch.object(hooks, 'canonical_url')
493 @patch.object(utils, 'config')
494- def test_console_settings_explicit_ip(self, _utils_config):
495+ def test_console_settings_explicit_ip(self, _utils_config,
496+ _canonical_url):
497 _utils_config.return_value = 'spice'
498 _cc_public_host = "public-host"
499 _cc_private_host = "private-host"
500 self.test_config.set('console-proxy-ip', _cc_public_host)
501 _con_sets = hooks.console_settings()
502- self.canonical_url.return_value = 'http://' + _cc_private_host
503+ _canonical_url.return_value = 'http://' + _cc_private_host
504 console_settings = {
505 'console_proxy_spice_address': 'http://%s:6082/spice_auto.html' %
506 (_cc_public_host),

Subscribers

People subscribed via source and target branches