Merge lp:~1chb1n/charms/trusty/neutron-api/next-amulet-15.10 into lp:~openstack-charmers-archive/charms/trusty/neutron-api/next

Proposed by Ryan Beisner
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
Reviewer Review Type Date Requested Status
Liam Young (community) Approve
Review via email: mp+274709@code.launchpad.net

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.

To post a comment you must log in.
Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

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/

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

charm_unit_test #11175 neutron-api-next for 1chb1n mp274709
    UNIT OK: passed

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

Revision history for this message
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://paste.ubuntu.com/12799468/
Build: http://10.245.162.77:8080/job/charm_amulet_test/7386/

157. By Ryan Beisner

fix relation check, remove varying unit data check

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

charm_lint_check #12028 neutron-api-next for 1chb1n mp274709
    LINT OK: passed

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

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

charm_unit_test #11177 neutron-api-next for 1chb1n mp274709
    UNIT OK: passed

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

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

charm_amulet_test #7391 neutron-api-next for 1chb1n mp274709
    AMULET OK: passed

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

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 '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

Subscribers

People subscribed via source and target branches