Merge lp:~hopem/charms/trusty/neutron-gateway/fix-network-vlan-ranges-parser into lp:~openstack-charmers-archive/charms/trusty/neutron-gateway/next

Proposed by Edward Hope-Morley
Status: Merged
Merged at revision: 116
Proposed branch: lp:~hopem/charms/trusty/neutron-gateway/fix-network-vlan-ranges-parser
Merge into: lp:~openstack-charmers-archive/charms/trusty/neutron-gateway/next
Diff against target: 335 lines (+131/-22)
8 files modified
config.yaml (+4/-2)
hooks/charmhelpers/contrib/hahelpers/cluster.py (+25/-0)
hooks/charmhelpers/contrib/openstack/neutron.py (+10/-5)
hooks/charmhelpers/core/hookenv.py (+86/-10)
hooks/charmhelpers/core/host.py (+1/-1)
hooks/charmhelpers/core/services/base.py (+2/-2)
hooks/charmhelpers/fetch/__init__.py (+1/-1)
unit_tests/test_neutron_utils.py (+2/-1)
To merge this branch: bzr merge lp:~hopem/charms/trusty/neutron-gateway/fix-network-vlan-ranges-parser
Reviewer Review Type Date Requested Status
Liam Young (community) Approve
Review via email: mp+258988@code.launchpad.net
To post a comment you must log in.
117. By Edward Hope-Morley

sync

Revision history for this message
Liam Young (gnuoy) wrote :

