Merge lp:~ivoks/charms/precise/nova-cloud-controller/alchemy-flags into lp:~charmers/charms/precise/nova-cloud-controller/trunk

Proposed by Ante Karamatić
Status: Superseded
Proposed branch: lp:~ivoks/charms/precise/nova-cloud-controller/alchemy-flags
Merge into: lp:~charmers/charms/precise/nova-cloud-controller/trunk
Diff against target: 454 lines (+179/-39)
10 files modified
config.yaml (+6/-0)
hooks/charmhelpers/contrib/openstack/context.py (+65/-21)
hooks/charmhelpers/contrib/openstack/utils.py (+14/-6)
hooks/charmhelpers/contrib/storage/linux/utils.py (+1/-1)
hooks/charmhelpers/core/hookenv.py (+6/-0)
hooks/charmhelpers/core/host.py (+44/-0)
hooks/charmhelpers/fetch/__init__.py (+32/-10)
revision (+1/-1)
templates/folsom/ovs_quantum_plugin.ini (+5/-0)
templates/havana/ovs_neutron_plugin.ini (+5/-0)
To merge this branch: bzr merge lp:~ivoks/charms/precise/nova-cloud-controller/alchemy-flags
Reviewer Review Type Date Requested Status
James Page Needs Information
Marco Ceppi (community) Abstain
Review via email: mp+203968@code.launchpad.net

This proposal has been superseded by a proposal from 2014-02-19.

Description of the change

This branch makes it possible to define sqlalchemy flags within [DATABASE] section of quantum/neutron agent plugins. This is commonly used to fine tune SQL access.

To post a comment you must log in.
Revision history for this message
Marco Ceppi (marcoceppi) wrote :

Deferring to openstack-charmers

review: Abstain
Revision history for this message
James Page (james-page) wrote :

I'm assuming that this is tune things like database pool sizing, timeouts etc?

I'd actually prefer to see that exposed via specific configuration options rather than being generic - this also feels like something we should have more sane default for - I'm assuming we can make a max pool size and lazy fill it as and when required?

review: Needs Information
Revision history for this message
Ante Karamatić (ivoks) wrote :

Correct, it's only for database tuning.

While I agree that having better defaults would help a lot, I'm pretty sure some people would find this useful. This is oriented to devops that understand how this impacts neutron. I deliberately used 'sqlalchemy' instead of 'database' in the name, to target people who actually do understand what sqlaclchemy is.

I took the same approach we have for nova.conf. We allow various configuration flags to be set for nova, but none for neutron.

63. By Ante Karamatić

Rebased on latest nova-c-c charm

Unmerged revisions

63. By Ante Karamatić

Rebased on latest nova-c-c charm

62. By Ante Karamatić

Bump revision

61. By Ante Karamatić

Add neutron-alchemy-flags functionality to nova-c-c charm

60. By Ante Karamatić

Add functionality to charm-helpers from:
  lp:~ivoks/charm-helpers/neutron-alchemy

59. By Ante Karamatić

