Merge lp:~1chb1n/charms/trusty/neutron-api/next-amulet-15.10 into lp:~openstack-charmers-archive/charms/trusty/neutron-api/next
- Trusty Tahr (14.04)
- next-amulet-15.10
- Merge into next
Status: | Merged |
---|---|
Merged at revision: | 153 |
Proposed branch: | lp:~1chb1n/charms/trusty/neutron-api/next-amulet-15.10 |
Merge into: | lp:~openstack-charmers-archive/charms/trusty/neutron-api/next |
Diff against target: |
448 lines (+177/-35) 11 files modified
hooks/charmhelpers/contrib/openstack/amulet/deployment.py (+40/-0) hooks/charmhelpers/contrib/openstack/amulet/utils.py (+1/-1) hooks/charmhelpers/contrib/openstack/context.py (+40/-13) hooks/charmhelpers/contrib/openstack/neutron.py (+17/-3) hooks/charmhelpers/contrib/openstack/templates/ceph.conf (+6/-0) hooks/charmhelpers/contrib/openstack/utils.py (+1/-0) hooks/charmhelpers/core/hookenv.py (+0/-1) hooks/charmhelpers/core/host.py (+12/-1) tests/basic_deployment.py (+19/-15) tests/charmhelpers/contrib/openstack/amulet/deployment.py (+40/-0) tests/charmhelpers/contrib/openstack/amulet/utils.py (+1/-1) |
To merge this branch: | bzr merge lp:~1chb1n/charms/trusty/neutron-api/next-amulet-15.10 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Liam Young (community) | Approve | ||
Review via email: mp+274709@code.launchpad.net |
Commit message
Description of the change
Update amulet tests for Trusty-Liberty, Wily-Liberty.
Sync charmhelpers.
Add service and relations to satisfy workload status ready state.
Add new logic to wait for extended status message to confirm deploy is ready, before testing.
uosci-testing-bot (uosci-testing-bot) wrote : | # |
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #11175 neutron-api-next for 1chb1n mp274709
UNIT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #7386 neutron-api-next for 1chb1n mp274709
AMULET FAIL: amulet-test failed
AMULET Results (max last 2 lines):
make: *** [functional_test] Error 1
ERROR:root:Make target returned non-zero.
Full amulet test output: http://
Build: http://
- 157. By Ryan Beisner
-
fix relation check, remove varying unit data check
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #12028 neutron-api-next for 1chb1n mp274709
LINT OK: passed
Build: http://
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #11177 neutron-api-next for 1chb1n mp274709
UNIT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #7391 neutron-api-next for 1chb1n mp274709
AMULET OK: passed
Build: http://
Preview Diff
1 | === modified file 'hooks/charmhelpers/contrib/openstack/amulet/deployment.py' |
2 | --- hooks/charmhelpers/contrib/openstack/amulet/deployment.py 2015-09-25 14:35:35 +0000 |
3 | +++ hooks/charmhelpers/contrib/openstack/amulet/deployment.py 2015-10-16 16:14:02 +0000 |
4 | @@ -14,6 +14,7 @@ |
5 | # You should have received a copy of the GNU Lesser General Public License |
6 | # along with charm-helpers. If not, see <http://www.gnu.org/licenses/>. |
7 | |
8 | +import re |
9 | import six |
10 | from collections import OrderedDict |
11 | from charmhelpers.contrib.amulet.deployment import ( |
12 | @@ -114,6 +115,45 @@ |
13 | for service, config in six.iteritems(configs): |
14 | self.d.configure(service, config) |
15 | |
16 | + def _auto_wait_for_status(self, message=None, exclude_services=None, |
17 | + timeout=1800): |
18 | + """Wait for all units to have a specific extended status, except |
19 | + for any defined as excluded. Unless specified via message, any |
20 | + status containing any case of 'ready' will be considered a match. |
21 | + |
22 | + Examples of message usage: |
23 | + |
24 | + Wait for all unit status to CONTAIN any case of 'ready' or 'ok': |
25 | + message = re.compile('.*ready.*|.*ok.*', re.IGNORECASE) |
26 | + |
27 | + Wait for all units to reach this status (exact match): |
28 | + message = 'Unit is ready' |
29 | + |
30 | + Wait for all units to reach any one of these (exact match): |
31 | + message = re.compile('Unit is ready|OK|Ready') |
32 | + |
33 | + Wait for at least one unit to reach this status (exact match): |
34 | + message = {'ready'} |
35 | + |
36 | + See Amulet's sentry.wait_for_messages() for message usage detail. |
37 | + https://github.com/juju/amulet/blob/master/amulet/sentry.py |
38 | + |
39 | + :param message: Expected status match |
40 | + :param exclude_services: List of juju service names to ignore |
41 | + :param timeout: Maximum time in seconds to wait for status match |
42 | + :returns: None. Raises if timeout is hit. |
43 | + """ |
44 | + |
45 | + if not message: |
46 | + message = re.compile('.*ready.*', re.IGNORECASE) |
47 | + |
48 | + if not exclude_services: |
49 | + exclude_services = [] |
50 | + |
51 | + services = list(set(self.d.services.keys()) - set(exclude_services)) |
52 | + service_messages = {service: message for service in services} |
53 | + self.d.sentry.wait_for_messages(service_messages, timeout=timeout) |
54 | + |
55 | def _get_openstack_release(self): |
56 | """Get openstack release. |
57 | |
58 | |
59 | === modified file 'hooks/charmhelpers/contrib/openstack/amulet/utils.py' |
60 | --- hooks/charmhelpers/contrib/openstack/amulet/utils.py 2015-09-25 14:35:35 +0000 |
61 | +++ hooks/charmhelpers/contrib/openstack/amulet/utils.py 2015-10-16 16:14:02 +0000 |
62 | @@ -752,7 +752,7 @@ |
63 | self.log.debug('SSL is enabled @{}:{} ' |
64 | '({})'.format(host, port, unit_name)) |
65 | return True |
66 | - elif not port and not conf_ssl: |
67 | + elif not conf_ssl: |
68 | self.log.debug('SSL not enabled @{}:{} ' |
69 | '({})'.format(host, port, unit_name)) |
70 | return False |
71 | |
72 | === modified file 'hooks/charmhelpers/contrib/openstack/context.py' |
73 | --- hooks/charmhelpers/contrib/openstack/context.py 2015-09-28 19:06:04 +0000 |
74 | +++ hooks/charmhelpers/contrib/openstack/context.py 2015-10-16 16:14:02 +0000 |
75 | @@ -14,6 +14,7 @@ |
76 | # You should have received a copy of the GNU Lesser General Public License |
77 | # along with charm-helpers. If not, see <http://www.gnu.org/licenses/>. |
78 | |
79 | +import glob |
80 | import json |
81 | import os |
82 | import re |
83 | @@ -951,6 +952,19 @@ |
84 | 'config': config} |
85 | return ovs_ctxt |
86 | |
87 | + def midonet_ctxt(self): |
88 | + driver = neutron_plugin_attribute(self.plugin, 'driver', |
89 | + self.network_manager) |
90 | + midonet_config = neutron_plugin_attribute(self.plugin, 'config', |
91 | + self.network_manager) |
92 | + mido_ctxt = {'core_plugin': driver, |
93 | + 'neutron_plugin': 'midonet', |
94 | + 'neutron_security_groups': self.neutron_security_groups, |
95 | + 'local_ip': unit_private_ip(), |
96 | + 'config': midonet_config} |
97 | + |
98 | + return mido_ctxt |
99 | + |
100 | def __call__(self): |
101 | if self.network_manager not in ['quantum', 'neutron']: |
102 | return {} |
103 | @@ -972,6 +986,8 @@ |
104 | ctxt.update(self.nuage_ctxt()) |
105 | elif self.plugin == 'plumgrid': |
106 | ctxt.update(self.pg_ctxt()) |
107 | + elif self.plugin == 'midonet': |
108 | + ctxt.update(self.midonet_ctxt()) |
109 | |
110 | alchemy_flags = config('neutron-alchemy-flags') |
111 | if alchemy_flags: |
112 | @@ -1104,7 +1120,7 @@ |
113 | |
114 | ctxt = { |
115 | ... other context ... |
116 | - 'subordinate_config': { |
117 | + 'subordinate_configuration': { |
118 | 'DEFAULT': { |
119 | 'key1': 'value1', |
120 | }, |
121 | @@ -1145,22 +1161,23 @@ |
122 | try: |
123 | sub_config = json.loads(sub_config) |
124 | except: |
125 | - log('Could not parse JSON from subordinate_config ' |
126 | - 'setting from %s' % rid, level=ERROR) |
127 | + log('Could not parse JSON from ' |
128 | + 'subordinate_configuration setting from %s' |
129 | + % rid, level=ERROR) |
130 | continue |
131 | |
132 | for service in self.services: |
133 | if service not in sub_config: |
134 | - log('Found subordinate_config on %s but it contained' |
135 | - 'nothing for %s service' % (rid, service), |
136 | - level=INFO) |
137 | + log('Found subordinate_configuration on %s but it ' |
138 | + 'contained nothing for %s service' |
139 | + % (rid, service), level=INFO) |
140 | continue |
141 | |
142 | sub_config = sub_config[service] |
143 | if self.config_file not in sub_config: |
144 | - log('Found subordinate_config on %s but it contained' |
145 | - 'nothing for %s' % (rid, self.config_file), |
146 | - level=INFO) |
147 | + log('Found subordinate_configuration on %s but it ' |
148 | + 'contained nothing for %s' |
149 | + % (rid, self.config_file), level=INFO) |
150 | continue |
151 | |
152 | sub_config = sub_config[self.config_file] |
153 | @@ -1363,7 +1380,7 @@ |
154 | normalized.update({port: port for port in resolved |
155 | if port in ports}) |
156 | if resolved: |
157 | - return {bridge: normalized[port] for port, bridge in |
158 | + return {normalized[port]: bridge for port, bridge in |
159 | six.iteritems(portmap) if port in normalized.keys()} |
160 | |
161 | return None |
162 | @@ -1374,12 +1391,22 @@ |
163 | def __call__(self): |
164 | ctxt = {} |
165 | mappings = super(PhyNICMTUContext, self).__call__() |
166 | - if mappings and mappings.values(): |
167 | - ports = mappings.values() |
168 | + if mappings and mappings.keys(): |
169 | + ports = sorted(mappings.keys()) |
170 | napi_settings = NeutronAPIContext()() |
171 | mtu = napi_settings.get('network_device_mtu') |
172 | + all_ports = set() |
173 | + # If any of ports is a vlan device, its underlying device must have |
174 | + # mtu applied first. |
175 | + for port in ports: |
176 | + for lport in glob.glob("/sys/class/net/%s/lower_*" % port): |
177 | + lport = os.path.basename(lport) |
178 | + all_ports.add(lport.split('_')[1]) |
179 | + |
180 | + all_ports = list(all_ports) |
181 | + all_ports.extend(ports) |
182 | if mtu: |
183 | - ctxt["devs"] = '\\n'.join(ports) |
184 | + ctxt["devs"] = '\\n'.join(all_ports) |
185 | ctxt['mtu'] = mtu |
186 | |
187 | return ctxt |
188 | |
189 | === modified file 'hooks/charmhelpers/contrib/openstack/neutron.py' |
190 | --- hooks/charmhelpers/contrib/openstack/neutron.py 2015-09-04 11:03:14 +0000 |
191 | +++ hooks/charmhelpers/contrib/openstack/neutron.py 2015-10-16 16:14:02 +0000 |
192 | @@ -209,6 +209,20 @@ |
193 | 'server_packages': ['neutron-server', |
194 | 'neutron-plugin-plumgrid'], |
195 | 'server_services': ['neutron-server'] |
196 | + }, |
197 | + 'midonet': { |
198 | + 'config': '/etc/neutron/plugins/midonet/midonet.ini', |
199 | + 'driver': 'midonet.neutron.plugin.MidonetPluginV2', |
200 | + 'contexts': [ |
201 | + context.SharedDBContext(user=config('neutron-database-user'), |
202 | + database=config('neutron-database'), |
203 | + relation_prefix='neutron', |
204 | + ssl_dir=NEUTRON_CONF_DIR)], |
205 | + 'services': [], |
206 | + 'packages': [[headers_package()] + determine_dkms_package()], |
207 | + 'server_packages': ['neutron-server', |
208 | + 'python-neutron-plugin-midonet'], |
209 | + 'server_services': ['neutron-server'] |
210 | } |
211 | } |
212 | if release >= 'icehouse': |
213 | @@ -310,10 +324,10 @@ |
214 | def parse_data_port_mappings(mappings, default_bridge='br-data'): |
215 | """Parse data port mappings. |
216 | |
217 | - Mappings must be a space-delimited list of port:bridge mappings. |
218 | + Mappings must be a space-delimited list of bridge:port. |
219 | |
220 | - Returns dict of the form {port:bridge} where port may be an mac address or |
221 | - interface name. |
222 | + Returns dict of the form {port:bridge} where ports may be mac addresses or |
223 | + interface names. |
224 | """ |
225 | |
226 | # NOTE(dosaboy): we use rvalue for key to allow multiple values to be |
227 | |
228 | === modified file 'hooks/charmhelpers/contrib/openstack/templates/ceph.conf' |
229 | --- hooks/charmhelpers/contrib/openstack/templates/ceph.conf 2015-07-16 20:17:53 +0000 |
230 | +++ hooks/charmhelpers/contrib/openstack/templates/ceph.conf 2015-10-16 16:14:02 +0000 |
231 | @@ -13,3 +13,9 @@ |
232 | err to syslog = {{ use_syslog }} |
233 | clog to syslog = {{ use_syslog }} |
234 | |
235 | +[client] |
236 | +{% if rbd_client_cache_settings -%} |
237 | +{% for key, value in rbd_client_cache_settings.iteritems() -%} |
238 | +{{ key }} = {{ value }} |
239 | +{% endfor -%} |
240 | +{%- endif %} |
241 | \ No newline at end of file |
242 | |
243 | === modified file 'hooks/charmhelpers/contrib/openstack/utils.py' |
244 | --- hooks/charmhelpers/contrib/openstack/utils.py 2015-10-06 07:11:01 +0000 |
245 | +++ hooks/charmhelpers/contrib/openstack/utils.py 2015-10-16 16:14:02 +0000 |
246 | @@ -121,6 +121,7 @@ |
247 | ('2.2.2', 'kilo'), |
248 | ('2.3.0', 'liberty'), |
249 | ('2.4.0', 'liberty'), |
250 | + ('2.5.0', 'liberty'), |
251 | ]) |
252 | |
253 | # >= Liberty version->codename mapping |
254 | |
255 | === modified file 'hooks/charmhelpers/core/hookenv.py' |
256 | --- hooks/charmhelpers/core/hookenv.py 2015-09-28 19:06:04 +0000 |
257 | +++ hooks/charmhelpers/core/hookenv.py 2015-10-16 16:14:02 +0000 |
258 | @@ -795,7 +795,6 @@ |
259 | raise |
260 | log_message = 'status-set failed: {} {}'.format(workload_state, |
261 | message) |
262 | - # XXX Fix this |
263 | log(log_message, level='INFO') |
264 | |
265 | |
266 | |
267 | === modified file 'hooks/charmhelpers/core/host.py' |
268 | --- hooks/charmhelpers/core/host.py 2015-09-25 14:35:35 +0000 |
269 | +++ hooks/charmhelpers/core/host.py 2015-10-16 16:14:02 +0000 |
270 | @@ -566,7 +566,14 @@ |
271 | os.chdir(cur) |
272 | |
273 | |
274 | -def chownr(path, owner, group, follow_links=True): |
275 | +def chownr(path, owner, group, follow_links=True, chowntopdir=False): |
276 | + """ |
277 | + Recursively change user and group ownership of files and directories |
278 | + in given path. Doesn't chown path itself by default, only its children. |
279 | + |
280 | + :param bool follow_links: Also Chown links if True |
281 | + :param bool chowntopdir: Also chown path itself if True |
282 | + """ |
283 | uid = pwd.getpwnam(owner).pw_uid |
284 | gid = grp.getgrnam(group).gr_gid |
285 | if follow_links: |
286 | @@ -574,6 +581,10 @@ |
287 | else: |
288 | chown = os.lchown |
289 | |
290 | + if chowntopdir: |
291 | + broken_symlink = os.path.lexists(path) and not os.path.exists(path) |
292 | + if not broken_symlink: |
293 | + chown(path, uid, gid) |
294 | for root, dirs, files in os.walk(path): |
295 | for name in dirs + files: |
296 | full = os.path.join(root, name) |
297 | |
298 | === modified file 'tests/020-basic-trusty-liberty' (properties changed: -x to +x) |
299 | === modified file 'tests/021-basic-wily-liberty' (properties changed: -x to +x) |
300 | === modified file 'tests/basic_deployment.py' |
301 | --- tests/basic_deployment.py 2015-09-28 19:06:04 +0000 |
302 | +++ tests/basic_deployment.py 2015-10-16 16:14:02 +0000 |
303 | @@ -1,11 +1,5 @@ |
304 | -#!/usr/bin/python |
305 | -""" |
306 | -Basic neutron-api functional test. |
307 | -""" |
308 | - |
309 | import amulet |
310 | import os |
311 | -import time |
312 | import yaml |
313 | |
314 | from charmhelpers.contrib.openstack.amulet.deployment import ( |
315 | @@ -35,6 +29,11 @@ |
316 | self._add_relations() |
317 | self._configure_services() |
318 | self._deploy() |
319 | + |
320 | + u.log.info('Waiting on extended status checks...') |
321 | + exclude_services = ['mysql'] |
322 | + self._auto_wait_for_status(exclude_services=exclude_services) |
323 | + |
324 | self._initialize_tests() |
325 | |
326 | def _add_services(self): |
327 | @@ -48,6 +47,7 @@ |
328 | other_services = [{'name': 'mysql'}, |
329 | {'name': 'rabbitmq-server'}, |
330 | {'name': 'keystone'}, |
331 | + {'name': 'glance'}, # to satisfy workload status |
332 | {'name': 'neutron-openvswitch'}, |
333 | {'name': 'nova-cloud-controller'}, |
334 | {'name': 'neutron-gateway'}, |
335 | @@ -68,6 +68,19 @@ |
336 | 'nova-compute:neutron-plugin': 'neutron-openvswitch:' |
337 | 'neutron-plugin', |
338 | 'nova-cloud-controller:shared-db': 'mysql:shared-db', |
339 | + 'neutron-gateway:amqp': 'rabbitmq-server:amqp', |
340 | + 'nova-cloud-controller:amqp': 'rabbitmq-server:amqp', |
341 | + 'nova-compute:amqp': 'rabbitmq-server:amqp', |
342 | + 'neutron-openvswitch:amqp': 'rabbitmq-server:amqp', |
343 | + 'nova-cloud-controller:identity-service': 'keystone:' |
344 | + 'identity-service', |
345 | + 'nova-cloud-controller:cloud-compute': 'nova-compute:' |
346 | + 'cloud-compute', |
347 | + 'glance:identity-service': 'keystone:identity-service', |
348 | + 'glance:shared-db': 'mysql:shared-db', |
349 | + 'glance:amqp': 'rabbitmq-server:amqp', |
350 | + 'nova-compute:image-service': 'glance:image-service', |
351 | + 'nova-cloud-controller:image-service': 'glance:image-service', |
352 | } |
353 | |
354 | # NOTE(beisner): relate this separately due to the resulting |
355 | @@ -158,8 +171,6 @@ |
356 | self._get_openstack_release())) |
357 | u.log.debug('openstack release str: {}'.format( |
358 | self._get_openstack_release_string())) |
359 | - # Let things settle a bit before moving forward |
360 | - time.sleep(30) |
361 | |
362 | def test_100_services(self): |
363 | """Verify the expected services are running on the corresponding |
364 | @@ -226,13 +237,6 @@ |
365 | 'password': u.not_null |
366 | } |
367 | |
368 | - if self._get_openstack_release() == self.precise_icehouse: |
369 | - # Precise |
370 | - expected['allowed_units'] = 'nova-cloud-controller/0 neutron-api/0' |
371 | - else: |
372 | - # Not Precise |
373 | - expected['allowed_units'] = 'neutron-api/0' |
374 | - |
375 | ret = u.validate_relation_data(unit, relation, expected) |
376 | if ret: |
377 | message = u.relation_error('mysql shared-db', ret) |
378 | |
379 | === modified file 'tests/charmhelpers/contrib/openstack/amulet/deployment.py' |
380 | --- tests/charmhelpers/contrib/openstack/amulet/deployment.py 2015-09-25 14:35:35 +0000 |
381 | +++ tests/charmhelpers/contrib/openstack/amulet/deployment.py 2015-10-16 16:14:02 +0000 |
382 | @@ -14,6 +14,7 @@ |
383 | # You should have received a copy of the GNU Lesser General Public License |
384 | # along with charm-helpers. If not, see <http://www.gnu.org/licenses/>. |
385 | |
386 | +import re |
387 | import six |
388 | from collections import OrderedDict |
389 | from charmhelpers.contrib.amulet.deployment import ( |
390 | @@ -114,6 +115,45 @@ |
391 | for service, config in six.iteritems(configs): |
392 | self.d.configure(service, config) |
393 | |
394 | + def _auto_wait_for_status(self, message=None, exclude_services=None, |
395 | + timeout=1800): |
396 | + """Wait for all units to have a specific extended status, except |
397 | + for any defined as excluded. Unless specified via message, any |
398 | + status containing any case of 'ready' will be considered a match. |
399 | + |
400 | + Examples of message usage: |
401 | + |
402 | + Wait for all unit status to CONTAIN any case of 'ready' or 'ok': |
403 | + message = re.compile('.*ready.*|.*ok.*', re.IGNORECASE) |
404 | + |
405 | + Wait for all units to reach this status (exact match): |
406 | + message = 'Unit is ready' |
407 | + |
408 | + Wait for all units to reach any one of these (exact match): |
409 | + message = re.compile('Unit is ready|OK|Ready') |
410 | + |
411 | + Wait for at least one unit to reach this status (exact match): |
412 | + message = {'ready'} |
413 | + |
414 | + See Amulet's sentry.wait_for_messages() for message usage detail. |
415 | + https://github.com/juju/amulet/blob/master/amulet/sentry.py |
416 | + |
417 | + :param message: Expected status match |
418 | + :param exclude_services: List of juju service names to ignore |
419 | + :param timeout: Maximum time in seconds to wait for status match |
420 | + :returns: None. Raises if timeout is hit. |
421 | + """ |
422 | + |
423 | + if not message: |
424 | + message = re.compile('.*ready.*', re.IGNORECASE) |
425 | + |
426 | + if not exclude_services: |
427 | + exclude_services = [] |
428 | + |
429 | + services = list(set(self.d.services.keys()) - set(exclude_services)) |
430 | + service_messages = {service: message for service in services} |
431 | + self.d.sentry.wait_for_messages(service_messages, timeout=timeout) |
432 | + |
433 | def _get_openstack_release(self): |
434 | """Get openstack release. |
435 | |
436 | |
437 | === modified file 'tests/charmhelpers/contrib/openstack/amulet/utils.py' |
438 | --- tests/charmhelpers/contrib/openstack/amulet/utils.py 2015-09-25 14:35:35 +0000 |
439 | +++ tests/charmhelpers/contrib/openstack/amulet/utils.py 2015-10-16 16:14:02 +0000 |
440 | @@ -752,7 +752,7 @@ |
441 | self.log.debug('SSL is enabled @{}:{} ' |
442 | '({})'.format(host, port, unit_name)) |
443 | return True |
444 | - elif not port and not conf_ssl: |
445 | + elif not conf_ssl: |
446 | self.log.debug('SSL not enabled @{}:{} ' |
447 | '({})'.format(host, port, unit_name)) |
448 | return False |
charm_lint_check #12024 neutron-api-next for 1chb1n mp274709
LINT OK: passed
Build: http:// 10.245. 162.77: 8080/job/ charm_lint_ check/12024/