Approve

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'config.yaml'
2--- config.yaml 2015-04-16 20:07:38 +0000
3+++ config.yaml 2015-05-20 19:44:14 +0000
4@@ -153,8 +153,10 @@
5 type: string
6 default: "physnet1:1000:2000"
7 description: |
8- Space-delimited list of Neutron network-provider & vlan-id-ranges using
9- format "<provider>:<start>:<end> ...".
10+ Space-delimited list of <physical_network>:<vlan_min>:<vlan_max> or
11+ <physical_network> specifying physical_network names usable for VLAN
12+ provider and tenant networks, as well as ranges of VLAN tags on each
13+ available for allocation to tenant networks.
14 # Network configuration options
15 # by default all access is over 'private-address'
16 os-data-network:
17
18=== modified file 'hooks/charmhelpers/contrib/hahelpers/cluster.py'
19--- hooks/charmhelpers/contrib/hahelpers/cluster.py 2015-03-31 15:13:53 +0000
20+++ hooks/charmhelpers/contrib/hahelpers/cluster.py 2015-05-20 19:44:14 +0000
21@@ -52,6 +52,8 @@
22 bool_from_string,
23 )
24
25+DC_RESOURCE_NAME = 'DC'
26+
27
28 class HAIncompleteConfig(Exception):
29 pass
30@@ -95,6 +97,27 @@
31 return False
32
33
34+def is_crm_dc():
35+ """
36+ Determine leadership by querying the pacemaker Designated Controller
37+ """
38+ cmd = ['crm', 'status']
39+ try:
40+ status = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
41+ if not isinstance(status, six.text_type):
42+ status = six.text_type(status, "utf-8")
43+ except subprocess.CalledProcessError:
44+ return False
45+ current_dc = ''
46+ for line in status.split('\n'):
47+ if line.startswith('Current DC'):
48+ # Current DC: juju-lytrusty-machine-2 (168108163) - partition with quorum
49+ current_dc = line.split(':')[1].split()[0]
50+ if current_dc == get_unit_hostname():
51+ return True
52+ return False
53+
54+
55 @retry_on_exception(5, base_delay=2, exc_type=CRMResourceNotFound)
56 def is_crm_leader(resource, retry=False):
57 """
58@@ -104,6 +127,8 @@
59 We allow this operation to be retried to avoid the possibility of getting a
60 false negative. See LP #1396246 for more info.
61 """
62+ if resource == DC_RESOURCE_NAME:
63+ return is_crm_dc()
64 cmd = ['crm', 'resource', 'show', resource]
65 try:
66 status = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
67
68=== modified file 'hooks/charmhelpers/contrib/openstack/neutron.py'
69--- hooks/charmhelpers/contrib/openstack/neutron.py 2015-04-16 20:07:38 +0000
70+++ hooks/charmhelpers/contrib/openstack/neutron.py 2015-05-20 19:44:14 +0000
71@@ -256,11 +256,14 @@
72 def parse_mappings(mappings):
73 parsed = {}
74 if mappings:
75- mappings = mappings.split(' ')
76+ mappings = mappings.split()
77 for m in mappings:
78 p = m.partition(':')
79- if p[1] == ':':
80- parsed[p[0].strip()] = p[2].strip()
81+ key = p[0].strip()
82+ if p[1]:
83+ parsed[key] = p[2].strip()
84+ else:
85+ parsed[key] = ''
86
87 return parsed
88
89@@ -283,13 +286,13 @@
90 Returns dict of the form {bridge:port}.
91 """
92 _mappings = parse_mappings(mappings)
93- if not _mappings:
94+ if not _mappings or list(_mappings.values()) == ['']:
95 if not mappings:
96 return {}
97
98 # For backwards-compatibility we need to support port-only provided in
99 # config.
100- _mappings = {default_bridge: mappings.split(' ')[0]}
101+ _mappings = {default_bridge: mappings.split()[0]}
102
103 bridges = _mappings.keys()
104 ports = _mappings.values()
105@@ -309,6 +312,8 @@
106
107 Mappings must be a space-delimited list of provider:start:end mappings.
108
109+ The start:end range is optional and may be omitted.
110+
111 Returns dict of the form {provider: (start, end)}.
112 """
113 _mappings = parse_mappings(mappings)
114
115=== modified file 'hooks/charmhelpers/core/hookenv.py'
116--- hooks/charmhelpers/core/hookenv.py 2015-04-16 20:07:38 +0000
117+++ hooks/charmhelpers/core/hookenv.py 2015-05-20 19:44:14 +0000
118@@ -21,12 +21,14 @@
119 # Charm Helpers Developers <juju@lists.ubuntu.com>
120
121 from __future__ import print_function
122+from functools import wraps
123 import os
124 import json
125 import yaml
126 import subprocess
127 import sys
128 import errno
129+import tempfile
130 from subprocess import CalledProcessError
131
132 import six
133@@ -58,15 +60,17 @@
134
135 will cache the result of unit_get + 'test' for future calls.
136 """
137+ @wraps(func)
138 def wrapper(*args, **kwargs):
139 global cache
140 key = str((func, args, kwargs))
141 try:
142 return cache[key]
143 except KeyError:
144- res = func(*args, **kwargs)
145- cache[key] = res
146- return res
147+ pass # Drop out of the exception handler scope.
148+ res = func(*args, **kwargs)
149+ cache[key] = res
150+ return res
151 return wrapper
152
153
154@@ -178,7 +182,7 @@
155
156 def remote_unit():
157 """The remote unit for the current relation hook"""
158- return os.environ['JUJU_REMOTE_UNIT']
159+ return os.environ.get('JUJU_REMOTE_UNIT', None)
160
161
162 def service_name():
163@@ -250,6 +254,12 @@
164 except KeyError:
165 return (self._prev_dict or {})[key]
166
167+ def get(self, key, default=None):
168+ try:
169+ return self[key]
170+ except KeyError:
171+ return default
172+
173 def keys(self):
174 prev_keys = []
175 if self._prev_dict is not None:
176@@ -353,14 +363,29 @@
177 """Set relation information for the current unit"""
178 relation_settings = relation_settings if relation_settings else {}
179 relation_cmd_line = ['relation-set']
180+ accepts_file = "--file" in subprocess.check_output(
181+ relation_cmd_line + ["--help"])
182 if relation_id is not None:
183 relation_cmd_line.extend(('-r', relation_id))
184- for k, v in (list(relation_settings.items()) + list(kwargs.items())):
185- if v is None:
186- relation_cmd_line.append('{}='.format(k))
187- else:
188- relation_cmd_line.append('{}={}'.format(k, v))
189- subprocess.check_call(relation_cmd_line)
190+ settings = relation_settings.copy()
191+ settings.update(kwargs)
192+ if accepts_file:
193+ # --file was introduced in Juju 1.23.2. Use it by default if
194+ # available, since otherwise we'll break if the relation data is
195+ # too big. Ideally we should tell relation-set to read the data from
196+ # stdin, but that feature is broken in 1.23.2: Bug #1454678.
197+ with tempfile.NamedTemporaryFile(delete=False) as settings_file:
198+ settings_file.write(yaml.safe_dump(settings).encode("utf-8"))
199+ subprocess.check_call(
200+ relation_cmd_line + ["--file", settings_file.name])
201+ os.remove(settings_file.name)
202+ else:
203+ for key, value in settings.items():
204+ if value is None:
205+ relation_cmd_line.append('{}='.format(key))
206+ else:
207+ relation_cmd_line.append('{}={}'.format(key, value))
208+ subprocess.check_call(relation_cmd_line)
209 # Flush cache of any relation-gets for local unit
210 flush(local_unit())
211
212@@ -509,6 +534,11 @@
213 return None
214
215
216+def unit_public_ip():
217+ """Get this unit's public IP address"""
218+ return unit_get('public-address')
219+
220+
221 def unit_private_ip():
222 """Get this unit's private IP address"""
223 return unit_get('private-address')
224@@ -605,3 +635,49 @@
225
226 The results set by action_set are preserved."""
227 subprocess.check_call(['action-fail', message])
228+
229+
230+def status_set(workload_state, message):
231+ """Set the workload state with a message
232+
233+ Use status-set to set the workload state with a message which is visible
234+ to the user via juju status. If the status-set command is not found then
235+ assume this is juju < 1.23 and juju-log the message unstead.
236+
237+ workload_state -- valid juju workload state.
238+ message -- status update message
239+ """
240+ valid_states = ['maintenance', 'blocked', 'waiting', 'active']
241+ if workload_state not in valid_states:
242+ raise ValueError(
243+ '{!r} is not a valid workload state'.format(workload_state)
244+ )
245+ cmd = ['status-set', workload_state, message]
246+ try:
247+ ret = subprocess.call(cmd)
248+ if ret == 0:
249+ return
250+ except OSError as e:
251+ if e.errno != errno.ENOENT:
252+ raise
253+ log_message = 'status-set failed: {} {}'.format(workload_state,
254+ message)
255+ log(log_message, level='INFO')
256+
257+
258+def status_get():
259+ """Retrieve the previously set juju workload state
260+
261+ If the status-set command is not found then assume this is juju < 1.23 and
262+ return 'unknown'
263+ """
264+ cmd = ['status-get']
265+ try:
266+ raw_status = subprocess.check_output(cmd, universal_newlines=True)
267+ status = raw_status.rstrip()
268+ return status
269+ except OSError as e:
270+ if e.errno == errno.ENOENT:
271+ return 'unknown'
272+ else:
273+ raise
274
275=== modified file 'hooks/charmhelpers/core/host.py'
276--- hooks/charmhelpers/core/host.py 2015-03-31 15:13:53 +0000
277+++ hooks/charmhelpers/core/host.py 2015-05-20 19:44:14 +0000
278@@ -90,7 +90,7 @@
279 ['service', service_name, 'status'],
280 stderr=subprocess.STDOUT).decode('UTF-8')
281 except subprocess.CalledProcessError as e:
282- return 'unrecognized service' not in e.output
283+ return b'unrecognized service' not in e.output
284 else:
285 return True
286
287
288=== modified file 'hooks/charmhelpers/core/services/base.py'
289--- hooks/charmhelpers/core/services/base.py 2015-02-24 12:07:07 +0000
290+++ hooks/charmhelpers/core/services/base.py 2015-05-20 19:44:14 +0000
291@@ -17,7 +17,7 @@
292 import os
293 import re
294 import json
295-from collections import Iterable
296+from collections import Iterable, OrderedDict
297
298 from charmhelpers.core import host
299 from charmhelpers.core import hookenv
300@@ -119,7 +119,7 @@
301 """
302 self._ready_file = os.path.join(hookenv.charm_dir(), 'READY-SERVICES.json')
303 self._ready = None
304- self.services = {}
305+ self.services = OrderedDict()
306 for service in services or []:
307 service_name = service['service']
308 self.services[service_name] = service
309
310=== modified file 'hooks/charmhelpers/fetch/__init__.py'
311--- hooks/charmhelpers/fetch/__init__.py 2015-03-31 15:13:53 +0000
312+++ hooks/charmhelpers/fetch/__init__.py 2015-05-20 19:44:14 +0000
313@@ -158,7 +158,7 @@
314
315 def apt_cache(in_memory=True):
316 """Build and return an apt cache"""
317- import apt_pkg
318+ from apt import apt_pkg
319 apt_pkg.init()
320 if in_memory:
321 apt_pkg.config.set("Dir::Cache::pkgcache", "")
322
323=== modified file 'unit_tests/test_neutron_utils.py'
324--- unit_tests/test_neutron_utils.py 2015-05-07 09:27:07 +0000
325+++ unit_tests/test_neutron_utils.py 2015-05-20 19:44:14 +0000
326@@ -930,7 +930,8 @@
327 'process_name': 'neutron-nvsd-agent',
328 'executable_name': '/usr/local/bin/neutron-nvsd-agent',
329 'config_files': ['/etc/neutron/neutron.conf',
330- '/etc/neutron/plugins/oneconvergence/nvsdplugin.ini'],
331+ '/etc/neutron/plugins/oneconvergence/'
332+ 'nvsdplugin.ini'],
333 'log_file': '/var/log/neutron/nvsd-agent.log',
334 }
335 neutron_plugin_openflow_context = {

Subscribers

People subscribed via source and target branches