Sync charmhelpers

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 2013-11-08 05:41:39 +0000
3+++ config.yaml 2014-01-30 13:48:00 +0000
4@@ -126,6 +126,12 @@
5 ssl_key:
6 type: string
7 description: SSL key to use with certificate specified as ssl_cert.
8+ neutron-alchemy-flags:
9+ default: None
10+ type: string
11+ description: |
12+ Comma separated list of key=value sqlalchemy related config flags to be
13+ set in plugin ini file.
14 # Neutron NVP Plugin configuration
15 nvp-controllers:
16 type: string
17
18=== modified file 'hooks/charmhelpers/contrib/openstack/context.py'
19--- hooks/charmhelpers/contrib/openstack/context.py 2013-10-28 19:03:14 +0000
20+++ hooks/charmhelpers/contrib/openstack/context.py 2014-01-30 13:48:00 +0000
21@@ -23,7 +23,6 @@
22 unit_get,
23 unit_private_ip,
24 ERROR,
25- WARNING,
26 )
27
28 from charmhelpers.contrib.hahelpers.cluster import (
29@@ -68,6 +67,43 @@
30 return True
31
32
33+def config_flags_parser(config_flags):
34+ if config_flags.find('==') >= 0:
35+ log("config_flags is not in expected format (key=value)",
36+ level=ERROR)
37+ raise OSContextError
38+ # strip the following from each value.
39+ post_strippers = ' ,'
40+ # we strip any leading/trailing '=' or ' ' from the string then
41+ # split on '='.
42+ split = config_flags.strip(' =').split('=')
43+ limit = len(split)
44+ flags = {}
45+ for i in xrange(0, limit - 1):
46+ current = split[i]
47+ next = split[i + 1]
48+ vindex = next.rfind(',')
49+ if (i == limit - 2) or (vindex < 0):
50+ value = next
51+ else:
52+ value = next[:vindex]
53+
54+ if i == 0:
55+ key = current
56+ else:
57+ # if this not the first entry, expect an embedded key.
58+ index = current.rfind(',')
59+ if index < 0:
60+ log("invalid config value(s) at index %s" % (i),
61+ level=ERROR)
62+ raise OSContextError
63+ key = current[index + 1:]
64+
65+ # Add to collection.
66+ flags[key.strip(post_strippers)] = value.rstrip(post_strippers)
67+ return flags
68+
69+
70 class OSContextGenerator(object):
71 interfaces = []
72
73@@ -182,10 +218,12 @@
74 # Sufficient information found = break out!
75 break
76 # Used for active/active rabbitmq >= grizzly
77- ctxt['rabbitmq_hosts'] = []
78- for unit in related_units(rid):
79- ctxt['rabbitmq_hosts'].append(relation_get('private-address',
80- rid=rid, unit=unit))
81+ if 'clustered' not in ctxt and len(related_units(rid)) > 1:
82+ rabbitmq_hosts = []
83+ for unit in related_units(rid):
84+ rabbitmq_hosts.append(relation_get('private-address',
85+ rid=rid, unit=unit))
86+ ctxt['rabbitmq_hosts'] = ','.join(rabbitmq_hosts)
87 if not context_complete(ctxt):
88 return {}
89 else:
90@@ -286,6 +324,7 @@
91
92
93 class ApacheSSLContext(OSContextGenerator):
94+
95 """
96 Generates a context for an apache vhost configuration that configures
97 HTTPS reverse proxying for one or many endpoints. Generated context
98@@ -428,33 +467,37 @@
99 elif self.plugin == 'nvp':
100 ctxt.update(self.nvp_ctxt())
101
102+ alchemy_flags = config('neutron-alchemy-flags')
103+ if alchemy_flags:
104+ flags = config_flags_parser(alchemy_flags)
105+ ctxt['neutron_alchemy_flags'] = flags
106+
107 self._save_flag_file()
108 return ctxt
109
110
111 class OSConfigFlagContext(OSContextGenerator):
112- '''
113- Responsible adding user-defined config-flags in charm config to a
114- to a template context.
115- '''
116+
117+ """
118+ Responsible for adding user-defined config-flags in charm config to a
119+ template context.
120+
121+ NOTE: the value of config-flags may be a comma-separated list of
122+ key=value pairs and some Openstack config files support
123+ comma-separated lists as values.
124+ """
125+
126 def __call__(self):
127 config_flags = config('config-flags')
128- if not config_flags or config_flags in ['None', '']:
129+ if not config_flags:
130 return {}
131- config_flags = config_flags.split(',')
132- flags = {}
133- for flag in config_flags:
134- if '=' not in flag:
135- log('Improperly formatted config-flag, expected k=v '
136- 'got %s' % flag, level=WARNING)
137- continue
138- k, v = flag.split('=')
139- flags[k.strip()] = v
140- ctxt = {'user_config_flags': flags}
141- return ctxt
142+
143+ flags = config_flags_parser(config_flags)
144+ return {'user_config_flags': flags}
145
146
147 class SubordinateConfigContext(OSContextGenerator):
148+
149 """
150 Responsible for inspecting relations to subordinates that
151 may be exporting required config via a json blob.
152@@ -495,6 +538,7 @@
153 }
154
155 """
156+
157 def __init__(self, service, config_file, interface):
158 """
159 :param service : Service name key to query in any subordinate
160
161=== modified file 'hooks/charmhelpers/contrib/openstack/utils.py'
162--- hooks/charmhelpers/contrib/openstack/utils.py 2013-11-06 03:48:26 +0000
163+++ hooks/charmhelpers/contrib/openstack/utils.py 2014-01-30 13:48:00 +0000
164@@ -41,6 +41,7 @@
165 ('quantal', 'folsom'),
166 ('raring', 'grizzly'),
167 ('saucy', 'havana'),
168+ ('trusty', 'icehouse')
169 ])
170
171
172@@ -201,7 +202,7 @@
173
174
175 def import_key(keyid):
176- cmd = "apt-key adv --keyserver keyserver.ubuntu.com " \
177+ cmd = "apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 " \
178 "--recv-keys %s" % keyid
179 try:
180 subprocess.check_call(cmd.split(' '))
181@@ -260,6 +261,9 @@
182 'havana': 'precise-updates/havana',
183 'havana/updates': 'precise-updates/havana',
184 'havana/proposed': 'precise-proposed/havana',
185+ 'icehouse': 'precise-updates/icehouse',
186+ 'icehouse/updates': 'precise-updates/icehouse',
187+ 'icehouse/proposed': 'precise-proposed/icehouse',
188 }
189
190 try:
191@@ -411,7 +415,7 @@
192 return ns_query(hostname)
193
194
195-def get_hostname(address):
196+def get_hostname(address, fqdn=True):
197 """
198 Resolves hostname for given IP, or returns the input
199 if it is already a hostname.
200@@ -430,7 +434,11 @@
201 if not result:
202 return None
203
204- # strip trailing .
205- if result.endswith('.'):
206- return result[:-1]
207- return result
208+ if fqdn:
209+ # strip trailing .
210+ if result.endswith('.'):
211+ return result[:-1]
212+ else:
213+ return result
214+ else:
215+ return result.split('.')[0]
216
217=== modified file 'hooks/charmhelpers/contrib/storage/linux/utils.py'
218--- hooks/charmhelpers/contrib/storage/linux/utils.py 2013-08-02 03:42:16 +0000
219+++ hooks/charmhelpers/contrib/storage/linux/utils.py 2014-01-30 13:48:00 +0000
220@@ -22,4 +22,4 @@
221
222 :param block_device: str: Full path of block device to clean.
223 '''
224- check_call(['sgdisk', '--zap-all', block_device])
225+ check_call(['sgdisk', '--zap-all', '--mbrtogpt', block_device])
226
227=== modified file 'hooks/charmhelpers/core/hookenv.py'
228--- hooks/charmhelpers/core/hookenv.py 2013-11-06 03:48:26 +0000
229+++ hooks/charmhelpers/core/hookenv.py 2014-01-30 13:48:00 +0000
230@@ -8,6 +8,7 @@
231 import json
232 import yaml
233 import subprocess
234+import sys
235 import UserDict
236 from subprocess import CalledProcessError
237
238@@ -149,6 +150,11 @@
239 return local_unit().split('/')[0]
240
241
242+def hook_name():
243+ """The name of the currently executing hook"""
244+ return os.path.basename(sys.argv[0])
245+
246+
247 @cached
248 def config(scope=None):
249 """Juju charm configuration"""
250
251=== modified file 'hooks/charmhelpers/core/host.py'
252--- hooks/charmhelpers/core/host.py 2013-10-22 23:01:40 +0000
253+++ hooks/charmhelpers/core/host.py 2014-01-30 13:48:00 +0000
254@@ -245,3 +245,47 @@
255 random_chars = [
256 random.choice(alphanumeric_chars) for _ in range(length)]
257 return(''.join(random_chars))
258+
259+
260+def list_nics(nic_type):
261+ '''Return a list of nics of given type(s)'''
262+ if isinstance(nic_type, basestring):
263+ int_types = [nic_type]
264+ else:
265+ int_types = nic_type
266+ interfaces = []
267+ for int_type in int_types:
268+ cmd = ['ip', 'addr', 'show', 'label', int_type + '*']
269+ ip_output = subprocess.check_output(cmd).split('\n')
270+ ip_output = (line for line in ip_output if line)
271+ for line in ip_output:
272+ if line.split()[1].startswith(int_type):
273+ interfaces.append(line.split()[1].replace(":", ""))
274+ return interfaces
275+
276+
277+def set_nic_mtu(nic, mtu):
278+ '''Set MTU on a network interface'''
279+ cmd = ['ip', 'link', 'set', nic, 'mtu', mtu]
280+ subprocess.check_call(cmd)
281+
282+
283+def get_nic_mtu(nic):
284+ cmd = ['ip', 'addr', 'show', nic]
285+ ip_output = subprocess.check_output(cmd).split('\n')
286+ mtu = ""
287+ for line in ip_output:
288+ words = line.split()
289+ if 'mtu' in words:
290+ mtu = words[words.index("mtu") + 1]
291+ return mtu
292+
293+
294+def get_nic_hwaddr(nic):
295+ cmd = ['ip', '-o', '-0', 'addr', 'show', nic]
296+ ip_output = subprocess.check_output(cmd)
297+ hwaddr = ""
298+ words = ip_output.split()
299+ if 'link/ether' in words:
300+ hwaddr = words[words.index('link/ether') + 1]
301+ return hwaddr
302
303=== modified file 'hooks/charmhelpers/fetch/__init__.py'
304--- hooks/charmhelpers/fetch/__init__.py 2013-11-06 03:48:26 +0000
305+++ hooks/charmhelpers/fetch/__init__.py 2014-01-30 13:48:00 +0000
306@@ -13,6 +13,7 @@
307 log,
308 )
309 import apt_pkg
310+import os
311
312 CLOUD_ARCHIVE = """# Ubuntu Cloud Archive
313 deb http://ubuntu-cloud.archive.canonical.com/ubuntu {} main
314@@ -43,8 +44,16 @@
315 'precise-havana/updates': 'precise-updates/havana',
316 'precise-updates/havana': 'precise-updates/havana',
317 'havana/proposed': 'precise-proposed/havana',
318- 'precies-havana/proposed': 'precise-proposed/havana',
319+ 'precise-havana/proposed': 'precise-proposed/havana',
320 'precise-proposed/havana': 'precise-proposed/havana',
321+ # Icehouse
322+ 'icehouse': 'precise-updates/icehouse',
323+ 'precise-icehouse': 'precise-updates/icehouse',
324+ 'precise-icehouse/updates': 'precise-updates/icehouse',
325+ 'precise-updates/icehouse': 'precise-updates/icehouse',
326+ 'icehouse/proposed': 'precise-proposed/icehouse',
327+ 'precise-icehouse/proposed': 'precise-proposed/icehouse',
328+ 'precise-proposed/icehouse': 'precise-proposed/icehouse',
329 }
330
331
332@@ -66,8 +75,10 @@
333
334 def apt_install(packages, options=None, fatal=False):
335 """Install one or more packages"""
336- options = options or []
337- cmd = ['apt-get', '-y']
338+ if options is None:
339+ options = ['--option=Dpkg::Options::=--force-confold']
340+
341+ cmd = ['apt-get', '--assume-yes']
342 cmd.extend(options)
343 cmd.append('install')
344 if isinstance(packages, basestring):
345@@ -76,10 +87,14 @@
346 cmd.extend(packages)
347 log("Installing {} with options: {}".format(packages,
348 options))
349+ env = os.environ.copy()
350+ if 'DEBIAN_FRONTEND' not in env:
351+ env['DEBIAN_FRONTEND'] = 'noninteractive'
352+
353 if fatal:
354- subprocess.check_call(cmd)
355+ subprocess.check_call(cmd, env=env)
356 else:
357- subprocess.call(cmd)
358+ subprocess.call(cmd, env=env)
359
360
361 def apt_update(fatal=False):
362@@ -93,7 +108,7 @@
363
364 def apt_purge(packages, fatal=False):
365 """Purge one or more packages"""
366- cmd = ['apt-get', '-y', 'purge']
367+ cmd = ['apt-get', '--assume-yes', 'purge']
368 if isinstance(packages, basestring):
369 cmd.append(packages)
370 else:
371@@ -123,14 +138,16 @@
372 if (source.startswith('ppa:') or
373 source.startswith('http:') or
374 source.startswith('deb ') or
375- source.startswith('cloud-archive:')):
376+ source.startswith('cloud-archive:')):
377 subprocess.check_call(['add-apt-repository', '--yes', source])
378 elif source.startswith('cloud:'):
379 apt_install(filter_installed_packages(['ubuntu-cloud-keyring']),
380 fatal=True)
381 pocket = source.split(':')[-1]
382 if pocket not in CLOUD_ARCHIVE_POCKETS:
383- raise SourceConfigError('Unsupported cloud: source option %s' % pocket)
384+ raise SourceConfigError(
385+ 'Unsupported cloud: source option %s' %
386+ pocket)
387 actual_pocket = CLOUD_ARCHIVE_POCKETS[pocket]
388 with open('/etc/apt/sources.list.d/cloud-archive.list', 'w') as apt:
389 apt.write(CLOUD_ARCHIVE.format(actual_pocket))
390@@ -220,7 +237,9 @@
391
392
393 class BaseFetchHandler(object):
394+
395 """Base class for FetchHandler implementations in fetch plugins"""
396+
397 def can_handle(self, source):
398 """Returns True if the source can be handled. Otherwise returns
399 a string explaining why it cannot"""
400@@ -248,10 +267,13 @@
401 for handler_name in fetch_handlers:
402 package, classname = handler_name.rsplit('.', 1)
403 try:
404- handler_class = getattr(importlib.import_module(package), classname)
405+ handler_class = getattr(
406+ importlib.import_module(package),
407+ classname)
408 plugin_list.append(handler_class())
409 except (ImportError, AttributeError):
410 # Skip missing plugins so that they can be ommitted from
411 # installation if desired
412- log("FetchHandler {} not found, skipping plugin".format(handler_name))
413+ log("FetchHandler {} not found, skipping plugin".format(
414+ handler_name))
415 return plugin_list
416
417=== modified file 'revision'
418--- revision 2013-11-08 05:41:39 +0000
419+++ revision 2014-01-30 13:48:00 +0000
420@@ -1,1 +1,1 @@
421-311
422+312
423
424=== modified file 'templates/folsom/ovs_quantum_plugin.ini'
425--- templates/folsom/ovs_quantum_plugin.ini 2013-08-19 21:13:45 +0000
426+++ templates/folsom/ovs_quantum_plugin.ini 2014-01-30 13:48:00 +0000
427@@ -16,6 +16,11 @@
428 {% else -%}
429 connection = sqlite:////var/lib/quantum/quantum.sqlite
430 {% endif -%}
431+{% if neutron_alchemy_flags -%}
432+{% for key, value in neutron_alchemy_flags.iteritems() -%}
433+{{ key }} = {{ value }}
434+{% endfor -%}
435+{% endif -%}
436
437 [SECURITYGROUP]
438 {% if neutron_security_groups -%}
439
440=== modified file 'templates/havana/ovs_neutron_plugin.ini'
441--- templates/havana/ovs_neutron_plugin.ini 2013-09-25 10:49:12 +0000
442+++ templates/havana/ovs_neutron_plugin.ini 2014-01-30 13:48:00 +0000
443@@ -10,6 +10,11 @@
444 {% else -%}
445 connection = sqlite:////var/lib/neutron/neutron.sqlite
446 {% endif -%}
447+{% if neutron_alchemy_flags -%}
448+{% for key, value in neutron_alchemy_flags.iteritems() -%}
449+{{ key }} = {{ value }}
450+{% endfor -%}
451+{% endif -%}
452
453 [securitygroup]
454 {% if neutron_security_groups -%}

Subscribers

People subscribed via source and target branches

to status/vote changes: