Merge lp:~openstack-charmers/charms/precise/nova-cloud-controller/icehouse into lp:~openstack-charmers-archive/charms/precise/nova-cloud-controller/trunk

Proposed by James Page
Status: Merged
Merged at revision: 71
Proposed branch: lp:~openstack-charmers/charms/precise/nova-cloud-controller/icehouse
Merge into: lp:~openstack-charmers-archive/charms/precise/nova-cloud-controller/trunk
Diff against target: 2203 lines (+1381/-122)
31 files modified
Makefile (+1/-2)
README.txt (+15/-0)
config.yaml (+6/-1)
hooks/charmhelpers/contrib/hahelpers/apache.py (+9/-8)
hooks/charmhelpers/contrib/openstack/context.py (+106/-25)
hooks/charmhelpers/contrib/openstack/neutron.py (+14/-4)
hooks/charmhelpers/contrib/openstack/utils.py (+1/-0)
hooks/charmhelpers/contrib/storage/linux/utils.py (+12/-3)
hooks/nova_cc_context.py (+45/-4)
hooks/nova_cc_hooks.py (+73/-11)
hooks/nova_cc_utils.py (+211/-33)
metadata.yaml (+4/-0)
setup.cfg (+5/-0)
templates/essex/nova.conf (+1/-1)
templates/folsom/nova.conf (+8/-3)
templates/folsom/ovs_quantum_plugin.ini (+1/-1)
templates/grizzly/nova.conf (+115/-0)
templates/grizzly/quantum.conf (+45/-0)
templates/havana/neutron.conf (+7/-6)
templates/havana/nova.conf (+119/-0)
templates/havana/nvp.ini (+0/-7)
templates/havana/ovs_neutron_plugin.ini (+0/-7)
templates/icehouse/etc_nova_api-paste.ini (+124/-0)
templates/icehouse/ml2_conf.ini (+30/-0)
templates/icehouse/neutron.conf (+71/-0)
templates/icehouse/nova.conf (+130/-0)
templates/parts/database (+3/-0)
templates/parts/rabbitmq (+21/-0)
templates/parts/section-database (+4/-0)
unit_tests/test_nova_cc_hooks.py (+97/-4)
unit_tests/test_nova_cc_utils.py (+103/-2)
To merge this branch: bzr merge lp:~openstack-charmers/charms/precise/nova-cloud-controller/icehouse
Reviewer Review Type Date Requested Status
OpenStack Charmers Pending
Review via email: mp+215238@code.launchpad.net

Description of the change

Icehouse support

Active/Active RMQ

SSL keystone support

Postgresql Support

To post a comment you must log in.
70. By Edward Hope-Morley

[heut2008,r=hopem]

Fix authorized_keys file becomes incorrect after removing a compute node and
then add a new node.

71. By James Page

[james-page,hazmat,ivoks,coreycb,yolanda.robla,r=james-page,t=*]

Support for Icehouse on 12.04 and 14.04
Support for Active/Active and SSL RabbitMQ
Support for SSL MySQL
Support for SSL endpoints
Support for PostgreSQL

Fixes for upgrades on 12.04 grizzly->havana->icehouse

72. By James Page

Fixup merge break

73. By James Page

Fixup another merge bug

74. By James Page

fixup merge break

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Makefile'
2--- Makefile 2013-09-20 16:29:50 +0000
3+++ Makefile 2014-04-16 09:26:11 +0000
4@@ -2,8 +2,7 @@
5 PYTHON := /usr/bin/env python
6
7 lint:
8- @flake8 --exclude hooks/charmhelpers hooks
9- @flake8 --exclude hooks/charmhelpers unit_tests
10+ @flake8 --exclude hooks/charmhelpers hooks unit_tests
11 @charm proof
12
13 test:
14
15=== added file 'README.txt'
16--- README.txt 1970-01-01 00:00:00 +0000
17+++ README.txt 2014-04-16 09:26:11 +0000
18@@ -0,0 +1,15 @@
19+=====================
20+nova-cloud-controller
21+=====================
22+
23+Cloud controller node for Openstack nova. Contains nova-schedule, nova-api, nova-network and nova-objectstore.
24+
25+******************************************************
26+Special considerations to be deployed using Postgresql
27+******************************************************
28+
29+juju deploy nova-cloud-controller
30+juju deploy postgresql
31+
32+juju add-relation "nova-cloud-controller:pgsql-nova-db" "postgresql:db"
33+juju add-relation "nova-cloud-controller:pgsql-neutron-db" "postgresql:db"
34
35=== modified file 'config.yaml'
36--- config.yaml 2014-03-25 18:44:23 +0000
37+++ config.yaml 2014-04-16 09:26:11 +0000
38@@ -120,12 +120,17 @@
39 type: string
40 description: |
41 SSL certificate to install and use for API ports. Setting this value
42- and ssl_key will enable reverse proxying, point Glance's entry in the
43+ and ssl_key will enable reverse proxying, point Nova's entry in the
44 Keystone catalog to use https, and override any certficiate and key
45 issued by Keystone (if it is configured to do so).
46 ssl_key:
47 type: string
48 description: SSL key to use with certificate specified as ssl_cert.
49+ ssl_ca:
50+ type: string
51+ description: |
52+ SSL CA to use with the certificate and key provided - this is only
53+ required if you are providing a privately signed ssl_cert and ssl_key.
54 use-syslog:
55 type: boolean
56 default: False
57
58=== added symlink 'hooks/amqp-relation-departed'
59=== target is u'nova_cc_hooks.py'
60=== modified file 'hooks/charmhelpers/contrib/hahelpers/apache.py'
61--- hooks/charmhelpers/contrib/hahelpers/apache.py 2013-08-02 03:42:16 +0000
62+++ hooks/charmhelpers/contrib/hahelpers/apache.py 2014-04-16 09:26:11 +0000
63@@ -39,14 +39,15 @@
64
65
66 def get_ca_cert():
67- ca_cert = None
68- log("Inspecting identity-service relations for CA SSL certificate.",
69- level=INFO)
70- for r_id in relation_ids('identity-service'):
71- for unit in relation_list(r_id):
72- if not ca_cert:
73- ca_cert = relation_get('ca_cert',
74- rid=r_id, unit=unit)
75+ ca_cert = config_get('ssl_ca')
76+ if ca_cert is None:
77+ log("Inspecting identity-service relations for CA SSL certificate.",
78+ level=INFO)
79+ for r_id in relation_ids('identity-service'):
80+ for unit in relation_list(r_id):
81+ if ca_cert is None:
82+ ca_cert = relation_get('ca_cert',
83+ rid=r_id, unit=unit)
84 return ca_cert
85
86
87
88=== modified file 'hooks/charmhelpers/contrib/openstack/context.py'
89--- hooks/charmhelpers/contrib/openstack/context.py 2014-03-25 12:26:42 +0000
90+++ hooks/charmhelpers/contrib/openstack/context.py 2014-04-16 09:26:11 +0000
91@@ -1,5 +1,6 @@
92 import json
93 import os
94+import time
95
96 from base64 import b64decode
97
98@@ -113,7 +114,8 @@
99 class SharedDBContext(OSContextGenerator):
100 interfaces = ['shared-db']
101
102- def __init__(self, database=None, user=None, relation_prefix=None):
103+ def __init__(self,
104+ database=None, user=None, relation_prefix=None, ssl_dir=None):
105 '''
106 Allows inspecting relation for settings prefixed with relation_prefix.
107 This is useful for parsing access for multiple databases returned via
108@@ -122,6 +124,7 @@
109 self.relation_prefix = relation_prefix
110 self.database = database
111 self.user = user
112+ self.ssl_dir = ssl_dir
113
114 def __call__(self):
115 self.database = self.database or config('database')
116@@ -139,17 +142,72 @@
117
118 for rid in relation_ids('shared-db'):
119 for unit in related_units(rid):
120- passwd = relation_get(password_setting, rid=rid, unit=unit)
121+ rdata = relation_get(rid=rid, unit=unit)
122 ctxt = {
123- 'database_host': relation_get('db_host', rid=rid,
124- unit=unit),
125+ 'database_host': rdata.get('db_host'),
126 'database': self.database,
127 'database_user': self.user,
128- 'database_password': passwd,
129- }
130- if context_complete(ctxt):
131- return ctxt
132- return {}
133+ 'database_password': rdata.get(password_setting),
134+ 'database_type': 'mysql'
135+ }
136+ if context_complete(ctxt):
137+ db_ssl(rdata, ctxt, self.ssl_dir)
138+ return ctxt
139+ return {}
140+
141+
142+class PostgresqlDBContext(OSContextGenerator):
143+ interfaces = ['pgsql-db']
144+
145+ def __init__(self, database=None):
146+ self.database = database
147+
148+ def __call__(self):
149+ self.database = self.database or config('database')
150+ if self.database is None:
151+ log('Could not generate postgresql_db context. '
152+ 'Missing required charm config options. '
153+ '(database name)')
154+ raise OSContextError
155+ ctxt = {}
156+
157+ for rid in relation_ids(self.interfaces[0]):
158+ for unit in related_units(rid):
159+ ctxt = {
160+ 'database_host': relation_get('host', rid=rid, unit=unit),
161+ 'database': self.database,
162+ 'database_user': relation_get('user', rid=rid, unit=unit),
163+ 'database_password': relation_get('password', rid=rid, unit=unit),
164+ 'database_type': 'postgresql',
165+ }
166+ if context_complete(ctxt):
167+ return ctxt
168+ return {}
169+
170+
171+def db_ssl(rdata, ctxt, ssl_dir):
172+ if 'ssl_ca' in rdata and ssl_dir:
173+ ca_path = os.path.join(ssl_dir, 'db-client.ca')
174+ with open(ca_path, 'w') as fh:
175+ fh.write(b64decode(rdata['ssl_ca']))
176+ ctxt['database_ssl_ca'] = ca_path
177+ elif 'ssl_ca' in rdata:
178+ log("Charm not setup for ssl support but ssl ca found")
179+ return ctxt
180+ if 'ssl_cert' in rdata:
181+ cert_path = os.path.join(
182+ ssl_dir, 'db-client.cert')
183+ if not os.path.exists(cert_path):
184+ log("Waiting 1m for ssl client cert validity")
185+ time.sleep(60)
186+ with open(cert_path, 'w') as fh:
187+ fh.write(b64decode(rdata['ssl_cert']))
188+ ctxt['database_ssl_cert'] = cert_path
189+ key_path = os.path.join(ssl_dir, 'db-client.key')
190+ with open(key_path, 'w') as fh:
191+ fh.write(b64decode(rdata['ssl_key']))
192+ ctxt['database_ssl_key'] = key_path
193+ return ctxt
194
195
196 class IdentityServiceContext(OSContextGenerator):
197@@ -161,24 +219,25 @@
198
199 for rid in relation_ids('identity-service'):
200 for unit in related_units(rid):
201+ rdata = relation_get(rid=rid, unit=unit)
202 ctxt = {
203- 'service_port': relation_get('service_port', rid=rid,
204- unit=unit),
205- 'service_host': relation_get('service_host', rid=rid,
206- unit=unit),
207- 'auth_host': relation_get('auth_host', rid=rid, unit=unit),
208- 'auth_port': relation_get('auth_port', rid=rid, unit=unit),
209- 'admin_tenant_name': relation_get('service_tenant',
210- rid=rid, unit=unit),
211- 'admin_user': relation_get('service_username', rid=rid,
212- unit=unit),
213- 'admin_password': relation_get('service_password', rid=rid,
214- unit=unit),
215- # XXX: Hard-coded http.
216- 'service_protocol': 'http',
217- 'auth_protocol': 'http',
218+ 'service_port': rdata.get('service_port'),
219+ 'service_host': rdata.get('service_host'),
220+ 'auth_host': rdata.get('auth_host'),
221+ 'auth_port': rdata.get('auth_port'),
222+ 'admin_tenant_name': rdata.get('service_tenant'),
223+ 'admin_user': rdata.get('service_username'),
224+ 'admin_password': rdata.get('service_password'),
225+ 'service_protocol':
226+ rdata.get('service_protocol') or 'http',
227+ 'auth_protocol':
228+ rdata.get('auth_protocol') or 'http',
229 }
230 if context_complete(ctxt):
231+ # NOTE(jamespage) this is required for >= icehouse
232+ # so a missing value just indicates keystone needs
233+ # upgrading
234+ ctxt['admin_tenant_id'] = rdata.get('service_tenant_id')
235 return ctxt
236 return {}
237
238@@ -186,6 +245,9 @@
239 class AMQPContext(OSContextGenerator):
240 interfaces = ['amqp']
241
242+ def __init__(self, ssl_dir=None):
243+ self.ssl_dir = ssl_dir
244+
245 def __call__(self):
246 log('Generating template context for amqp')
247 conf = config()
248@@ -196,7 +258,6 @@
249 log('Could not generate shared_db context. '
250 'Missing required charm config options: %s.' % e)
251 raise OSContextError
252-
253 ctxt = {}
254 for rid in relation_ids('amqp'):
255 ha_vip_only = False
256@@ -214,6 +275,14 @@
257 unit=unit),
258 'rabbitmq_virtual_host': vhost,
259 })
260+
261+ ssl_port = relation_get('ssl_port', rid=rid, unit=unit)
262+ if ssl_port:
263+ ctxt['rabbit_ssl_port'] = ssl_port
264+ ssl_ca = relation_get('ssl_ca', rid=rid, unit=unit)
265+ if ssl_ca:
266+ ctxt['rabbit_ssl_ca'] = ssl_ca
267+
268 if relation_get('ha_queues', rid=rid, unit=unit) is not None:
269 ctxt['rabbitmq_ha_queues'] = True
270
271@@ -221,6 +290,16 @@
272 rid=rid, unit=unit) is not None
273
274 if context_complete(ctxt):
275+ if 'rabbit_ssl_ca' in ctxt:
276+ if not self.ssl_dir:
277+ log(("Charm not setup for ssl support "
278+ "but ssl ca found"))
279+ break
280+ ca_path = os.path.join(
281+ self.ssl_dir, 'rabbit-client-ca.pem')
282+ with open(ca_path, 'w') as fh:
283+ fh.write(b64decode(ctxt['rabbit_ssl_ca']))
284+ ctxt['rabbit_ssl_ca'] = ca_path
285 # Sufficient information found = break out!
286 break
287 # Used for active/active rabbitmq >= grizzly
288@@ -391,6 +470,8 @@
289 'private_address': unit_get('private-address'),
290 'endpoints': []
291 }
292+ if is_clustered():
293+ ctxt['private_address'] = config('vip')
294 for api_port in self.external_ports:
295 ext_port = determine_apache_port(api_port)
296 int_port = determine_api_port(api_port)
297
298=== modified file 'hooks/charmhelpers/contrib/openstack/neutron.py'
299--- hooks/charmhelpers/contrib/openstack/neutron.py 2014-03-25 12:26:42 +0000
300+++ hooks/charmhelpers/contrib/openstack/neutron.py 2014-04-16 09:26:11 +0000
301@@ -17,6 +17,8 @@
302 kver = check_output(['uname', '-r']).strip()
303 return 'linux-headers-%s' % kver
304
305+QUANTUM_CONF_DIR = '/etc/quantum'
306+
307
308 def kernel_version():
309 """ Retrieve the current major kernel version as a tuple e.g. (3, 13) """
310@@ -35,6 +37,8 @@
311
312
313 # legacy
314+
315+
316 def quantum_plugins():
317 from charmhelpers.contrib.openstack import context
318 return {
319@@ -46,7 +50,8 @@
320 'contexts': [
321 context.SharedDBContext(user=config('neutron-database-user'),
322 database=config('neutron-database'),
323- relation_prefix='neutron')],
324+ relation_prefix='neutron',
325+ ssl_dir=QUANTUM_CONF_DIR)],
326 'services': ['quantum-plugin-openvswitch-agent'],
327 'packages': [[headers_package()] + determine_dkms_package(),
328 ['quantum-plugin-openvswitch-agent']],
329@@ -61,7 +66,8 @@
330 'contexts': [
331 context.SharedDBContext(user=config('neutron-database-user'),
332 database=config('neutron-database'),
333- relation_prefix='neutron')],
334+ relation_prefix='neutron',
335+ ssl_dir=QUANTUM_CONF_DIR)],
336 'services': [],
337 'packages': [],
338 'server_packages': ['quantum-server',
339@@ -70,6 +76,8 @@
340 }
341 }
342
343+NEUTRON_CONF_DIR = '/etc/neutron'
344+
345
346 def neutron_plugins():
347 from charmhelpers.contrib.openstack import context
348@@ -83,7 +91,8 @@
349 'contexts': [
350 context.SharedDBContext(user=config('neutron-database-user'),
351 database=config('neutron-database'),
352- relation_prefix='neutron')],
353+ relation_prefix='neutron',
354+ ssl_dir=NEUTRON_CONF_DIR)],
355 'services': ['neutron-plugin-openvswitch-agent'],
356 'packages': [[headers_package()] + determine_dkms_package(),
357 ['neutron-plugin-openvswitch-agent']],
358@@ -98,7 +107,8 @@
359 'contexts': [
360 context.SharedDBContext(user=config('neutron-database-user'),
361 database=config('neutron-database'),
362- relation_prefix='neutron')],
363+ relation_prefix='neutron',
364+ ssl_dir=NEUTRON_CONF_DIR)],
365 'services': [],
366 'packages': [],
367 'server_packages': ['neutron-server',
368
369=== modified file 'hooks/charmhelpers/contrib/openstack/utils.py'
370--- hooks/charmhelpers/contrib/openstack/utils.py 2014-03-25 12:26:42 +0000
371+++ hooks/charmhelpers/contrib/openstack/utils.py 2014-04-16 09:26:11 +0000
372@@ -65,6 +65,7 @@
373 ('1.10.0', 'havana'),
374 ('1.9.1', 'havana'),
375 ('1.9.0', 'havana'),
376+ ('1.13.1', 'icehouse'),
377 ('1.13.0', 'icehouse'),
378 ('1.12.0', 'icehouse'),
379 ('1.11.0', 'icehouse'),
380
381=== modified file 'hooks/charmhelpers/contrib/storage/linux/utils.py'
382--- hooks/charmhelpers/contrib/storage/linux/utils.py 2014-03-25 12:26:42 +0000
383+++ hooks/charmhelpers/contrib/storage/linux/utils.py 2014-04-16 09:26:11 +0000
384@@ -2,7 +2,9 @@
385 from stat import S_ISBLK
386
387 from subprocess import (
388- check_call
389+ check_call,
390+ check_output,
391+ call
392 )
393
394
395@@ -22,5 +24,12 @@
396
397 :param block_device: str: Full path of block device to clean.
398 '''
399- check_call(['sgdisk', '--zap-all', '--clear',
400- '--mbrtogpt', block_device])
401+ # sometimes sgdisk exits non-zero; this is OK, dd will clean up
402+ call(['sgdisk', '--zap-all', '--mbrtogpt',
403+ '--clear', block_device])
404+ dev_end = check_output(['blockdev', '--getsz', block_device])
405+ gpt_end = int(dev_end.split()[0]) - 100
406+ check_call(['dd', 'if=/dev/zero', 'of=%s'%(block_device),
407+ 'bs=1M', 'count=1'])
408+ check_call(['dd', 'if=/dev/zero', 'of=%s'%(block_device),
409+ 'bs=512', 'count=100', 'seek=%s'%(gpt_end)])
410
411=== modified file 'hooks/nova_cc_context.py'
412--- hooks/nova_cc_context.py 2014-02-16 19:17:42 +0000
413+++ hooks/nova_cc_context.py 2014-04-16 09:26:11 +0000
414@@ -1,12 +1,17 @@
415
416 from charmhelpers.core.hookenv import (
417- config, relation_ids, relation_set, log, ERROR)
418+ config, relation_ids, relation_set, log, ERROR,
419+ unit_get)
420
421 from charmhelpers.fetch import apt_install, filter_installed_packages
422 from charmhelpers.contrib.openstack import context, neutron, utils
423
424 from charmhelpers.contrib.hahelpers.cluster import (
425- determine_apache_port, determine_api_port)
426+ determine_apache_port,
427+ determine_api_port,
428+ https,
429+ is_clustered
430+)
431
432
433 class ApacheSSLContext(context.ApacheSSLContext):
434@@ -112,6 +117,24 @@
435 return ctxt
436
437
438+def canonical_url(vip_setting='vip'):
439+ '''
440+ Returns the correct HTTP URL to this host given the state of HTTPS
441+ configuration and hacluster.
442+
443+ :vip_setting: str: Setting in charm config that specifies
444+ VIP address.
445+ '''
446+ scheme = 'http'
447+ if https():
448+ scheme = 'https'
449+ if is_clustered():
450+ addr = config(vip_setting)
451+ else:
452+ addr = unit_get('private-address')
453+ return '%s://%s' % (scheme, addr)
454+
455+
456 class NeutronCCContext(context.NeutronContext):
457 interfaces = []
458
459@@ -148,10 +171,12 @@
460 ','.join(_config['nvp-controllers'].split())
461 ctxt['nvp_controllers_list'] = \
462 _config['nvp-controllers'].split()
463+ ctxt['nova_url'] = "{}:8774/v2".format(canonical_url())
464 return ctxt
465
466
467 class IdentityServiceContext(context.IdentityServiceContext):
468+
469 def __call__(self):
470 ctxt = super(IdentityServiceContext, self).__call__()
471 if not ctxt:
472@@ -159,7 +184,23 @@
473
474 # the ec2 api needs to know the location of the keystone ec2
475 # tokens endpoint, set in nova.conf
476- ec2_tokens = 'http://%s:%s/v2.0/ec2tokens' % (ctxt['service_host'],
477- ctxt['service_port'])
478+ ec2_tokens = '%s://%s:%s/v2.0/ec2tokens' % (
479+ ctxt['service_protocol'] or 'http',
480+ ctxt['service_host'],
481+ ctxt['service_port']
482+ )
483 ctxt['keystone_ec2_url'] = ec2_tokens
484+ ctxt['region'] = config('region')
485 return ctxt
486+
487+
488+class NovaPostgresqlDBContext(context.PostgresqlDBContext):
489+ interfaces = ['pgsql-nova-db']
490+
491+
492+class NeutronPostgresqlDBContext(context.PostgresqlDBContext):
493+ interfaces = ['pgsql-neutron-db']
494+
495+ def __init__(self):
496+ super(NeutronPostgresqlDBContext,
497+ self).__init__(config('neutron-database'))
498
499=== modified file 'hooks/nova_cc_hooks.py'
500--- hooks/nova_cc_hooks.py 2014-02-16 18:44:30 +0000
501+++ hooks/nova_cc_hooks.py 2014-04-16 09:26:11 +0000
502@@ -13,7 +13,9 @@
503 UnregisteredHookError,
504 config,
505 charm_dir,
506+ is_relation_made,
507 log,
508+ ERROR,
509 relation_get,
510 relation_ids,
511 relation_set,
512@@ -96,8 +98,9 @@
513 @hooks.hook('config-changed')
514 @restart_on_change(restart_map(), stopstart=True)
515 def config_changed():
516+ global CONFIGS
517 if openstack_upgrade_available('nova-common'):
518- do_openstack_upgrade(configs=CONFIGS)
519+ CONFIGS = do_openstack_upgrade()
520 save_script_rc()
521 configure_https()
522 CONFIGS.write_all()
523@@ -110,6 +113,7 @@
524
525
526 @hooks.hook('amqp-relation-changed')
527+@hooks.hook('amqp-relation-departed')
528 @restart_on_change(restart_map())
529 def amqp_changed():
530 if 'amqp' not in CONFIGS.complete_contexts():
531@@ -124,6 +128,14 @@
532
533 @hooks.hook('shared-db-relation-joined')
534 def db_joined():
535+ if is_relation_made('pgsql-nova-db') or \
536+ is_relation_made('pgsql-neutron-db'):
537+ # error, postgresql is used
538+ e = ('Attempting to associate a mysql database when there is already '
539+ 'associated a postgresql one')
540+ log(e, level=ERROR)
541+ raise Exception(e)
542+
543 relation_set(nova_database=config('database'),
544 nova_username=config('database-user'),
545 nova_hostname=unit_get('private-address'))
546@@ -134,25 +146,68 @@
547 neutron_hostname=unit_get('private-address'))
548
549
550+@hooks.hook('pgsql-nova-db-relation-joined')
551+def pgsql_nova_db_joined():
552+ if is_relation_made('shared-db'):
553+ # raise error
554+ e = ('Attempting to associate a postgresql database'
555+ ' when there is already associated a mysql one')
556+ log(e, level=ERROR)
557+ raise Exception(e)
558+
559+ relation_set(database=config('database'))
560+
561+
562+@hooks.hook('pgsql-neutron-db-relation-joined')
563+def pgsql_neutron_db_joined():
564+ if is_relation_made('shared-db'):
565+ # raise error
566+ e = ('Attempting to associate a postgresql database'
567+ ' when there is already associated a mysql one')
568+ log(e, level=ERROR)
569+ raise Exception(e)
570+
571+ relation_set(database=config('neutron-database'))
572+
573+
574 @hooks.hook('shared-db-relation-changed')
575 @restart_on_change(restart_map())
576 def db_changed():
577 if 'shared-db' not in CONFIGS.complete_contexts():
578 log('shared-db relation incomplete. Peer not ready?')
579 return
580- CONFIGS.write(NOVA_CONF)
581-
582+ CONFIGS.write_all()
583+
584+ if eligible_leader(CLUSTER_RES):
585+ migrate_database()
586+ log('Triggering remote cloud-compute restarts.')
587+ [compute_joined(rid=rid, remote_restart=True)
588+ for rid in relation_ids('cloud-compute')]
589+
590+
591+@hooks.hook('pgsql-nova-db-relation-changed')
592+@restart_on_change(restart_map())
593+def postgresql_nova_db_changed():
594+ if 'pgsql-nova-db' not in CONFIGS.complete_contexts():
595+ log('pgsql-nova-db relation incomplete. Peer not ready?')
596+ return
597+ CONFIGS.write_all()
598+
599+ if eligible_leader(CLUSTER_RES):
600+ migrate_database()
601+ log('Triggering remote cloud-compute restarts.')
602+ [compute_joined(rid=rid, remote_restart=True)
603+ for rid in relation_ids('cloud-compute')]
604+
605+
606+@hooks.hook('pgsql-neutron-db-relation-changed')
607+@restart_on_change(restart_map())
608+def postgresql_neutron_db_changed():
609 if network_manager() in ['neutron', 'quantum']:
610 plugin = neutron_plugin()
611 # DB config might have been moved to main neutron.conf in H?
612 CONFIGS.write(neutron_plugin_attribute(plugin, 'config'))
613
614- if eligible_leader(CLUSTER_RES):
615- migrate_database()
616- log('Triggering remote cloud-compute restarts.')
617- [compute_joined(rid=rid, remote_restart=True)
618- for rid in relation_ids('cloud-compute')]
619-
620
621 @hooks.hook('image-service-relation-changed')
622 @restart_on_change(restart_map())
623@@ -211,6 +266,8 @@
624 cfg = {
625 'auth_host': ks_auth_host,
626 'auth_port': auth_token_config('auth_port'),
627+ 'auth_protocol': auth_token_config('auth_protocol'),
628+ 'service_protocol': auth_token_config('service_protocol'),
629 'service_port': auth_token_config('service_port'),
630 'service_username': auth_token_config('admin_user'),
631 'service_password': auth_token_config('admin_password'),
632@@ -226,7 +283,8 @@
633 def save_novarc():
634 auth = _auth_config()
635 # XXX hard-coded http
636- ks_url = 'http://%s:%s/v2.0' % (auth['auth_host'], auth['auth_port'])
637+ ks_url = '%s://%s:%s/v2.0' % (auth['auth_protocol'],
638+ auth['auth_host'], auth['auth_port'])
639 with open('/etc/quantum/novarc', 'wb') as out:
640 out.write('export OS_USERNAME=%s\n' % auth['service_username'])
641 out.write('export OS_PASSWORD=%s\n' % auth['service_password'])
642@@ -385,7 +443,9 @@
643 'identity-service-relation-broken',
644 'image-service-relation-broken',
645 'nova-volume-service-relation-broken',
646- 'shared-db-relation-broken'
647+ 'shared-db-relation-broken',
648+ 'pgsql-nova-db-relation-broken',
649+ 'pgsql-neutron-db-relation-broken',
650 'quantum-network-service-relation-broken')
651 def relation_broken():
652 CONFIGS.write_all()
653@@ -436,6 +496,8 @@
654 def upgrade_charm():
655 for r_id in relation_ids('amqp'):
656 amqp_joined(relation_id=r_id)
657+ for r_id in relation_ids('identity-service'):
658+ identity_joined(rid=r_id)
659
660
661 def main():
662
663=== modified file 'hooks/nova_cc_utils.py'
664--- hooks/nova_cc_utils.py 2014-04-11 12:08:46 +0000
665+++ hooks/nova_cc_utils.py 2014-04-16 09:26:11 +0000
666@@ -22,8 +22,9 @@
667 save_script_rc as _save_script_rc)
668
669 from charmhelpers.fetch import (
670+ apt_upgrade,
671+ apt_update,
672 apt_install,
673- apt_update,
674 )
675
676 from charmhelpers.core.hookenv import (
677@@ -36,6 +37,10 @@
678 ERROR,
679 )
680
681+from charmhelpers.core.host import (
682+ service_start
683+)
684+
685
686 import nova_cc_context
687
688@@ -49,6 +54,7 @@
689 'haproxy',
690 'python-keystoneclient',
691 'python-mysqldb',
692+ 'python-psycopg2',
693 'uuid',
694 ]
695
696@@ -69,11 +75,15 @@
697 'quantum-server': 9696,
698 }
699
700-NOVA_CONF = '/etc/nova/nova.conf'
701-NOVA_API_PASTE = '/etc/nova/api-paste.ini'
702-QUANTUM_CONF = '/etc/quantum/quantum.conf'
703-QUANTUM_API_PASTE = '/etc/quantum/api-paste.ini'
704-NEUTRON_CONF = '/etc/neutron/neutron.conf'
705+NOVA_CONF_DIR = "/etc/nova"
706+QUANTUM_CONF_DIR = "/etc/quantum"
707+NEUTRON_CONF_DIR = "/etc/neutron"
708+
709+NOVA_CONF = '%s/nova.conf' % NOVA_CONF_DIR
710+NOVA_API_PASTE = '%s/api-paste.ini' % NOVA_CONF_DIR
711+QUANTUM_CONF = '%s/quantum.conf' % QUANTUM_CONF_DIR
712+QUANTUM_API_PASTE = '%s/api-paste.ini' % QUANTUM_CONF_DIR
713+NEUTRON_CONF = '%s/neutron.conf' % NEUTRON_CONF_DIR
714 HAPROXY_CONF = '/etc/haproxy/haproxy.cfg'
715 APACHE_CONF = '/etc/apache2/sites-available/openstack_https_frontend'
716 APACHE_24_CONF = '/etc/apache2/sites-available/openstack_https_frontend.conf'
717@@ -83,8 +93,10 @@
718 BASE_RESOURCE_MAP = OrderedDict([
719 (NOVA_CONF, {
720 'services': BASE_SERVICES,
721- 'contexts': [context.AMQPContext(),
722- context.SharedDBContext(relation_prefix='nova'),
723+ 'contexts': [context.AMQPContext(ssl_dir=NOVA_CONF_DIR),
724+ context.SharedDBContext(
725+ relation_prefix='nova', ssl_dir=NOVA_CONF_DIR),
726+ nova_cc_context.NovaPostgresqlDBContext(),
727 context.ImageServiceContext(),
728 context.OSConfigFlagContext(),
729 context.SubordinateConfigContext(
730@@ -104,11 +116,17 @@
731 }),
732 (QUANTUM_CONF, {
733 'services': ['quantum-server'],
734- 'contexts': [context.AMQPContext(),
735- context.SyslogContext(),
736+ 'contexts': [context.AMQPContext(ssl_dir=QUANTUM_CONF_DIR),
737+ context.SharedDBContext(
738+ user=config('neutron-database-user'),
739+ database=config('neutron-database'),
740+ relation_prefix='neutron',
741+ ssl_dir=QUANTUM_CONF_DIR),
742+ nova_cc_context.NeutronPostgresqlDBContext(),
743 nova_cc_context.HAProxyContext(),
744 nova_cc_context.IdentityServiceContext(),
745- nova_cc_context.NeutronCCContext()],
746+ nova_cc_context.NeutronCCContext(),
747+ context.SyslogContext()],
748 }),
749 (QUANTUM_DEFAULT, {
750 'services': ['quantum-server'],
751@@ -120,11 +138,17 @@
752 }),
753 (NEUTRON_CONF, {
754 'services': ['neutron-server'],
755- 'contexts': [context.AMQPContext(),
756- context.SyslogContext(),
757+ 'contexts': [context.AMQPContext(ssl_dir=NEUTRON_CONF_DIR),
758+ context.SharedDBContext(
759+ user=config('neutron-database-user'),
760+ database=config('neutron-database'),
761+ relation_prefix='neutron',
762+ ssl_dir=NEUTRON_CONF_DIR),
763+ nova_cc_context.NeutronPostgresqlDBContext(),
764 nova_cc_context.IdentityServiceContext(),
765 nova_cc_context.NeutronCCContext(),
766- nova_cc_context.HAProxyContext()],
767+ nova_cc_context.HAProxyContext(),
768+ context.SyslogContext()],
769 }),
770 (NEUTRON_DEFAULT, {
771 'services': ['neutron-server'],
772@@ -195,6 +219,10 @@
773 resource_map[conf]['contexts'].append(
774 nova_cc_context.NeutronCCContext())
775
776+ # update for postgres
777+ resource_map[conf]['contexts'].append(
778+ nova_cc_context.NeutronPostgresqlDBContext())
779+
780 # nova-conductor for releases >= G.
781 if os_release('nova-common') not in ['essex', 'folsom']:
782 resource_map['/etc/nova/nova.conf']['services'] += ['nova-conductor']
783@@ -211,8 +239,8 @@
784 return resource_map
785
786
787-def register_configs():
788- release = os_release('nova-common')
789+def register_configs(release=None):
790+ release = release or os_release('nova-common')
791 configs = templating.OSConfigRenderer(templates_dir=TEMPLATES,
792 openstack_release=release)
793 for cfg, rscs in resource_map().iteritems():
794@@ -226,10 +254,18 @@
795 if v['services']])
796
797
798+def services():
799+ ''' Returns a list of services associate with this charm '''
800+ _services = []
801+ for v in restart_map().values():
802+ _services = _services + v
803+ return list(set(_services))
804+
805+
806 def determine_ports():
807 '''Assemble a list of API ports for services we are managing'''
808 ports = []
809- for cfg, services in restart_map().iteritems():
810+ for services in restart_map().values():
811 for service in services:
812 try:
813 ports.append(API_PORTS[service])
814@@ -245,7 +281,7 @@
815 def determine_packages():
816 # currently all packages match service names
817 packages = [] + BASE_PACKAGES
818- for k, v in resource_map().iteritems():
819+ for v in resource_map().values():
820 packages.extend(v['services'])
821 if network_manager() in ['neutron', 'quantum']:
822 pkgs = neutron_plugin_attribute(neutron_plugin(), 'server_packages',
823@@ -273,27 +309,162 @@
824 _save_script_rc(**env_vars)
825
826
827-def do_openstack_upgrade(configs):
828- new_src = config('openstack-origin')
829+def get_step_upgrade_source(new_src):
830+ '''
831+ Determine if upgrade skips a release and, if so, return source
832+ of skipped release.
833+ '''
834+ sources = {
835+ # target_src: (cur_pocket, step_src)
836+ 'cloud:precise-icehouse':
837+ ('precise-updates/grizzly', 'cloud:precise-havana'),
838+ 'cloud:precise-icehouse/proposed':
839+ ('precise-proposed/grizzly', 'cloud:precise-havana/proposed')
840+ }
841+
842+ with open('/etc/apt/sources.list.d/cloud-archive.list', 'r') as f:
843+ line = f.readline()
844+ for target_src, (cur_pocket, step_src) in sources.items():
845+ if target_src != new_src:
846+ continue
847+ if cur_pocket in line:
848+ return step_src
849+
850+ return None
851+
852+POLICY_RC_D = """#!/bin/bash
853+
854+set -e
855+
856+case $1 in
857+ neutron-server|quantum-server|nova-*)
858+ [ $2 = "start" ] && exit 101
859+ ;;
860+ *)
861+ ;;
862+esac
863+
864+exit 0
865+"""
866+
867+
868+def enable_policy_rcd():
869+ with open('/usr/sbin/policy-rc.d', 'w') as policy:
870+ policy.write(POLICY_RC_D)
871+ os.chmod('/usr/sbin/policy-rc.d', 0o755)
872+
873+
874+def disable_policy_rcd():
875+ os.unlink('/usr/sbin/policy-rc.d')
876+
877+
878+QUANTUM_DB_MANAGE = "/usr/bin/quantum-db-manage"
879+NEUTRON_DB_MANAGE = "/usr/bin/neutron-db-manage"
880+
881+
882+def reset_os_release():
883+ # Ugly hack to make os_release re-read versions
884+ import charmhelpers.contrib.openstack.utils as utils
885+ utils.os_rel = None
886+
887+
888+def neutron_db_manage(actions):
889+ net_manager = network_manager()
890+ if net_manager in ['neutron', 'quantum']:
891+ plugin = neutron_plugin()
892+ conf = neutron_plugin_attribute(plugin, 'config', net_manager)
893+ if net_manager == 'quantum':
894+ cmd = QUANTUM_DB_MANAGE
895+ else:
896+ cmd = NEUTRON_DB_MANAGE
897+ subprocess.check_call([
898+ cmd, '--config-file=/etc/{mgr}/{mgr}.conf'.format(mgr=net_manager),
899+ '--config-file={}'.format(conf)] + actions
900+ )
901+
902+
903+def get_db_connection():
904+ config = ConfigParser.RawConfigParser()
905+ config.read('/etc/neutron/neutron.conf')
906+ try:
907+ return config.get('database', 'connection')
908+ except:
909+ return None
910+
911+
912+def ml2_migration():
913+ reset_os_release()
914+ net_manager = network_manager()
915+ if net_manager == 'neutron':
916+ plugin = neutron_plugin()
917+ if plugin == 'ovs':
918+ log('Migrating from openvswitch to ml2 plugin')
919+ cmd = [
920+ 'python',
921+ '/usr/lib/python2.7/dist-packages/neutron'
922+ '/db/migration/migrate_to_ml2.py',
923+ '--tunnel-type', 'gre',
924+ '--release', 'icehouse',
925+ 'openvswitch', get_db_connection()
926+ ]
927+ subprocess.check_call(cmd)
928+
929+
930+def _do_openstack_upgrade(new_src):
931+ enable_policy_rcd()
932+ cur_os_rel = os_release('nova-common')
933 new_os_rel = get_os_codename_install_source(new_src)
934 log('Performing OpenStack upgrade to %s.' % (new_os_rel))
935
936 configure_installation_source(new_src)
937- apt_update()
938-
939 dpkg_opts = [
940 '--option', 'Dpkg::Options::=--force-confnew',
941 '--option', 'Dpkg::Options::=--force-confdef',
942 ]
943
944- apt_install(packages=determine_packages(), options=dpkg_opts, fatal=True)
945-
946- # set CONFIGS to load templates from new release and regenerate config
947- configs.set_release(openstack_release=new_os_rel)
948- configs.write_all()
949+ # NOTE(jamespage) pre-stamp neutron database before upgrade from grizzly
950+ if cur_os_rel == 'grizzly':
951+ neutron_db_manage(['stamp', 'grizzly'])
952+
953+ apt_update(fatal=True)
954+ apt_upgrade(options=dpkg_opts, fatal=True, dist=True)
955+ apt_install(determine_packages(), fatal=True)
956+
957+ if cur_os_rel == 'grizzly':
958+ # NOTE(jamespage) when upgrading from grizzly->havana, config
959+ # files need to be generated prior to performing the db upgrade
960+ reset_os_release()
961+ configs = register_configs(release=new_os_rel)
962+ configs.write_all()
963+ neutron_db_manage(['upgrade', 'head'])
964+ else:
965+ # NOTE(jamespage) upgrade with existing config files as the
966+ # havana->icehouse migration enables new service_plugins which
967+ # create issues with db upgrades
968+ neutron_db_manage(['upgrade', 'head'])
969+ reset_os_release()
970+ configs = register_configs(release=new_os_rel)
971+ configs.write_all()
972+
973+ if new_os_rel == 'icehouse':
974+ # NOTE(jamespage) default plugin switch to ml2@icehouse
975+ ml2_migration()
976
977 if eligible_leader(CLUSTER_RES):
978 migrate_database()
979+ [service_start(s) for s in services()]
980+
981+ disable_policy_rcd()
982+
983+ return configs
984+
985+
986+def do_openstack_upgrade():
987+ new_src = config('openstack-origin')
988+ step_src = get_step_upgrade_source(new_src)
989+ if step_src is not None:
990+ _do_openstack_upgrade(step_src)
991+ return _do_openstack_upgrade(new_src)
992
993
994 def volume_service():
995@@ -315,10 +486,10 @@
996
997
998 def auth_token_config(setting):
999- '''
1000+ """
1001 Returns currently configured value for setting in api-paste.ini's
1002 authtoken section, or None.
1003- '''
1004+ """
1005 config = ConfigParser.RawConfigParser()
1006 config.read('/etc/nova/api-paste.ini')
1007 try:
1008@@ -363,7 +534,10 @@
1009
1010 def ssh_known_host_key(host, user=None):
1011 cmd = ['ssh-keygen', '-f', known_hosts(user), '-H', '-F', host]
1012- return subprocess.check_output(cmd).strip()
1013+ try:
1014+ return subprocess.check_output(cmd).strip()
1015+ except subprocess.CalledProcessError:
1016+ return None
1017
1018
1019 def remove_known_host(host, user=None):
1020@@ -459,10 +633,14 @@
1021 '''Generates a dictionary containing all relevant endpoints to be
1022 passed to keystone as relation settings.'''
1023 region = config('region')
1024+ os_rel = os_release('nova-common')
1025
1026- # TODO: Configurable nova API version.
1027- nova_url = ('%s:%s/v1.1/$(tenant_id)s' %
1028- (url, api_port('nova-api-os-compute')))
1029+ if os_rel >= 'grizzly':
1030+ nova_url = ('%s:%s/v2/$(tenant_id)s' %
1031+ (url, api_port('nova-api-os-compute')))
1032+ else:
1033+ nova_url = ('%s:%s/v1.1/$(tenant_id)s' %
1034+ (url, api_port('nova-api-os-compute')))
1035 ec2_url = '%s:%s/services/Cloud' % (url, api_port('nova-api-ec2'))
1036 nova_volume_url = ('%s:%s/v1/$(tenant_id)s' %
1037 (url, api_port('nova-api-os-compute')))
1038
1039=== added symlink 'hooks/pgsql-neutron-db-relation-broken'
1040=== target is u'nova_cc_hooks.py'
1041=== added symlink 'hooks/pgsql-neutron-db-relation-changed'
1042=== target is u'nova_cc_hooks.py'
1043=== added symlink 'hooks/pgsql-neutron-db-relation-joined'
1044=== target is u'nova_cc_hooks.py'
1045=== added symlink 'hooks/pgsql-nova-db-relation-broken'
1046=== target is u'nova_cc_hooks.py'
1047=== added symlink 'hooks/pgsql-nova-db-relation-changed'
1048=== target is u'nova_cc_hooks.py'
1049=== added symlink 'hooks/pgsql-nova-db-relation-joined'
1050=== target is u'nova_cc_hooks.py'
1051=== modified file 'metadata.yaml'
1052--- metadata.yaml 2013-10-16 19:00:25 +0000
1053+++ metadata.yaml 2014-04-16 09:26:11 +0000
1054@@ -12,6 +12,10 @@
1055 requires:
1056 shared-db:
1057 interface: mysql-shared
1058+ pgsql-nova-db:
1059+ interface: pgsql
1060+ pgsql-neutron-db:
1061+ interface: pgsql
1062 amqp:
1063 interface: rabbitmq
1064 image-service:
1065
1066=== added file 'setup.cfg'
1067--- setup.cfg 1970-01-01 00:00:00 +0000
1068+++ setup.cfg 2014-04-16 09:26:11 +0000
1069@@ -0,0 +1,5 @@
1070+[nosetests]
1071+verbosity=2
1072+with-coverage=1
1073+cover-erase=1
1074+cover-package=hooks
1075
1076=== modified file 'templates/essex/nova.conf'
1077--- templates/essex/nova.conf 2014-03-25 18:44:23 +0000
1078+++ templates/essex/nova.conf 2014-04-16 09:26:11 +0000
1079@@ -17,7 +17,7 @@
1080 --use_syslog={{ use_syslog }}
1081 --ec2_private_dns_show_ip
1082 {% if database_host -%}
1083---sql_connection=mysql://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}
1084+--sql_connection={{ database_type }}://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}
1085 {% endif -%}
1086 {% if rabbitmq_host -%}
1087 --rabbit_host={{ rabbitmq_host }}
1088
1089=== modified file 'templates/folsom/nova.conf'
1090--- templates/folsom/nova.conf 2014-03-25 18:44:23 +0000
1091+++ templates/folsom/nova.conf 2014-04-16 09:26:11 +0000
1092@@ -25,11 +25,16 @@
1093 keystone_ec2_url = {{ keystone_ec2_url }}
1094 {% endif -%}
1095
1096-{% if database_host -%}
1097-sql_connection = mysql://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}
1098-{% endif -%}
1099+{% include "parts/database" %}
1100
1101 {% if rabbitmq_host -%}
1102+{% if rabbit_ssl_port %}
1103+rabbit_use_ssl=True
1104+rabbit_port={{ rabbit_ssl_port }}
1105+{% if rabbit_ssl_ca %}
1106+kombu_ssl_ca_certs={{rabbit_ssl_ca}}
1107+{% endif %}
1108+{% endif %}
1109 rabbit_host = {{ rabbitmq_host }}
1110 rabbit_userid = {{ rabbitmq_user }}
1111 rabbit_password = {{ rabbitmq_password }}
1112
1113=== modified file 'templates/folsom/ovs_quantum_plugin.ini'
1114--- templates/folsom/ovs_quantum_plugin.ini 2014-03-26 11:49:01 +0000
1115+++ templates/folsom/ovs_quantum_plugin.ini 2014-04-16 09:26:11 +0000
1116@@ -11,7 +11,7 @@
1117
1118 [DATABASE]
1119 {% if database_host -%}
1120-sql_connection = mysql://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}?quantum?charset=utf8
1121+sql_connection = {{ database_type }}://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}{% if database_ssl_ca %}?ssl_ca={{ database_ssl_ca }}{% if database_ssl_cert %}&ssl_cert={{ database_ssl_cert }}&ssl_key={{ database_ssl_key }}{% endif %}{% endif %}
1122 reconnect_interval = 2
1123 {% else -%}
1124 connection = sqlite:////var/lib/quantum/quantum.sqlite
1125
1126=== added file 'templates/grizzly/nova.conf'
1127--- templates/grizzly/nova.conf 1970-01-01 00:00:00 +0000
1128+++ templates/grizzly/nova.conf 2014-04-16 09:26:11 +0000
1129@@ -0,0 +1,115 @@
1130+###############################################################################
1131+# [ WARNING ]
1132+# Configuration file maintained by Juju. Local changes may be overwritten.
1133+###############################################################################
1134+[DEFAULT]
1135+dhcpbridge_flagfile=/etc/nova/nova.conf
1136+dhcpbridge=/usr/bin/nova-dhcpbridge
1137+logdir=/var/log/nova
1138+state_path=/var/lib/nova
1139+lock_path=/var/lock/nova
1140+force_dhcp_release=True
1141+iscsi_helper=tgtadm
1142+libvirt_use_virtio_for_bridges=True
1143+connection_type=libvirt
1144+root_helper=sudo nova-rootwrap /etc/nova/rootwrap.conf
1145+verbose=True
1146+ec2_private_dns_show_ip=True
1147+api_paste_config=/etc/nova/api-paste.ini
1148+volumes_path=/var/lib/nova/volumes
1149+enabled_apis=ec2,osapi_compute,metadata
1150+auth_strategy=keystone
1151+compute_driver=libvirt.LibvirtDriver
1152+{% if keystone_ec2_url -%}
1153+keystone_ec2_url = {{ keystone_ec2_url }}
1154+{% endif -%}
1155+
1156+{% include "parts/database" %}
1157+
1158+{% include "parts/rabbitmq" %}
1159+
1160+{% if glance_api_servers -%}
1161+glance_api_servers = {{ glance_api_servers }}
1162+{% endif -%}
1163+
1164+{% if rbd_pool -%}
1165+rbd_pool = {{ rbd_pool }}
1166+rbd_user = {{ rbd_user }}
1167+rbd_secret_uuid = {{ rbd_secret_uuid }}
1168+{% endif -%}
1169+
1170+{% if neutron_plugin and neutron_plugin == 'ovs' -%}
1171+libvirt_vif_driver = nova.virt.libvirt.vif.LibvirtGenericVIFDriver
1172+libvirt_user_virtio_for_bridges = True
1173+{% if neutron_security_groups -%}
1174+security_group_api = {{ network_manager }}
1175+nova_firewall_driver = nova.virt.firewall.NoopFirewallDriver
1176+{% endif -%}
1177+{% if external_network -%}
1178+default_floating_pool = {{ external_network }}
1179+{% endif -%}
1180+{% endif -%}
1181+
1182+{% if neutron_plugin and neutron_plugin == 'nvp' -%}
1183+security_group_api = neutron
1184+nova_firewall_driver = nova.virt.firewall.NoopFirewallDriver
1185+{% if external_network -%}
1186+default_floating_pool = {{ external_network }}
1187+{% endif -%}
1188+{% endif -%}
1189+
1190+{% if network_manager_config -%}
1191+{% for key, value in network_manager_config.iteritems() -%}
1192+{{ key }} = {{ value }}
1193+{% endfor -%}
1194+{% endif -%}
1195+
1196+{% if network_manager and network_manager == 'quantum' -%}
1197+network_api_class = nova.network.quantumv2.api.API
1198+quantum_url = {{ neutron_url }}
1199+{% if auth_host -%}
1200+quantum_auth_strategy = keystone
1201+quantum_admin_tenant_name = {{ admin_tenant_name }}
1202+quantum_admin_username = {{ admin_user }}
1203+quantum_admin_password = {{ admin_password }}
1204+quantum_admin_auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}/v2.0
1205+{% endif -%}
1206+{% elif network_manager and network_manager == 'neutron' -%}
1207+network_api_class = nova.network.neutronv2.api.API
1208+neutron_url = {{ neutron_url }}
1209+{% if auth_host -%}
1210+neutron_auth_strategy = keystone
1211+neutron_admin_tenant_name = {{ admin_tenant_name }}
1212+neutron_admin_username = {{ admin_user }}
1213+neutron_admin_password = {{ admin_password }}
1214+neutron_admin_auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}/v2.0
1215+{% endif -%}
1216+{% else -%}
1217+network_manager = nova.network.manager.FlatDHCPManager
1218+{% endif -%}
1219+
1220+{% if default_floating_pool -%}
1221+default_floating_pool = {{ default_floating_pool }}
1222+{% endif -%}
1223+
1224+{% if volume_service -%}
1225+volume_api_class=nova.volume.cinder.API
1226+{% endif -%}
1227+
1228+{% if user_config_flags -%}
1229+{% for key, value in user_config_flags.iteritems() -%}
1230+{{ key }} = {{ value }}
1231+{% endfor -%}
1232+{% endif -%}
1233+
1234+{% if listen_ports -%}
1235+{% for key, value in listen_ports.iteritems() -%}
1236+{{ key }} = {{ value }}
1237+{% endfor -%}
1238+{% endif -%}
1239+
1240+{% if sections and 'DEFAULT' in sections -%}
1241+{% for key, value in sections['DEFAULT'] -%}
1242+{{ key }} = {{ value }}
1243+{% endfor -%}
1244+{% endif -%}
1245
1246=== added file 'templates/grizzly/quantum.conf'
1247--- templates/grizzly/quantum.conf 1970-01-01 00:00:00 +0000
1248+++ templates/grizzly/quantum.conf 2014-04-16 09:26:11 +0000
1249@@ -0,0 +1,45 @@
1250+# grizzly
1251+###############################################################################
1252+# [ WARNING ]
1253+# Configuration file maintained by Juju. Local changes may be overwritten.
1254+###############################################################################
1255+[DEFAULT]
1256+state_path = /var/lib/quantum
1257+lock_path = $state_path/lock
1258+bind_host = 0.0.0.0
1259+{% if neutron_bind_port -%}
1260+bind_port = {{ neutron_bind_port }}
1261+{% else -%}
1262+bind_port = 9696
1263+{% endif -%}
1264+{% if core_plugin -%}
1265+core_plugin = {{ core_plugin }}
1266+{% endif -%}
1267+api_paste_config = /etc/quantum/api-paste.ini
1268+auth_strategy = keystone
1269+control_exchange = quantum
1270+notification_driver = quantum.openstack.common.notifier.rpc_notifier
1271+default_notification_level = INFO
1272+notification_topics = notifications
1273+
1274+{% include "parts/database" %}
1275+
1276+{% include "parts/rabbitmq" %}
1277+
1278+{% if neutron_security_groups -%}
1279+allow_overlapping_ips = True
1280+{% endif -%}
1281+
1282+[QUOTAS]
1283+quota_driver = quantum.db.quota_db.DbQuotaDriver
1284+{% if neutron_security_groups -%}
1285+quota_items = network,subnet,port,security_group,security_group_rule
1286+{% endif -%}
1287+
1288+[DEFAULT_SERVICETYPE]
1289+
1290+[AGENT]
1291+root_helper = sudo quantum-rootwrap /etc/quantum/rootwrap.conf
1292+
1293+[keystone_authtoken]
1294+# auth_token middleware currently set in /etc/quantum/api-paste.ini
1295
1296=== modified file 'templates/havana/neutron.conf'
1297--- templates/havana/neutron.conf 2014-03-25 18:44:23 +0000
1298+++ templates/havana/neutron.conf 2014-04-16 09:26:11 +0000
1299@@ -16,17 +16,16 @@
1300 {% endif -%}
1301 {% if core_plugin -%}
1302 core_plugin = {{ core_plugin }}
1303+{% if neutron_plugin in ['ovs', 'ml2'] -%}
1304+service_plugins = neutron.services.metering.metering_plugin.MeteringPlugin
1305+{% endif -%}
1306 {% endif -%}
1307 {% if neutron_security_groups -%}
1308 allow_overlapping_ips = True
1309 neutron_firewall_driver = neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver
1310 {% endif -%}
1311-{% if rabbitmq_host -%}
1312-rabbit_host = {{ rabbitmq_host }}
1313-rabbit_userid = {{ rabbitmq_user }}
1314-rabbit_password = {{ rabbitmq_password }}
1315-rabbit_virtual_host = {{ rabbitmq_virtual_host }}
1316-{% endif -%}
1317+
1318+{% include "parts/rabbitmq" %}
1319
1320 [quotas]
1321 quota_driver = neutron.db.quota_db.DbQuotaDriver
1322@@ -51,5 +50,7 @@
1323 admin_password = {{ admin_password }}
1324 {% endif -%}
1325
1326+{% include "parts/section-database" %}
1327+
1328 [lbaas]
1329 [service_providers]
1330
1331=== added file 'templates/havana/nova.conf'
1332--- templates/havana/nova.conf 1970-01-01 00:00:00 +0000
1333+++ templates/havana/nova.conf 2014-04-16 09:26:11 +0000
1334@@ -0,0 +1,119 @@
1335+###############################################################################
1336+# [ WARNING ]
1337+# Configuration file maintained by Juju. Local changes may be overwritten.
1338+###############################################################################
1339+[DEFAULT]
1340+dhcpbridge_flagfile=/etc/nova/nova.conf
1341+dhcpbridge=/usr/bin/nova-dhcpbridge
1342+logdir=/var/log/nova
1343+state_path=/var/lib/nova
1344+lock_path=/var/lock/nova
1345+force_dhcp_release=True
1346+iscsi_helper=tgtadm
1347+libvirt_use_virtio_for_bridges=True
1348+connection_type=libvirt
1349+root_helper=sudo nova-rootwrap /etc/nova/rootwrap.conf
1350+verbose=True
1351+ec2_private_dns_show_ip=True
1352+api_paste_config=/etc/nova/api-paste.ini
1353+volumes_path=/var/lib/nova/volumes
1354+enabled_apis=ec2,osapi_compute,metadata
1355+auth_strategy=keystone
1356+compute_driver=libvirt.LibvirtDriver
1357+{% if keystone_ec2_url -%}
1358+keystone_ec2_url = {{ keystone_ec2_url }}
1359+{% endif -%}
1360+
1361+{% include "parts/database" %}
1362+
1363+{% include "parts/rabbitmq" %}
1364+
1365+{% if glance_api_servers -%}
1366+glance_api_servers = {{ glance_api_servers }}
1367+{% endif -%}
1368+
1369+{% if rbd_pool -%}
1370+rbd_pool = {{ rbd_pool }}
1371+rbd_user = {{ rbd_user }}
1372+rbd_secret_uuid = {{ rbd_secret_uuid }}
1373+{% endif -%}
1374+
1375+{% if neutron_plugin and neutron_plugin == 'ovs' -%}
1376+libvirt_vif_driver = nova.virt.libvirt.vif.LibvirtGenericVIFDriver
1377+libvirt_user_virtio_for_bridges = True
1378+{% if neutron_security_groups -%}
1379+security_group_api = {{ network_manager }}
1380+nova_firewall_driver = nova.virt.firewall.NoopFirewallDriver
1381+{% endif -%}
1382+{% if external_network -%}
1383+default_floating_pool = {{ external_network }}
1384+{% endif -%}
1385+{% endif -%}
1386+
1387+{% if neutron_plugin and neutron_plugin == 'nvp' -%}
1388+security_group_api = neutron
1389+nova_firewall_driver = nova.virt.firewall.NoopFirewallDriver
1390+{% if external_network -%}
1391+default_floating_pool = {{ external_network }}
1392+{% endif -%}
1393+{% endif -%}
1394+
1395+{% if network_manager_config -%}
1396+{% for key, value in network_manager_config.iteritems() -%}
1397+{{ key }} = {{ value }}
1398+{% endfor -%}
1399+{% endif -%}
1400+
1401+{% if network_manager and network_manager == 'quantum' -%}
1402+network_api_class = nova.network.quantumv2.api.API
1403+quantum_url = {{ neutron_url }}
1404+{% if auth_host -%}
1405+quantum_auth_strategy = keystone
1406+quantum_admin_tenant_name = {{ admin_tenant_name }}
1407+quantum_admin_username = {{ admin_user }}
1408+quantum_admin_password = {{ admin_password }}
1409+quantum_admin_auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}/v2.0
1410+{% endif -%}
1411+{% elif network_manager and network_manager == 'neutron' -%}
1412+network_api_class = nova.network.neutronv2.api.API
1413+neutron_url = {{ neutron_url }}
1414+{% if auth_host -%}
1415+neutron_auth_strategy = keystone
1416+neutron_admin_tenant_name = {{ admin_tenant_name }}
1417+neutron_admin_username = {{ admin_user }}
1418+neutron_admin_password = {{ admin_password }}
1419+neutron_admin_auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}/v2.0
1420+{% endif -%}
1421+{% else -%}
1422+network_manager = nova.network.manager.FlatDHCPManager
1423+{% endif -%}
1424+
1425+{% if default_floating_pool -%}
1426+default_floating_pool = {{ default_floating_pool }}
1427+{% endif -%}
1428+
1429+{% if volume_service -%}
1430+volume_api_class=nova.volume.cinder.API
1431+{% endif -%}
1432+
1433+{% if user_config_flags -%}
1434+{% for key, value in user_config_flags.iteritems() -%}
1435+{{ key }} = {{ value }}
1436+{% endfor -%}
1437+{% endif -%}
1438+
1439+{% if listen_ports -%}
1440+{% for key, value in listen_ports.iteritems() -%}
1441+{{ key }} = {{ value }}
1442+{% endfor -%}
1443+{% endif -%}
1444+
1445+{% if sections and 'DEFAULT' in sections -%}
1446+{% for key, value in sections['DEFAULT'] -%}
1447+{{ key }} = {{ value }}
1448+{% endfor -%}
1449+{% endif -%}
1450+
1451+[osapi_v3]
1452+enabled=True
1453+
1454
1455=== modified file 'templates/havana/nvp.ini'
1456--- templates/havana/nvp.ini 2014-03-26 11:49:01 +0000
1457+++ templates/havana/nvp.ini 2014-04-16 09:26:11 +0000
1458@@ -9,10 +9,3 @@
1459 nvp_controllers = {{ nvp_controllers }}
1460 default_tz_uuid = {{ nvp_tz_uuid }}
1461 default_l3_gw_service_uuid = {{ nvp_l3_uuid }}
1462-
1463-[database]
1464-{% if database_host -%}
1465-connection = mysql://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}
1466-{% else -%}
1467-connection = sqlite:////var/lib/neutron/neutron.sqlite
1468-{% endif -%}
1469
1470=== modified file 'templates/havana/ovs_neutron_plugin.ini'
1471--- templates/havana/ovs_neutron_plugin.ini 2014-03-26 11:49:01 +0000
1472+++ templates/havana/ovs_neutron_plugin.ini 2014-04-16 09:26:11 +0000
1473@@ -4,13 +4,6 @@
1474 enable_tunneling = True
1475 local_ip = {{ local_ip }}
1476
1477-[database]
1478-{% if database_host -%}
1479-connection = mysql://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}
1480-{% else -%}
1481-connection = sqlite:////var/lib/neutron/neutron.sqlite
1482-{% endif -%}
1483-
1484 [securitygroup]
1485 {% if neutron_security_groups -%}
1486 firewall_driver = neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver
1487
1488=== added directory 'templates/icehouse'
1489=== added file 'templates/icehouse/etc_nova_api-paste.ini'
1490--- templates/icehouse/etc_nova_api-paste.ini 1970-01-01 00:00:00 +0000
1491+++ templates/icehouse/etc_nova_api-paste.ini 2014-04-16 09:26:11 +0000
1492@@ -0,0 +1,124 @@
1493+############
1494+# Metadata #
1495+############
1496+[composite:metadata]
1497+use = egg:Paste#urlmap
1498+/: meta
1499+
1500+[pipeline:meta]
1501+pipeline = ec2faultwrap logrequest metaapp
1502+
1503+[app:metaapp]
1504+paste.app_factory = nova.api.metadata.handler:MetadataRequestHandler.factory
1505+
1506+#######
1507+# EC2 #
1508+#######
1509+
1510+[composite:ec2]
1511+use = egg:Paste#urlmap
1512+/services/Cloud: ec2cloud
1513+
1514+[composite:ec2cloud]
1515+use = call:nova.api.auth:pipeline_factory
1516+noauth = ec2faultwrap logrequest ec2noauth cloudrequest validator ec2executor
1517+keystone = ec2faultwrap logrequest ec2keystoneauth cloudrequest validator ec2executor
1518+
1519+[filter:ec2faultwrap]
1520+paste.filter_factory = nova.api.ec2:FaultWrapper.factory
1521+
1522+[filter:logrequest]
1523+paste.filter_factory = nova.api.ec2:RequestLogging.factory
1524+
1525+[filter:ec2lockout]
1526+paste.filter_factory = nova.api.ec2:Lockout.factory
1527+
1528+[filter:ec2keystoneauth]
1529+paste.filter_factory = nova.api.ec2:EC2KeystoneAuth.factory
1530+
1531+[filter:ec2noauth]
1532+paste.filter_factory = nova.api.ec2:NoAuth.factory
1533+
1534+[filter:cloudrequest]
1535+controller = nova.api.ec2.cloud.CloudController
1536+paste.filter_factory = nova.api.ec2:Requestify.factory
1537+
1538+[filter:authorizer]
1539+paste.filter_factory = nova.api.ec2:Authorizer.factory
1540+
1541+[filter:validator]
1542+paste.filter_factory = nova.api.ec2:Validator.factory
1543+
1544+[app:ec2executor]
1545+paste.app_factory = nova.api.ec2:Executor.factory
1546+
1547+#############
1548+# OpenStack #
1549+#############
1550+
1551+[composite:osapi_compute]
1552+use = call:nova.api.openstack.urlmap:urlmap_factory
1553+/: oscomputeversions
1554+/v1.1: openstack_compute_api_v2
1555+/v2: openstack_compute_api_v2
1556+/v3: openstack_compute_api_v3
1557+
1558+[composite:openstack_compute_api_v2]
1559+use = call:nova.api.auth:pipeline_factory
1560+noauth = faultwrap sizelimit noauth ratelimit osapi_compute_app_v2
1561+keystone = faultwrap sizelimit authtoken keystonecontext ratelimit osapi_compute_app_v2
1562+keystone_nolimit = faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v2
1563+
1564+[composite:openstack_compute_api_v3]
1565+use = call:nova.api.auth:pipeline_factory_v3
1566+noauth = faultwrap sizelimit noauth_v3 osapi_compute_app_v3
1567+keystone = faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v3
1568+
1569+[filter:faultwrap]
1570+paste.filter_factory = nova.api.openstack:FaultWrapper.factory
1571+
1572+[filter:noauth]
1573+paste.filter_factory = nova.api.openstack.auth:NoAuthMiddleware.factory
1574+
1575+[filter:noauth_v3]
1576+paste.filter_factory = nova.api.openstack.auth:NoAuthMiddlewareV3.factory
1577+
1578+[filter:ratelimit]
1579+paste.filter_factory = nova.api.openstack.compute.limits:RateLimitingMiddleware.factory
1580+
1581+[filter:sizelimit]
1582+paste.filter_factory = nova.api.sizelimit:RequestBodySizeLimiter.factory
1583+
1584+[app:osapi_compute_app_v2]
1585+paste.app_factory = nova.api.openstack.compute:APIRouter.factory
1586+
1587+[app:osapi_compute_app_v3]
1588+paste.app_factory = nova.api.openstack.compute:APIRouterV3.factory
1589+
1590+[pipeline:oscomputeversions]
1591+pipeline = faultwrap oscomputeversionapp
1592+
1593+[app:oscomputeversionapp]
1594+paste.app_factory = nova.api.openstack.compute.versions:Versions.factory
1595+
1596+##########
1597+# Shared #
1598+##########
1599+
1600+[filter:keystonecontext]
1601+paste.filter_factory = nova.api.auth:NovaKeystoneContext.factory
1602+
1603+[filter:authtoken]
1604+paste.filter_factory = keystoneclient.middleware.auth_token:filter_factory
1605+{% if service_host -%}
1606+# NOTE(jamespage) - not used - but required for relation to nova-compute
1607+service_protocol = {{ service_protocol }}
1608+service_host = {{ service_host }}
1609+service_port = {{ service_port }}
1610+auth_host = {{ auth_host }}
1611+auth_port = {{ auth_port }}
1612+auth_protocol = {{ auth_protocol }}
1613+admin_tenant_name = {{ admin_tenant_name }}
1614+admin_user = {{ admin_user }}
1615+admin_password = {{ admin_password }}
1616+{% endif -%}
1617
1618=== added file 'templates/icehouse/ml2_conf.ini'
1619--- templates/icehouse/ml2_conf.ini 1970-01-01 00:00:00 +0000
1620+++ templates/icehouse/ml2_conf.ini 2014-04-16 09:26:11 +0000
1621@@ -0,0 +1,30 @@
1622+# icehouse
1623+###############################################################################
1624+# [ WARNING ]
1625+# Configuration file maintained by Juju. Local changes may be overwritten.
1626+###############################################################################
1627+[ml2]
1628+type_drivers = gre,vxlan
1629+tenant_network_types = gre,vxlan
1630+mechanism_drivers = openvswitch
1631+
1632+[ml2_type_gre]
1633+tunnel_id_ranges = 1:1000
1634+
1635+[ml2_type_vxlan]
1636+vni_ranges = 1001:2000
1637+
1638+[ovs]
1639+enable_tunneling = True
1640+local_ip = {{ local_ip }}
1641+
1642+[agent]
1643+tunnel_types = gre
1644+
1645+[securitygroup]
1646+{% if neutron_security_groups -%}
1647+enable_security_group = True
1648+firewall_driver = neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver
1649+{% else -%}
1650+enable_security_group = False
1651+{% endif -%}
1652
1653=== added file 'templates/icehouse/neutron.conf'
1654--- templates/icehouse/neutron.conf 1970-01-01 00:00:00 +0000
1655+++ templates/icehouse/neutron.conf 2014-04-16 09:26:11 +0000
1656@@ -0,0 +1,71 @@
1657+###############################################################################
1658+# [ WARNING ]
1659+# Configuration file maintained by Juju. Local changes may be overwritten.
1660+###############################################################################
1661+[DEFAULT]
1662+state_path = /var/lib/neutron
1663+lock_path = $state_path/lock
1664+bind_host = 0.0.0.0
1665+auth_strategy = keystone
1666+notification_driver = neutron.openstack.common.notifier.rpc_notifier
1667+
1668+{% if neutron_bind_port -%}
1669+bind_port = {{ neutron_bind_port }}
1670+{% else -%}
1671+bind_port = 9696
1672+{% endif -%}
1673+
1674+{% if core_plugin -%}
1675+core_plugin = {{ core_plugin }}
1676+{% if neutron_plugin in ['ovs', 'ml2'] -%}
1677+service_plugins = neutron.services.l3_router.l3_router_plugin.L3RouterPlugin,neutron.services.firewall.fwaas_plugin.FirewallPlugin,neutron.services.loadbalancer.plugin.LoadBalancerPlugin,neutron.services.vpn.plugin.VPNDriverPlugin,neutron.services.metering.metering_plugin.MeteringPlugin
1678+{% endif -%}
1679+{% endif -%}
1680+
1681+{% if neutron_security_groups -%}
1682+allow_overlapping_ips = True
1683+neutron_firewall_driver = neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver
1684+{% endif -%}
1685+
1686+{% include "parts/rabbitmq" %}
1687+
1688+notify_nova_on_port_status_changes = True
1689+notify_nova_on_port_data_changes = True
1690+nova_url = {{ nova_url }}
1691+nova_region_name = {{ region }}
1692+{% if auth_host -%}
1693+nova_admin_username = {{ admin_user }}
1694+nova_admin_tenant_id = {{ admin_tenant_id }}
1695+nova_admin_password = {{ admin_password }}
1696+nova_admin_auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}/v2.0
1697+{% endif -%}
1698+
1699+[quotas]
1700+quota_driver = neutron.db.quota_db.DbQuotaDriver
1701+{% if neutron_security_groups -%}
1702+quota_items = network,subnet,port,security_group,security_group_rule
1703+{% endif -%}
1704+
1705+[agent]
1706+root_helper = sudo /usr/bin/neutron-rootwrap /etc/neutron/rootwrap.conf
1707+
1708+[keystone_authtoken]
1709+signing_dir = $state_path/keystone-signing
1710+{% if service_host -%}
1711+service_protocol = {{ service_protocol }}
1712+service_host = {{ service_host }}
1713+service_port = {{ service_port }}
1714+auth_host = {{ auth_host }}
1715+auth_port = {{ auth_port }}
1716+auth_protocol = {{ auth_protocol }}
1717+admin_tenant_name = {{ admin_tenant_name }}
1718+admin_user = {{ admin_user }}
1719+admin_password = {{ admin_password }}
1720+{% endif -%}
1721+
1722+{% include "parts/section-database" %}
1723+
1724+[service_providers]
1725+service_provider=LOADBALANCER:Haproxy:neutron.services.loadbalancer.drivers.haproxy.plugin_driver.HaproxyOnHostPluginDriver:default
1726+service_provider=VPN:openswan:neutron.services.vpn.service_drivers.ipsec.IPsecVPNDriver:default
1727+service_provider=FIREWALL:Iptables:neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver:default
1728\ No newline at end of file
1729
1730=== added file 'templates/icehouse/nova.conf'
1731--- templates/icehouse/nova.conf 1970-01-01 00:00:00 +0000
1732+++ templates/icehouse/nova.conf 2014-04-16 09:26:11 +0000
1733@@ -0,0 +1,130 @@
1734+###############################################################################
1735+# [ WARNING ]
1736+# Configuration file maintained by Juju. Local changes may be overwritten.
1737+###############################################################################
1738+[DEFAULT]
1739+dhcpbridge_flagfile=/etc/nova/nova.conf
1740+dhcpbridge=/usr/bin/nova-dhcpbridge
1741+logdir=/var/log/nova
1742+state_path=/var/lib/nova
1743+lock_path=/var/lock/nova
1744+force_dhcp_release=True
1745+iscsi_helper=tgtadm
1746+libvirt_use_virtio_for_bridges=True
1747+connection_type=libvirt
1748+root_helper=sudo nova-rootwrap /etc/nova/rootwrap.conf
1749+verbose=True
1750+ec2_private_dns_show_ip=True
1751+api_paste_config=/etc/nova/api-paste.ini
1752+volumes_path=/var/lib/nova/volumes
1753+enabled_apis=ec2,osapi_compute,metadata
1754+auth_strategy=keystone
1755+compute_driver=libvirt.LibvirtDriver
1756+{% if keystone_ec2_url -%}
1757+keystone_ec2_url = {{ keystone_ec2_url }}
1758+{% endif -%}
1759+
1760+{% include "parts/database" %}
1761+
1762+{% include "parts/rabbitmq" %}
1763+
1764+{% if glance_api_servers -%}
1765+glance_api_servers = {{ glance_api_servers }}
1766+{% endif -%}
1767+
1768+{% if rbd_pool -%}
1769+rbd_pool = {{ rbd_pool }}
1770+rbd_user = {{ rbd_user }}
1771+rbd_secret_uuid = {{ rbd_secret_uuid }}
1772+{% endif -%}
1773+
1774+{% if neutron_plugin and neutron_plugin == 'ovs' -%}
1775+libvirt_vif_driver = nova.virt.libvirt.vif.LibvirtGenericVIFDriver
1776+libvirt_user_virtio_for_bridges = True
1777+{% if neutron_security_groups -%}
1778+security_group_api = {{ network_manager }}
1779+nova_firewall_driver = nova.virt.firewall.NoopFirewallDriver
1780+{% endif -%}
1781+{% if external_network -%}
1782+default_floating_pool = {{ external_network }}
1783+{% endif -%}
1784+{% endif -%}
1785+
1786+{% if neutron_plugin and neutron_plugin == 'nvp' -%}
1787+security_group_api = neutron
1788+nova_firewall_driver = nova.virt.firewall.NoopFirewallDriver
1789+{% if external_network -%}
1790+default_floating_pool = {{ external_network }}
1791+{% endif -%}
1792+{% endif -%}
1793+
1794+{% if network_manager_config -%}
1795+{% for key, value in network_manager_config.iteritems() -%}
1796+{{ key }} = {{ value }}
1797+{% endfor -%}
1798+{% endif -%}
1799+
1800+{% if network_manager and network_manager == 'quantum' -%}
1801+network_api_class = nova.network.quantumv2.api.API
1802+quantum_url = {{ neutron_url }}
1803+{% if auth_host -%}
1804+quantum_auth_strategy = keystone
1805+quantum_admin_tenant_name = {{ admin_tenant_name }}
1806+quantum_admin_username = {{ admin_user }}
1807+quantum_admin_password = {{ admin_password }}
1808+quantum_admin_auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}/v2.0
1809+{% endif -%}
1810+{% elif network_manager and network_manager == 'neutron' -%}
1811+network_api_class = nova.network.neutronv2.api.API
1812+neutron_url = {{ neutron_url }}
1813+{% if auth_host -%}
1814+neutron_auth_strategy = keystone
1815+neutron_admin_tenant_name = {{ admin_tenant_name }}
1816+neutron_admin_username = {{ admin_user }}
1817+neutron_admin_password = {{ admin_password }}
1818+neutron_admin_auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}/v2.0
1819+{% endif -%}
1820+{% else -%}
1821+network_manager = nova.network.manager.FlatDHCPManager
1822+{% endif -%}
1823+
1824+{% if default_floating_pool -%}
1825+default_floating_pool = {{ default_floating_pool }}
1826+{% endif -%}
1827+
1828+{% if volume_service -%}
1829+volume_api_class=nova.volume.cinder.API
1830+{% endif -%}
1831+
1832+{% if user_config_flags -%}
1833+{% for key, value in user_config_flags.iteritems() -%}
1834+{{ key }} = {{ value }}
1835+{% endfor -%}
1836+{% endif -%}
1837+
1838+{% if listen_ports -%}
1839+{% for key, value in listen_ports.iteritems() -%}
1840+{{ key }} = {{ value }}
1841+{% endfor -%}
1842+{% endif -%}
1843+
1844+{% if sections and 'DEFAULT' in sections -%}
1845+{% for key, value in sections['DEFAULT'] -%}
1846+{{ key }} = {{ value }}
1847+{% endfor -%}
1848+{% endif -%}
1849+
1850+{% if auth_host -%}
1851+[keystone_authtoken]
1852+auth_uri = {{ service_protocol }}://{{ service_host }}:{{ service_port }}/
1853+auth_host = {{ auth_host }}
1854+auth_port = {{ auth_port }}
1855+auth_protocol = {{ auth_protocol }}
1856+admin_tenant_name = {{ admin_tenant_name }}
1857+admin_user = {{ admin_user }}
1858+admin_password = {{ admin_password }}
1859+{% endif -%}
1860+
1861+[osapi_v3]
1862+enabled=True
1863+
1864
1865=== added directory 'templates/parts'
1866=== added file 'templates/parts/database'
1867--- templates/parts/database 1970-01-01 00:00:00 +0000
1868+++ templates/parts/database 2014-04-16 09:26:11 +0000
1869@@ -0,0 +1,3 @@
1870+{% if database_host -%}
1871+sql_connection = {{ database_type }}://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}{% if database_ssl_ca %}?ssl_ca={{ database_ssl_ca }}{% if database_ssl_cert %}&ssl_cert={{ database_ssl_cert }}&ssl_key={{ database_ssl_key }}{% endif %}{% endif %}
1872+{% endif -%}
1873
1874=== added file 'templates/parts/rabbitmq'
1875--- templates/parts/rabbitmq 1970-01-01 00:00:00 +0000
1876+++ templates/parts/rabbitmq 2014-04-16 09:26:11 +0000
1877@@ -0,0 +1,21 @@
1878+{% if rabbitmq_host or rabbitmq_hosts -%}
1879+rabbit_userid = {{ rabbitmq_user }}
1880+rabbit_virtual_host = {{ rabbitmq_virtual_host }}
1881+rabbit_password = {{ rabbitmq_password }}
1882+{% if rabbitmq_hosts -%}
1883+rabbit_hosts = {{ rabbitmq_hosts }}
1884+{% if rabbitmq_ha_queues -%}
1885+rabbit_ha_queues = True
1886+rabbit_durable_queues = False
1887+{% endif -%}
1888+{% else -%}
1889+rabbit_host = {{ rabbitmq_host }}
1890+{% endif -%}
1891+{% if rabbit_ssl_port -%}
1892+rabbit_use_ssl = True
1893+rabbit_port = {{ rabbit_ssl_port }}
1894+{% if rabbit_ssl_ca -%}
1895+kombu_ssl_ca_certs = {{ rabbit_ssl_ca }}
1896+{% endif -%}
1897+{% endif -%}
1898+{% endif -%}
1899\ No newline at end of file
1900
1901=== added file 'templates/parts/section-database'
1902--- templates/parts/section-database 1970-01-01 00:00:00 +0000
1903+++ templates/parts/section-database 2014-04-16 09:26:11 +0000
1904@@ -0,0 +1,4 @@
1905+{% if database_host -%}
1906+[database]
1907+connection = {{ database_type }}://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}{% if database_ssl_ca %}?ssl_ca={{ database_ssl_ca }}{% if database_ssl_cert %}&ssl_cert={{ database_ssl_cert }}&ssl_key={{ database_ssl_key }}{% endif %}{% endif %}
1908+{% endif -%}
1909
1910=== modified file 'unit_tests/test_nova_cc_hooks.py'
1911--- unit_tests/test_nova_cc_hooks.py 2013-11-08 05:41:39 +0000
1912+++ unit_tests/test_nova_cc_hooks.py 2014-04-16 09:26:11 +0000
1913@@ -1,8 +1,9 @@
1914-from mock import MagicMock, patch
1915-
1916+from mock import call, MagicMock, patch
1917 from test_utils import CharmTestCase
1918
1919-import nova_cc_utils as utils
1920+with patch('charmhelpers.core.hookenv.config') as config:
1921+ config.return_value = 'neutron'
1922+ import nova_cc_utils as utils
1923
1924 _reg = utils.register_configs
1925 _map = utils.restart_map
1926@@ -15,7 +16,6 @@
1927 utils.register_configs = _reg
1928 utils.restart_map = _map
1929
1930-
1931 TO_PATCH = [
1932 'api_port',
1933 'apt_update',
1934@@ -29,8 +29,11 @@
1935 'determine_packages',
1936 'determine_ports',
1937 'open_port',
1938+ 'is_relation_made',
1939+ 'log',
1940 'relation_get',
1941 'relation_set',
1942+ 'relation_ids',
1943 'ssh_compute_add',
1944 'ssh_known_hosts_b64',
1945 'ssh_authorized_keys_b64',
1946@@ -42,6 +45,7 @@
1947 'eligible_leader',
1948 'keystone_ca_cert_b64',
1949 'neutron_plugin',
1950+ 'migrate_database',
1951 ]
1952
1953
1954@@ -63,6 +67,7 @@
1955
1956 def setUp(self):
1957 super(NovaCCHooksTests, self).setUp(hooks, TO_PATCH)
1958+
1959 self.config.side_effect = self.test_config.get
1960 self.relation_get.side_effect = self.test_relation.get
1961 self.charm_dir.return_value = '/var/lib/juju/charms/nova/charm'
1962@@ -138,3 +143,91 @@
1963 quantum_url='http://nova-cc-host1:9696', quantum_plugin='nvp',
1964 relation_id=None,
1965 **FAKE_KS_AUTH_CFG)
1966+
1967+ def test_db_joined(self):
1968+ self.unit_get.return_value = 'nova.foohost.com'
1969+ self.is_relation_made.return_value = False
1970+ hooks.db_joined()
1971+ self.relation_set.assert_called_with(nova_database='nova',
1972+ nova_username='nova',
1973+ nova_hostname='nova.foohost.com')
1974+ self.unit_get.assert_called_with('private-address')
1975+
1976+ def test_postgresql_nova_db_joined(self):
1977+ self.is_relation_made.return_value = False
1978+ hooks.pgsql_nova_db_joined()
1979+ self.relation_set.assert_called_with(database='nova')
1980+
1981+ def test_postgresql_neutron_db_joined(self):
1982+ self.is_relation_made.return_value = False
1983+ hooks.pgsql_neutron_db_joined()
1984+ self.relation_set.assert_called_with(database='neutron')
1985+
1986+ def test_db_joined_with_postgresql(self):
1987+ self.is_relation_made.return_value = True
1988+
1989+ with self.assertRaises(Exception) as context:
1990+ hooks.db_joined()
1991+ self.assertEqual(context.exception.message,
1992+ 'Attempting to associate a mysql database when'
1993+ ' there is already associated a postgresql one')
1994+
1995+ def test_postgresql_nova_joined_with_db(self):
1996+ self.is_relation_made.return_value = True
1997+
1998+ with self.assertRaises(Exception) as context:
1999+ hooks.pgsql_nova_db_joined()
2000+ self.assertEqual(context.exception.message,
2001+ 'Attempting to associate a postgresql database when'
2002+ ' there is already associated a mysql one')
2003+
2004+ def test_postgresql_neutron_joined_with_db(self):
2005+ self.is_relation_made.return_value = True
2006+
2007+ with self.assertRaises(Exception) as context:
2008+ hooks.pgsql_neutron_db_joined()
2009+ self.assertEqual(context.exception.message,
2010+ 'Attempting to associate a postgresql database when'
2011+ ' there is already associated a mysql one')
2012+
2013+ @patch.object(hooks, 'CONFIGS')
2014+ def test_db_changed_missing_relation_data(self, configs):
2015+ configs.complete_contexts = MagicMock()
2016+ configs.complete_contexts.return_value = []
2017+ hooks.db_changed()
2018+ self.log.assert_called_with(
2019+ 'shared-db relation incomplete. Peer not ready?'
2020+ )
2021+
2022+ @patch.object(hooks, 'CONFIGS')
2023+ def test_postgresql_nova_db_changed_missing_relation_data(self, configs):
2024+ configs.complete_contexts = MagicMock()
2025+ configs.complete_contexts.return_value = []
2026+ hooks.postgresql_nova_db_changed()
2027+ self.log.assert_called_with(
2028+ 'pgsql-nova-db relation incomplete. Peer not ready?'
2029+ )
2030+
2031+ def _shared_db_test(self, configs):
2032+ configs.complete_contexts = MagicMock()
2033+ configs.complete_contexts.return_value = ['shared-db']
2034+ configs.write = MagicMock()
2035+ hooks.db_changed()
2036+
2037+ def _postgresql_db_test(self, configs):
2038+ configs.complete_contexts = MagicMock()
2039+ configs.complete_contexts.return_value = ['pgsql-nova-db']
2040+ configs.write = MagicMock()
2041+ hooks.postgresql_nova_db_changed()
2042+
2043+ @patch.object(hooks, 'CONFIGS')
2044+ def test_db_changed(self, configs):
2045+ self._shared_db_test(configs)
2046+ self.assertTrue(configs.write_all.called)
2047+ self.migrate_database.assert_called_with()
2048+
2049+ @patch.object(hooks, 'CONFIGS')
2050+ def test_postgresql_db_changed(self, configs):
2051+ self._postgresql_db_test(configs)
2052+ self.assertTrue(configs.write_all.called)
2053+ self.migrate_database.assert_called_with()
2054
2055=== modified file 'unit_tests/test_nova_cc_utils.py'
2056--- unit_tests/test_nova_cc_utils.py 2013-12-16 13:33:34 +0000
2057+++ unit_tests/test_nova_cc_utils.py 2014-04-16 09:26:11 +0000
2058@@ -13,15 +13,28 @@
2059 hookenv.config = _conf
2060
2061 TO_PATCH = [
2062+ 'apt_update',
2063+ 'apt_upgrade',
2064+ 'apt_install',
2065 'config',
2066+ 'configure_installation_source',
2067+ 'disable_policy_rcd',
2068+ 'eligible_leader',
2069+ 'enable_policy_rcd',
2070+ 'get_os_codename_install_source',
2071 'log',
2072+ 'ml2_migration',
2073 'network_manager',
2074+ 'neutron_db_manage',
2075 'neutron_plugin',
2076 'neutron_plugin_attribute',
2077 'os_release',
2078+ 'register_configs',
2079 'relation_ids',
2080 'remote_unit',
2081 '_save_script_rc',
2082+ 'service_start',
2083+ 'services'
2084 ]
2085
2086 SCRIPTRC_ENV_VARS = {
2087@@ -103,6 +116,12 @@
2088 }
2089
2090
2091+DPKG_OPTS = [
2092+ '--option', 'Dpkg::Options::=--force-confnew',
2093+ '--option', 'Dpkg::Options::=--force-confdef',
2094+]
2095+
2096+
2097 def fake_plugin_attribute(plugin, attr, net_manager):
2098 if plugin in PLUGIN_ATTRIBUTES:
2099 try:
2100@@ -345,7 +364,9 @@
2101 ssh_dir.return_value = '/tmp/foo'
2102 self.assertEquals(utils.authorized_keys(), '/tmp/foo/authorized_keys')
2103 ssh_dir.assert_called_with(None)
2104- self.assertEquals(utils.authorized_keys('bar'), '/tmp/foo/authorized_keys')
2105+ self.assertEquals(
2106+ utils.authorized_keys('bar'),
2107+ '/tmp/foo/authorized_keys')
2108 ssh_dir.assert_called_with('bar')
2109
2110 @patch.object(utils, 'known_hosts')
2111@@ -374,7 +395,8 @@
2112 @patch.object(utils, 'known_hosts')
2113 @patch.object(utils, 'authorized_keys')
2114 @patch('os.path.isfile')
2115- def test_ssh_compute_remove(self, isfile, auth_key, known_host):
2116+ def test_ssh_compute_remove(self, isfile,
2117+ auth_key, known_host):
2118 isfile.return_value = False
2119
2120 removed_key = AUTHORIZED_KEYS.split('\n')[2]
2121@@ -454,3 +476,82 @@
2122 _known_hosts.assert_called_with(None)
2123 utils.remove_known_host('test', 'bar')
2124 _known_hosts.assert_called_with('bar')
2125+
2126+ @patch('subprocess.check_output')
2127+ def test_migrate_database(self, check_output):
2128+ "Migrate database with nova-manage"
2129+ utils.migrate_database()
2130+ check_output.assert_called_with(['nova-manage', 'db', 'sync'])
2131+
2132+ @patch.object(utils, 'get_step_upgrade_source')
2133+ @patch.object(utils, 'migrate_database')
2134+ @patch.object(utils, 'determine_packages')
2135+ def test_upgrade_grizzly_icehouse(self, determine_packages,
2136+ migrate_database,
2137+ get_step_upgrade_source):
2138+ "Simulate a call to do_openstack_upgrade() for grizzly->icehouse"
2139+ get_step_upgrade_source.return_value = 'cloud:precise-havana'
2140+ self.os_release.side_effect = ['grizzly', 'havana']
2141+ self.get_os_codename_install_source.side_effect = [
2142+ 'havana',
2143+ 'icehouse']
2144+ self.eligible_leader.return_value = True
2145+ utils.do_openstack_upgrade()
2146+ expected = [call(['stamp', 'grizzly']), call(['upgrade', 'head']),
2147+ call(['upgrade', 'head'])]
2148+ self.assertEquals(self.neutron_db_manage.call_args_list, expected)
2149+ self.apt_update.assert_called_with(fatal=True)
2150+ self.apt_upgrade.assert_called_with(options=DPKG_OPTS, fatal=True,
2151+ dist=True)
2152+ self.apt_install.assert_called_with(determine_packages(), fatal=True)
2153+ expected = [call(release='havana'), call(release='icehouse')]
2154+ self.assertEquals(self.register_configs.call_args_list, expected)
2155+ self.assertEquals(self.ml2_migration.call_count, 1)
2156+ self.assertTrue(migrate_database.call_count, 2)
2157+
2158+ @patch.object(utils, 'get_step_upgrade_source')
2159+ @patch.object(utils, 'migrate_database')
2160+ @patch.object(utils, 'determine_packages')
2161+ def test_upgrade_havana_icehouse(self, determine_packages,
2162+ migrate_database,
2163+ get_step_upgrade_source):
2164+ "Simulate a call to do_openstack_upgrade() for havana->icehouse"
2165+ get_step_upgrade_source.return_value = None
2166+ self.os_release.return_value = 'havana'
2167+ self.get_os_codename_install_source.return_value = 'icehouse'
2168+ self.eligible_leader.return_value = True
2169+ utils.do_openstack_upgrade()
2170+ self.neutron_db_manage.assert_called_with(['upgrade', 'head'])
2171+ self.apt_update.assert_called_with(fatal=True)
2172+ self.apt_upgrade.assert_called_with(options=DPKG_OPTS, fatal=True,
2173+ dist=True)
2174+ self.apt_install.assert_called_with(determine_packages(), fatal=True)
2175+ self.register_configs.assert_called_with(release='icehouse')
2176+ self.assertEquals(self.ml2_migration.call_count, 1)
2177+ self.assertTrue(migrate_database.call_count, 1)
2178+
2179+ @patch.object(utils, '_do_openstack_upgrade')
2180+ def test_upgrade_grizzly_icehouse_source(self, _do_openstack_upgrade):
2181+ "Verify get_step_upgrade_source() for grizzly->icehouse"
2182+ self.config.side_effect = None
2183+ self.config.return_value = 'cloud:precise-icehouse'
2184+ with patch_open() as (_open, _file):
2185+ _file.read = MagicMock()
2186+ _file.readline.return_value = ("deb url"
2187+ " precise-updates/grizzly main")
2188+ utils.do_openstack_upgrade()
2189+ expected = [call('cloud:precise-havana'),
2190+ call('cloud:precise-icehouse')]
2191+ self.assertEquals(_do_openstack_upgrade.call_args_list, expected)
2192+
2193+ @patch.object(utils, '_do_openstack_upgrade')
2194+ def test_upgrade_havana_icehouse_source(self, _do_openstack_upgrade):
2195+ "Verify get_step_upgrade_source() for havana->icehouse"
2196+ self.config.side_effect = None
2197+ self.config.return_value = 'cloud:precise-icehouse'
2198+ with patch_open() as (_open, _file):
2199+ _file.read = MagicMock()
2200+ _file.readline.return_value = "deb url precise-updates/havana main"
2201+ utils.do_openstack_upgrade()
2202+ expected = [call('cloud:precise-icehouse')]
2203+ self.assertEquals(_do_openstack_upgrade.call_args_list, expected)

Subscribers

People subscribed via source and target branches