Merge lp:~1chb1n/charms/trusty/nova-compute/next-amulet-15.10 into lp:~openstack-charmers-archive/charms/trusty/nova-compute/next
- Trusty Tahr (14.04)
- next-amulet-15.10
- Merge into next
Proposed by
Ryan Beisner
Status: | Merged |
---|---|
Merged at revision: | 175 |
Proposed branch: | lp:~1chb1n/charms/trusty/nova-compute/next-amulet-15.10 |
Merge into: | lp:~openstack-charmers-archive/charms/trusty/nova-compute/next |
Diff against target: |
632 lines (+249/-120) 5 files modified
tests/020-basic-trusty-liberty (+11/-0) tests/021-basic-wily-liberty (+9/-0) tests/README (+10/-0) tests/basic_deployment.py (+179/-120) tests/charmhelpers/contrib/openstack/amulet/deployment.py (+40/-0) |
To merge this branch: | bzr merge lp:~1chb1n/charms/trusty/nova-compute/next-amulet-15.10 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Liam Young (community) | Approve | ||
Review via email: mp+274659@code.launchpad.net |
Commit message
Description of the change
Update amulet tests for Vivid-Kilo, Trusty-Liberty, prep for Wily-Liberty.
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 : | # |
Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #11170 nova-compute-next for 1chb1n mp274659
UNIT OK: passed
Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #7381 nova-compute-next for 1chb1n mp274659
AMULET OK: passed
Build: http://
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'tests/019-basic-vivid-kilo' (properties changed: -x to +x) |
2 | === added file 'tests/020-basic-trusty-liberty' |
3 | --- tests/020-basic-trusty-liberty 1970-01-01 00:00:00 +0000 |
4 | +++ tests/020-basic-trusty-liberty 2015-10-16 05:42:31 +0000 |
5 | @@ -0,0 +1,11 @@ |
6 | +#!/usr/bin/python |
7 | + |
8 | +"""Amulet tests on a basic nova compute deployment on trusty-liberty.""" |
9 | + |
10 | +from basic_deployment import NovaBasicDeployment |
11 | + |
12 | +if __name__ == '__main__': |
13 | + deployment = NovaBasicDeployment(series='trusty', |
14 | + openstack='cloud:trusty-liberty', |
15 | + source='cloud:trusty-updates/liberty') |
16 | + deployment.run_tests() |
17 | |
18 | === added file 'tests/021-basic-wily-liberty' |
19 | --- tests/021-basic-wily-liberty 1970-01-01 00:00:00 +0000 |
20 | +++ tests/021-basic-wily-liberty 2015-10-16 05:42:31 +0000 |
21 | @@ -0,0 +1,9 @@ |
22 | +#!/usr/bin/python |
23 | + |
24 | +"""Amulet tests on a basic nova compute deployment on wily-liberty.""" |
25 | + |
26 | +from basic_deployment import NovaBasicDeployment |
27 | + |
28 | +if __name__ == '__main__': |
29 | + deployment = NovaBasicDeployment(series='wily') |
30 | + deployment.run_tests() |
31 | |
32 | === modified file 'tests/README' |
33 | --- tests/README 2014-09-30 20:31:36 +0000 |
34 | +++ tests/README 2015-10-16 05:42:31 +0000 |
35 | @@ -1,6 +1,16 @@ |
36 | This directory provides Amulet tests that focus on verification of nova-compute |
37 | deployments. |
38 | |
39 | +test_* methods are called in lexical sort order, although each individual test |
40 | +should be idempotent, and expected to pass regardless of run order. |
41 | + |
42 | +Test name convention to ensure desired test order: |
43 | + 1xx service and endpoint checks |
44 | + 2xx relation checks |
45 | + 3xx config checks |
46 | + 4xx functional checks |
47 | + 9xx restarts and other final checks |
48 | + |
49 | In order to run tests, you'll need charm-tools installed (in addition to |
50 | juju, of course): |
51 | sudo add-apt-repository ppa:juju/stable |
52 | |
53 | === modified file 'tests/basic_deployment.py' |
54 | --- tests/basic_deployment.py 2015-10-02 09:40:38 +0000 |
55 | +++ tests/basic_deployment.py 2015-10-16 05:42:31 +0000 |
56 | @@ -1,8 +1,5 @@ |
57 | -#!/usr/bin/python |
58 | - |
59 | import amulet |
60 | import os |
61 | -import time |
62 | import yaml |
63 | |
64 | from charmhelpers.contrib.openstack.amulet.deployment import ( |
65 | @@ -11,8 +8,8 @@ |
66 | |
67 | from charmhelpers.contrib.openstack.amulet.utils import ( |
68 | OpenStackAmuletUtils, |
69 | - DEBUG, # flake8: noqa |
70 | - ERROR |
71 | + DEBUG, |
72 | + # ERROR |
73 | ) |
74 | |
75 | # Use DEBUG to turn on debug logging |
76 | @@ -22,15 +19,21 @@ |
77 | class NovaBasicDeployment(OpenStackAmuletDeployment): |
78 | """Amulet tests on a basic nova compute deployment.""" |
79 | |
80 | - def __init__(self, series=None, openstack=None, source=None, git=False, |
81 | - stable=False): |
82 | + def __init__(self, series=None, openstack=None, source=None, |
83 | + git=False, stable=False): |
84 | """Deploy the entire test environment.""" |
85 | - super(NovaBasicDeployment, self).__init__(series, openstack, source, stable) |
86 | + super(NovaBasicDeployment, self).__init__(series, openstack, |
87 | + source, stable) |
88 | self.git = git |
89 | self._add_services() |
90 | self._add_relations() |
91 | self._configure_services() |
92 | self._deploy() |
93 | + |
94 | + u.log.info('Waiting on extended status checks...') |
95 | + exclude_services = ['mysql'] |
96 | + self._auto_wait_for_status(exclude_services=exclude_services) |
97 | + |
98 | self._initialize_tests() |
99 | |
100 | def _add_services(self): |
101 | @@ -41,8 +44,10 @@ |
102 | compatible with the local charm (e.g. stable or next). |
103 | """ |
104 | this_service = {'name': 'nova-compute'} |
105 | - other_services = [{'name': 'mysql'}, {'name': 'rabbitmq-server'}, |
106 | - {'name': 'nova-cloud-controller'}, {'name': 'keystone'}, |
107 | + other_services = [{'name': 'mysql'}, |
108 | + {'name': 'rabbitmq-server'}, |
109 | + {'name': 'nova-cloud-controller'}, |
110 | + {'name': 'keystone'}, |
111 | {'name': 'glance'}] |
112 | super(NovaBasicDeployment, self)._add_services(this_service, |
113 | other_services) |
114 | @@ -50,18 +55,20 @@ |
115 | def _add_relations(self): |
116 | """Add all of the relations for the services.""" |
117 | relations = { |
118 | - 'nova-compute:image-service': 'glance:image-service', |
119 | - 'nova-compute:shared-db': 'mysql:shared-db', |
120 | - 'nova-compute:amqp': 'rabbitmq-server:amqp', |
121 | - 'nova-cloud-controller:shared-db': 'mysql:shared-db', |
122 | - 'nova-cloud-controller:identity-service': 'keystone:identity-service', |
123 | - 'nova-cloud-controller:amqp': 'rabbitmq-server:amqp', |
124 | - 'nova-cloud-controller:cloud-compute': 'nova-compute:cloud-compute', |
125 | - 'nova-cloud-controller:image-service': 'glance:image-service', |
126 | - 'keystone:shared-db': 'mysql:shared-db', |
127 | - 'glance:identity-service': 'keystone:identity-service', |
128 | - 'glance:shared-db': 'mysql:shared-db', |
129 | - 'glance:amqp': 'rabbitmq-server:amqp' |
130 | + 'nova-compute:image-service': 'glance:image-service', |
131 | + 'nova-compute:shared-db': 'mysql:shared-db', |
132 | + 'nova-compute:amqp': 'rabbitmq-server:amqp', |
133 | + 'nova-cloud-controller:shared-db': 'mysql:shared-db', |
134 | + 'nova-cloud-controller:identity-service': 'keystone:' |
135 | + 'identity-service', |
136 | + 'nova-cloud-controller:amqp': 'rabbitmq-server:amqp', |
137 | + 'nova-cloud-controller:cloud-compute': 'nova-compute:' |
138 | + 'cloud-compute', |
139 | + 'nova-cloud-controller:image-service': 'glance:image-service', |
140 | + 'keystone:shared-db': 'mysql:shared-db', |
141 | + 'glance:identity-service': 'keystone:identity-service', |
142 | + 'glance:shared-db': 'mysql:shared-db', |
143 | + 'glance:amqp': 'rabbitmq-server:amqp' |
144 | } |
145 | super(NovaBasicDeployment, self)._add_relations(relations) |
146 | |
147 | @@ -86,7 +93,7 @@ |
148 | openstack_origin_git = { |
149 | 'repositories': [ |
150 | {'name': 'requirements', |
151 | - 'repository': reqs_repo, |
152 | + 'repository': reqs_repo, |
153 | 'branch': branch}, |
154 | {'name': 'neutron', |
155 | 'repository': neutron_repo, |
156 | @@ -99,8 +106,11 @@ |
157 | 'http_proxy': amulet_http_proxy, |
158 | 'https_proxy': amulet_http_proxy, |
159 | } |
160 | - nova_config['openstack-origin-git'] = yaml.dump(openstack_origin_git) |
161 | - nova_cc_config['openstack-origin-git'] = yaml.dump(openstack_origin_git) |
162 | + nova_config['openstack-origin-git'] = \ |
163 | + yaml.dump(openstack_origin_git) |
164 | + |
165 | + nova_cc_config['openstack-origin-git'] = \ |
166 | + yaml.dump(openstack_origin_git) |
167 | |
168 | keystone_config = {'admin-password': 'openstack', |
169 | 'admin-token': 'ubuntutesting'} |
170 | @@ -118,8 +128,10 @@ |
171 | self.nova_cc_sentry = self.d.sentry.unit['nova-cloud-controller/0'] |
172 | self.glance_sentry = self.d.sentry.unit['glance/0'] |
173 | |
174 | - # Let things settle a bit before moving forward |
175 | - time.sleep(30) |
176 | + u.log.debug('openstack release val: {}'.format( |
177 | + self._get_openstack_release())) |
178 | + u.log.debug('openstack release str: {}'.format( |
179 | + self._get_openstack_release_string())) |
180 | |
181 | # Authenticate admin with keystone |
182 | self.keystone = u.authenticate_keystone_admin(self.keystone_sentry, |
183 | @@ -156,32 +168,38 @@ |
184 | password='password', |
185 | tenant=self.demo_tenant) |
186 | |
187 | - def test_services(self): |
188 | + def test_100_services(self): |
189 | """Verify the expected services are running on the corresponding |
190 | service units.""" |
191 | - commands = { |
192 | - self.mysql_sentry: ['status mysql'], |
193 | - self.rabbitmq_sentry: ['sudo service rabbitmq-server status'], |
194 | - self.nova_compute_sentry: ['status nova-compute', |
195 | - 'status nova-network', |
196 | - 'status nova-api'], |
197 | - self.nova_cc_sentry: ['status nova-api-ec2', |
198 | - 'status nova-api-os-compute', |
199 | - 'status nova-objectstore', |
200 | - 'status nova-cert', |
201 | - 'status nova-scheduler'], |
202 | - self.keystone_sentry: ['status keystone'], |
203 | - self.glance_sentry: ['status glance-registry', 'status glance-api'] |
204 | + u.log.debug('Checking system services on units...') |
205 | + |
206 | + services = { |
207 | + self.mysql_sentry: ['mysql'], |
208 | + self.rabbitmq_sentry: ['rabbitmq-server'], |
209 | + self.nova_compute_sentry: ['nova-compute', |
210 | + 'nova-network', |
211 | + 'nova-api'], |
212 | + self.nova_cc_sentry: ['nova-api-ec2', |
213 | + 'nova-api-os-compute', |
214 | + 'nova-objectstore', |
215 | + 'nova-cert', |
216 | + 'nova-scheduler'], |
217 | + self.keystone_sentry: ['keystone'], |
218 | + self.glance_sentry: ['glance-registry', |
219 | + 'glance-api'] |
220 | } |
221 | + |
222 | if self._get_openstack_release() >= self.precise_grizzly: |
223 | - commands[self.nova_cc_sentry] = ['status nova-conductor'] |
224 | + services[self.nova_cc_sentry] = ['nova-conductor'] |
225 | |
226 | - ret = u.validate_services(commands) |
227 | + ret = u.validate_services_by_name(services) |
228 | if ret: |
229 | amulet.raise_status(amulet.FAIL, msg=ret) |
230 | |
231 | - def test_service_catalog(self): |
232 | + def test_102_service_catalog(self): |
233 | """Verify that the service catalog endpoint data is valid.""" |
234 | + u.log.debug('Checking keystone service catalog...') |
235 | + |
236 | endpoint_vol = {'adminURL': u.valid_url, |
237 | 'region': 'RegionOne', |
238 | 'publicURL': u.valid_url, |
239 | @@ -190,9 +208,11 @@ |
240 | 'region': 'RegionOne', |
241 | 'publicURL': u.valid_url, |
242 | 'internalURL': u.valid_url} |
243 | + |
244 | if self._get_openstack_release() >= self.precise_folsom: |
245 | endpoint_vol['id'] = u.not_null |
246 | endpoint_id['id'] = u.not_null |
247 | + |
248 | if self._get_openstack_release() >= self.trusty_kilo: |
249 | expected = {'compute': [endpoint_vol], 'identity': [endpoint_id]} |
250 | else: |
251 | @@ -204,16 +224,20 @@ |
252 | if ret: |
253 | amulet.raise_status(amulet.FAIL, msg=ret) |
254 | |
255 | - def test_openstack_compute_api_endpoint(self): |
256 | + def test_104_openstack_compute_api_endpoint(self): |
257 | """Verify the openstack compute api (osapi) endpoint data.""" |
258 | + u.log.debug('Checking compute endpoint data...') |
259 | + |
260 | endpoints = self.keystone.endpoints.list() |
261 | admin_port = internal_port = public_port = '8774' |
262 | - expected = {'id': u.not_null, |
263 | - 'region': 'RegionOne', |
264 | - 'adminurl': u.valid_url, |
265 | - 'internalurl': u.valid_url, |
266 | - 'publicurl': u.valid_url, |
267 | - 'service_id': u.not_null} |
268 | + expected = { |
269 | + 'id': u.not_null, |
270 | + 'region': 'RegionOne', |
271 | + 'adminurl': u.valid_url, |
272 | + 'internalurl': u.valid_url, |
273 | + 'publicurl': u.valid_url, |
274 | + 'service_id': u.not_null |
275 | + } |
276 | |
277 | ret = u.validate_endpoint_data(endpoints, admin_port, internal_port, |
278 | public_port, expected) |
279 | @@ -221,19 +245,22 @@ |
280 | message = 'osapi endpoint: {}'.format(ret) |
281 | amulet.raise_status(amulet.FAIL, msg=message) |
282 | |
283 | - def test_ec2_api_endpoint(self): |
284 | + def test_106_ec2_api_endpoint(self): |
285 | """Verify the EC2 api endpoint data.""" |
286 | if self._get_openstack_release() >= self.trusty_kilo: |
287 | return |
288 | |
289 | + u.log.debug('Checking ec2 endpoint data...') |
290 | endpoints = self.keystone.endpoints.list() |
291 | admin_port = internal_port = public_port = '8773' |
292 | - expected = {'id': u.not_null, |
293 | - 'region': 'RegionOne', |
294 | - 'adminurl': u.valid_url, |
295 | - 'internalurl': u.valid_url, |
296 | - 'publicurl': u.valid_url, |
297 | - 'service_id': u.not_null} |
298 | + expected = { |
299 | + 'id': u.not_null, |
300 | + 'region': 'RegionOne', |
301 | + 'adminurl': u.valid_url, |
302 | + 'internalurl': u.valid_url, |
303 | + 'publicurl': u.valid_url, |
304 | + 'service_id': u.not_null |
305 | + } |
306 | |
307 | ret = u.validate_endpoint_data(endpoints, admin_port, internal_port, |
308 | public_port, expected) |
309 | @@ -241,19 +268,22 @@ |
310 | message = 'EC2 endpoint: {}'.format(ret) |
311 | amulet.raise_status(amulet.FAIL, msg=message) |
312 | |
313 | - def test_s3_api_endpoint(self): |
314 | + def test_108_s3_api_endpoint(self): |
315 | """Verify the S3 api endpoint data.""" |
316 | if self._get_openstack_release() >= self.trusty_kilo: |
317 | return |
318 | |
319 | + u.log.debug('Checking s3 endpoint data...') |
320 | endpoints = self.keystone.endpoints.list() |
321 | admin_port = internal_port = public_port = '3333' |
322 | - expected = {'id': u.not_null, |
323 | - 'region': 'RegionOne', |
324 | - 'adminurl': u.valid_url, |
325 | - 'internalurl': u.valid_url, |
326 | - 'publicurl': u.valid_url, |
327 | - 'service_id': u.not_null} |
328 | + expected = { |
329 | + 'id': u.not_null, |
330 | + 'region': 'RegionOne', |
331 | + 'adminurl': u.valid_url, |
332 | + 'internalurl': u.valid_url, |
333 | + 'publicurl': u.valid_url, |
334 | + 'service_id': u.not_null |
335 | + } |
336 | |
337 | ret = u.validate_endpoint_data(endpoints, admin_port, internal_port, |
338 | public_port, expected) |
339 | @@ -261,8 +291,10 @@ |
340 | message = 'S3 endpoint: {}'.format(ret) |
341 | amulet.raise_status(amulet.FAIL, msg=message) |
342 | |
343 | - def test_nova_shared_db_relation(self): |
344 | + def test_200_nova_shared_db_relation(self): |
345 | """Verify the nova-compute to mysql shared-db relation data""" |
346 | + u.log.debug('Checking n-c:mysql db relation data...') |
347 | + |
348 | unit = self.nova_compute_sentry |
349 | relation = ['shared-db', 'mysql:shared-db'] |
350 | expected = { |
351 | @@ -277,8 +309,9 @@ |
352 | message = u.relation_error('nova-compute shared-db', ret) |
353 | amulet.raise_status(amulet.FAIL, msg=message) |
354 | |
355 | - def test_mysql_shared_db_relation(self): |
356 | + def test_202_mysql_shared_db_relation(self): |
357 | """Verify the mysql to nova-compute shared-db relation data""" |
358 | + u.log.debug('Checking mysql:n-c db relation data...') |
359 | unit = self.mysql_sentry |
360 | relation = ['shared-db', 'nova-compute:shared-db'] |
361 | expected = { |
362 | @@ -292,8 +325,9 @@ |
363 | message = u.relation_error('mysql shared-db', ret) |
364 | amulet.raise_status(amulet.FAIL, msg=message) |
365 | |
366 | - def test_nova_amqp_relation(self): |
367 | + def test_204_nova_amqp_relation(self): |
368 | """Verify the nova-compute to rabbitmq-server amqp relation data""" |
369 | + u.log.debug('Checking n-c:rmq amqp relation data...') |
370 | unit = self.nova_compute_sentry |
371 | relation = ['amqp', 'rabbitmq-server:amqp'] |
372 | expected = { |
373 | @@ -307,8 +341,9 @@ |
374 | message = u.relation_error('nova-compute amqp', ret) |
375 | amulet.raise_status(amulet.FAIL, msg=message) |
376 | |
377 | - def test_rabbitmq_amqp_relation(self): |
378 | + def test_206_rabbitmq_amqp_relation(self): |
379 | """Verify the rabbitmq-server to nova-compute amqp relation data""" |
380 | + u.log.debug('Checking rmq:n-c amqp relation data...') |
381 | unit = self.rabbitmq_sentry |
382 | relation = ['amqp', 'nova-compute:amqp'] |
383 | expected = { |
384 | @@ -322,8 +357,9 @@ |
385 | message = u.relation_error('rabbitmq amqp', ret) |
386 | amulet.raise_status(amulet.FAIL, msg=message) |
387 | |
388 | - def test_nova_cloud_compute_relation(self): |
389 | + def test_208_nova_cloud_compute_relation(self): |
390 | """Verify the nova-compute to nova-cc cloud-compute relation data""" |
391 | + u.log.debug('Checking n-c:n-c-c cloud-compute relation data...') |
392 | unit = self.nova_compute_sentry |
393 | relation = ['cloud-compute', 'nova-cloud-controller:cloud-compute'] |
394 | expected = { |
395 | @@ -335,8 +371,9 @@ |
396 | message = u.relation_error('nova-compute cloud-compute', ret) |
397 | amulet.raise_status(amulet.FAIL, msg=message) |
398 | |
399 | - def test_nova_cc_cloud_compute_relation(self): |
400 | + def test_210_nova_cc_cloud_compute_relation(self): |
401 | """Verify the nova-cc to nova-compute cloud-compute relation data""" |
402 | + u.log.debug('Checking n-c-c:n-c cloud-compute relation data...') |
403 | unit = self.nova_cc_sentry |
404 | relation = ['cloud-compute', 'nova-compute:cloud-compute'] |
405 | expected = { |
406 | @@ -354,52 +391,25 @@ |
407 | message = u.relation_error('nova-cc cloud-compute', ret) |
408 | amulet.raise_status(amulet.FAIL, msg=message) |
409 | |
410 | - def test_z_restart_on_config_change(self): |
411 | - """Verify that the specified services are restarted when the config |
412 | - is changed. |
413 | - |
414 | - Note(coreycb): The method name with the _z_ is a little odd |
415 | - but it forces the test to run last. It just makes things |
416 | - easier because restarting services requires re-authorization. |
417 | - """ |
418 | - # NOTE(coreycb): Skipping failing test on essex until resolved. |
419 | - # config-flags don't take effect on essex. |
420 | - if self._get_openstack_release() == self.precise_essex: |
421 | - u.log.error("Skipping failing test until resolved") |
422 | - return |
423 | - |
424 | - services = ['nova-compute', 'nova-api', 'nova-network'] |
425 | - self.d.configure('nova-compute', {'config-flags': 'verbose=False'}) |
426 | - |
427 | - time = 20 |
428 | - for s in services: |
429 | - if not u.service_restarted(self.nova_compute_sentry, s, |
430 | - '/etc/nova/nova.conf', sleep_time=time): |
431 | - self.d.configure('nova-compute', {'config-flags': 'verbose=True'}) |
432 | - msg = "service {} didn't restart after config change".format(s) |
433 | - amulet.raise_status(amulet.FAIL, msg=msg) |
434 | - time = 0 |
435 | - |
436 | - self.d.configure('nova-compute', {'config-flags': 'verbose=True'}) |
437 | - |
438 | - def test_nova_config(self): |
439 | + def test_300_nova_config(self): |
440 | """Verify the data in the nova config file.""" |
441 | # NOTE(coreycb): Currently no way to test on essex because config file |
442 | # has no section headers. |
443 | if self._get_openstack_release() == self.precise_essex: |
444 | return |
445 | |
446 | + u.log.debug('Checking nova config file data...') |
447 | unit = self.nova_compute_sentry |
448 | conf = '/etc/nova/nova.conf' |
449 | - rabbitmq_relation = self.rabbitmq_sentry.relation('amqp', |
450 | - 'nova-compute:amqp') |
451 | - glance_relation = self.glance_sentry.relation('image-service', |
452 | - 'nova-compute:image-service') |
453 | - mysql_relation = self.mysql_sentry.relation('shared-db', |
454 | - 'nova-compute:shared-db') |
455 | + rmq_nc_rel = self.rabbitmq_sentry.relation('amqp', |
456 | + 'nova-compute:amqp') |
457 | + gl_nc_rel = self.glance_sentry.relation('image-service', |
458 | + 'nova-compute:image-service') |
459 | + db_nc_rel = self.mysql_sentry.relation('shared-db', |
460 | + 'nova-compute:shared-db') |
461 | db_uri = "mysql://{}:{}@{}/{}".format('nova', |
462 | - mysql_relation['nova_password'], |
463 | - mysql_relation['db_host'], |
464 | + db_nc_rel['nova_password'], |
465 | + db_nc_rel['db_host'], |
466 | 'nova') |
467 | |
468 | expected = { |
469 | @@ -428,9 +438,9 @@ |
470 | expected[d]['sql_connection'] = db_uri |
471 | expected[d]['rabbit_userid'] = 'nova' |
472 | expected[d]['rabbit_virtual_host'] = 'openstack' |
473 | - expected[d]['rabbit_password'] = rabbitmq_relation['password'] |
474 | - expected[d]['rabbit_host'] = rabbitmq_relation['hostname'] |
475 | - expected[d]['glance_api_servers'] = glance_relation['glance-api-server'] |
476 | + expected[d]['rabbit_password'] = rmq_nc_rel['password'] |
477 | + expected[d]['rabbit_host'] = rmq_nc_rel['hostname'] |
478 | + expected[d]['glance_api_servers'] = gl_nc_rel['glance-api-server'] |
479 | else: |
480 | oslo_concurrency = { |
481 | 'oslo_concurrency': { |
482 | @@ -446,13 +456,13 @@ |
483 | 'oslo_messaging_rabbit': { |
484 | 'rabbit_userid': 'nova', |
485 | 'rabbit_virtual_host': 'openstack', |
486 | - 'rabbit_password': rabbitmq_relation['password'], |
487 | - 'rabbit_host': rabbitmq_relation['hostname'], |
488 | + 'rabbit_password': rmq_nc_rel['password'], |
489 | + 'rabbit_host': rmq_nc_rel['hostname'], |
490 | } |
491 | } |
492 | glance = { |
493 | 'glance': { |
494 | - 'api_servers': glance_relation['glance-api-server'] |
495 | + 'api_servers': gl_nc_rel['glance-api-server'] |
496 | } |
497 | } |
498 | expected.update(oslo_concurrency) |
499 | @@ -466,15 +476,17 @@ |
500 | message = "nova config error: {}".format(ret) |
501 | amulet.raise_status(amulet.FAIL, msg=message) |
502 | |
503 | - def test_image_instance_create(self): |
504 | + def test_400_image_instance_create(self): |
505 | """Create an image/instance, verify they exist, and delete them.""" |
506 | # NOTE(coreycb): Skipping failing test on essex until resolved. essex |
507 | - # nova API calls are getting "Malformed request url (HTTP |
508 | - # 400)". |
509 | + # nova API calls are getting "Malformed request url |
510 | + # (HTTP 400)". |
511 | if self._get_openstack_release() == self.precise_essex: |
512 | - u.log.error("Skipping failing test until resolved") |
513 | + u.log.error("Skipping test (due to Essex)") |
514 | return |
515 | |
516 | + u.log.debug('Checking nova instance creation...') |
517 | + |
518 | image = u.create_cirros_image(self.glance, "cirros-image") |
519 | if not image: |
520 | amulet.raise_status(amulet.FAIL, msg="Image create failed") |
521 | @@ -496,5 +508,52 @@ |
522 | message = "nova cirros instance does not exist" |
523 | amulet.raise_status(amulet.FAIL, msg=message) |
524 | |
525 | - u.delete_image(self.glance, image) |
526 | - u.delete_instance(self.nova_demo, instance) |
527 | + u.delete_resource(self.glance.images, image.id, |
528 | + msg="glance image") |
529 | + |
530 | + u.delete_resource(self.nova_demo.servers, instance.id, |
531 | + msg="nova instance") |
532 | + |
533 | + def test_900_restart_on_config_change(self): |
534 | + """Verify that the specified services are restarted when the config |
535 | + is changed.""" |
536 | + # NOTE(coreycb): Skipping failing test on essex until resolved. |
537 | + # config-flags don't take effect on essex. |
538 | + if self._get_openstack_release() == self.precise_essex: |
539 | + u.log.error("Skipping failing test until resolved") |
540 | + return |
541 | + |
542 | + sentry = self.nova_compute_sentry |
543 | + juju_service = 'nova-compute' |
544 | + |
545 | + # Expected default and alternate values |
546 | + set_default = {'verbose': 'False'} |
547 | + set_alternate = {'verbose': 'True'} |
548 | + |
549 | + # Services which are expected to restart upon config change, |
550 | + # and corresponding config files affected by the change |
551 | + conf_file = '/etc/nova/nova.conf' |
552 | + services = { |
553 | + 'nova-compute': conf_file, |
554 | + 'nova-api': conf_file, |
555 | + 'nova-network': conf_file |
556 | + } |
557 | + |
558 | + # Make config change, check for service restarts |
559 | + u.log.debug('Making config change on {}...'.format(juju_service)) |
560 | + mtime = u.get_sentry_time(sentry) |
561 | + self.d.configure(juju_service, set_alternate) |
562 | + |
563 | + sleep_time = 30 |
564 | + for s, conf_file in services.iteritems(): |
565 | + u.log.debug("Checking that service restarted: {}".format(s)) |
566 | + if not u.validate_service_config_changed(sentry, mtime, s, |
567 | + conf_file, |
568 | + sleep_time=sleep_time): |
569 | + |
570 | + self.d.configure(juju_service, set_default) |
571 | + msg = "service {} didn't restart after config change".format(s) |
572 | + amulet.raise_status(amulet.FAIL, msg=msg) |
573 | + sleep_time = 0 |
574 | + |
575 | + self.d.configure(juju_service, set_default) |
576 | |
577 | === modified file 'tests/charmhelpers/contrib/openstack/amulet/deployment.py' |
578 | --- tests/charmhelpers/contrib/openstack/amulet/deployment.py 2015-09-28 07:56:16 +0000 |
579 | +++ tests/charmhelpers/contrib/openstack/amulet/deployment.py 2015-10-16 05:42:31 +0000 |
580 | @@ -14,6 +14,7 @@ |
581 | # You should have received a copy of the GNU Lesser General Public License |
582 | # along with charm-helpers. If not, see <http://www.gnu.org/licenses/>. |
583 | |
584 | +import re |
585 | import six |
586 | from collections import OrderedDict |
587 | from charmhelpers.contrib.amulet.deployment import ( |
588 | @@ -114,6 +115,45 @@ |
589 | for service, config in six.iteritems(configs): |
590 | self.d.configure(service, config) |
591 | |
592 | + def _auto_wait_for_status(self, message=None, exclude_services=None, |
593 | + timeout=1800): |
594 | + """Wait for all units to have a specific extended status, except |
595 | + for any defined as excluded. Unless specified via message, any |
596 | + status containing any case of 'ready' will be considered a match. |
597 | + |
598 | + Examples of message usage: |
599 | + |
600 | + Wait for all unit status to CONTAIN any case of 'ready' or 'ok': |
601 | + message = re.compile('.*ready.*|.*ok.*', re.IGNORECASE) |
602 | + |
603 | + Wait for all units to reach this status (exact match): |
604 | + message = 'Unit is ready' |
605 | + |
606 | + Wait for all units to reach any one of these (exact match): |
607 | + message = re.compile('Unit is ready|OK|Ready') |
608 | + |
609 | + Wait for at least one unit to reach this status (exact match): |
610 | + message = {'ready'} |
611 | + |
612 | + See Amulet's sentry.wait_for_messages() for message usage detail. |
613 | + https://github.com/juju/amulet/blob/master/amulet/sentry.py |
614 | + |
615 | + :param message: Expected status match |
616 | + :param exclude_services: List of juju service names to ignore |
617 | + :param timeout: Maximum time in seconds to wait for status match |
618 | + :returns: None. Raises if timeout is hit. |
619 | + """ |
620 | + |
621 | + if not message: |
622 | + message = re.compile('.*ready.*', re.IGNORECASE) |
623 | + |
624 | + if not exclude_services: |
625 | + exclude_services = [] |
626 | + |
627 | + services = list(set(self.d.services.keys()) - set(exclude_services)) |
628 | + service_messages = {service: message for service in services} |
629 | + self.d.sentry.wait_for_messages(service_messages, timeout=timeout) |
630 | + |
631 | def _get_openstack_release(self): |
632 | """Get openstack release. |
633 |
charm_lint_check #12019 nova-compute-next for 1chb1n mp274659
LINT OK: passed
Build: http:// 10.245. 162.77: 8080/job/ charm_lint_ check/12019/