Merge lp:~1chb1n/charms/trusty/nova-cloud-controller/next-amulet-1510 into lp:~openstack-charmers-archive/charms/trusty/nova-cloud-controller/next
- Trusty Tahr (14.04)
- next-amulet-1510
- Merge into next
Status: | Merged |
---|---|
Merged at revision: | 201 |
Proposed branch: | lp:~1chb1n/charms/trusty/nova-cloud-controller/next-amulet-1510 |
Merge into: | lp:~openstack-charmers-archive/charms/trusty/nova-cloud-controller/next |
Diff against target: |
820 lines (+326/-175) 5 files modified
tests/020-basic-trusty-liberty (+12/-0) tests/021-basic-wily-liberty (+10/-0) tests/README (+10/-0) tests/basic_deployment.py (+254/-175) tests/charmhelpers/contrib/openstack/amulet/deployment.py (+40/-0) |
To merge this branch: | bzr merge lp:~1chb1n/charms/trusty/nova-cloud-controller/next-amulet-1510 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Liam Young (community) | Approve | ||
Review via email: mp+273740@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.
Dependent on this charm-helpers change landing:
https:/
uosci-testing-bot (uosci-testing-bot) wrote : | # |
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #10967 nova-cloud-
UNIT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #7308 nova-cloud-
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://
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #11843 nova-cloud-
LINT OK: passed
Build: http://
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #11015 nova-cloud-
UNIT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #7311 nova-cloud-
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://
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #11898 nova-cloud-
LINT OK: passed
Build: http://
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #11065 nova-cloud-
UNIT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #11899 nova-cloud-
LINT OK: passed
Build: http://
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #11066 nova-cloud-
UNIT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #7338 nova-cloud-
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://
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #7339 nova-cloud-
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://
Ryan Beisner (1chb1n) wrote : | # |
^ FYI, Amulet passes for everything but the deploy-from-source tests, which are also failing in next proper.
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #11957 nova-cloud-
LINT OK: passed
Build: http://
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #11115 nova-cloud-
UNIT OK: passed
- 209. By Ryan Beisner
-
resync tests/charmhelpers
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #11988 nova-cloud-
LINT OK: passed
Build: http://
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #11142 nova-cloud-
UNIT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #7343 nova-cloud-
AMULET OK: passed
Build: http://
- 210. By Ryan Beisner
-
stop using deprecated delete helpers
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #12018 nova-cloud-
LINT OK: passed
Build: http://
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #11169 nova-cloud-
UNIT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #7371 nova-cloud-
AMULET OK: passed
Build: http://
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #7379 nova-cloud-
AMULET OK: passed
Build: http://
Preview Diff
1 | === modified file 'tests/010-basic-precise-essex' (properties changed: +x to -x) |
2 | === modified file 'tests/019-basic-vivid-kilo' (properties changed: -x to +x) |
3 | === added file 'tests/020-basic-trusty-liberty' |
4 | --- tests/020-basic-trusty-liberty 1970-01-01 00:00:00 +0000 |
5 | +++ tests/020-basic-trusty-liberty 2015-10-16 05:41:21 +0000 |
6 | @@ -0,0 +1,12 @@ |
7 | +#!/usr/bin/python |
8 | + |
9 | +"""Amulet tests on a basic nova cloud controller deployment on |
10 | + trusty-liberty.""" |
11 | + |
12 | +from basic_deployment import NovaCCBasicDeployment |
13 | + |
14 | +if __name__ == '__main__': |
15 | + deployment = NovaCCBasicDeployment(series='trusty', |
16 | + openstack='cloud:trusty-liberty', |
17 | + source='cloud:trusty-updates/liberty') |
18 | + deployment.run_tests() |
19 | |
20 | === added file 'tests/021-basic-wily-liberty' |
21 | --- tests/021-basic-wily-liberty 1970-01-01 00:00:00 +0000 |
22 | +++ tests/021-basic-wily-liberty 2015-10-16 05:41:21 +0000 |
23 | @@ -0,0 +1,10 @@ |
24 | +#!/usr/bin/python |
25 | + |
26 | +"""Amulet tests on a basic nova cloud controller deployment on |
27 | + wily-liberty.""" |
28 | + |
29 | +from basic_deployment import NovaCCBasicDeployment |
30 | + |
31 | +if __name__ == '__main__': |
32 | + deployment = NovaCCBasicDeployment(series='wily') |
33 | + deployment.run_tests() |
34 | |
35 | === modified file 'tests/README' |
36 | --- tests/README 2014-09-29 21:03:48 +0000 |
37 | +++ tests/README 2015-10-16 05:41:21 +0000 |
38 | @@ -1,6 +1,16 @@ |
39 | This directory provides Amulet tests that focus on verification of Nova Cloud |
40 | Controller deployments. |
41 | |
42 | +test_* methods are called in lexical sort order, although each individual test |
43 | +should be idempotent, and expected to pass regardless of run order. |
44 | + |
45 | +Test name convention to ensure desired test order: |
46 | + 1xx service and endpoint checks |
47 | + 2xx relation checks |
48 | + 3xx config checks |
49 | + 4xx functional checks |
50 | + 9xx restarts and other final checks |
51 | + |
52 | In order to run tests, you'll need charm-tools installed (in addition to |
53 | juju, of course): |
54 | sudo add-apt-repository ppa:juju/stable |
55 | |
56 | === modified file 'tests/basic_deployment.py' |
57 | --- tests/basic_deployment.py 2015-10-05 06:50:03 +0000 |
58 | +++ tests/basic_deployment.py 2015-10-16 05:41:21 +0000 |
59 | @@ -1,5 +1,3 @@ |
60 | -#!/usr/bin/python |
61 | - |
62 | import amulet |
63 | import os |
64 | import yaml |
65 | @@ -10,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 | @@ -24,12 +22,18 @@ |
77 | def __init__(self, series=None, openstack=None, source=None, git=False, |
78 | stable=False): |
79 | """Deploy the entire test environment.""" |
80 | - super(NovaCCBasicDeployment, self).__init__(series, openstack, source, stable) |
81 | + super(NovaCCBasicDeployment, self).__init__(series, openstack, |
82 | + source, stable) |
83 | self.git = git |
84 | self._add_services() |
85 | self._add_relations() |
86 | self._configure_services() |
87 | self._deploy() |
88 | + |
89 | + u.log.info('Waiting on extended status checks...') |
90 | + exclude_services = ['mysql'] |
91 | + self._auto_wait_for_status(exclude_services=exclude_services) |
92 | + |
93 | self._initialize_tests() |
94 | |
95 | def _add_services(self): |
96 | @@ -40,27 +44,31 @@ |
97 | compatible with the local charm (e.g. stable or next). |
98 | """ |
99 | this_service = {'name': 'nova-cloud-controller'} |
100 | - other_services = [{'name': 'mysql'}, {'name': 'rabbitmq-server'}, |
101 | + other_services = [{'name': 'mysql'}, |
102 | + {'name': 'rabbitmq-server'}, |
103 | {'name': 'nova-compute', 'units': 2}, |
104 | - {'name': 'keystone'}, {'name': 'glance'}] |
105 | + {'name': 'keystone'}, |
106 | + {'name': 'glance'}] |
107 | super(NovaCCBasicDeployment, self)._add_services(this_service, |
108 | other_services) |
109 | |
110 | def _add_relations(self): |
111 | """Add all of the relations for the services.""" |
112 | relations = { |
113 | - 'nova-cloud-controller:shared-db': 'mysql:shared-db', |
114 | - 'nova-cloud-controller:identity-service': 'keystone:identity-service', |
115 | - 'nova-cloud-controller:amqp': 'rabbitmq-server:amqp', |
116 | - 'nova-cloud-controller:cloud-compute': 'nova-compute:cloud-compute', |
117 | - 'nova-cloud-controller:image-service': 'glance:image-service', |
118 | - 'nova-compute:image-service': 'glance:image-service', |
119 | - 'nova-compute:shared-db': 'mysql:shared-db', |
120 | - 'nova-compute:amqp': 'rabbitmq-server:amqp', |
121 | - 'keystone:shared-db': 'mysql:shared-db', |
122 | - 'glance:identity-service': 'keystone:identity-service', |
123 | - 'glance:shared-db': 'mysql:shared-db', |
124 | - 'glance:amqp': 'rabbitmq-server:amqp' |
125 | + 'nova-cloud-controller:shared-db': 'mysql:shared-db', |
126 | + 'nova-cloud-controller:identity-service': 'keystone:' |
127 | + 'identity-service', |
128 | + 'nova-cloud-controller:amqp': 'rabbitmq-server:amqp', |
129 | + 'nova-cloud-controller:cloud-compute': 'nova-compute:' |
130 | + 'cloud-compute', |
131 | + 'nova-cloud-controller:image-service': 'glance:image-service', |
132 | + 'nova-compute:image-service': 'glance:image-service', |
133 | + 'nova-compute:shared-db': 'mysql:shared-db', |
134 | + 'nova-compute:amqp': 'rabbitmq-server:amqp', |
135 | + 'keystone:shared-db': 'mysql:shared-db', |
136 | + 'glance:identity-service': 'keystone:identity-service', |
137 | + 'glance:shared-db': 'mysql:shared-db', |
138 | + 'glance:amqp': 'rabbitmq-server:amqp' |
139 | } |
140 | super(NovaCCBasicDeployment, self)._add_relations(relations) |
141 | |
142 | @@ -98,16 +106,24 @@ |
143 | 'http_proxy': amulet_http_proxy, |
144 | 'https_proxy': amulet_http_proxy, |
145 | } |
146 | - nova_cc_config['openstack-origin-git'] = yaml.dump(openstack_origin_git) |
147 | - nova_config['openstack-origin-git'] = yaml.dump(openstack_origin_git) |
148 | + |
149 | + nova_cc_config['openstack-origin-git'] = \ |
150 | + yaml.dump(openstack_origin_git) |
151 | + |
152 | + nova_config['openstack-origin-git'] = \ |
153 | + yaml.dump(openstack_origin_git) |
154 | |
155 | # Add some rate-limiting options to the charm. These will noop before |
156 | # icehouse. |
157 | - nova_cc_config['api-rate-limit-rules'] = "( POST, '*', .*, 9999, MINUTE );" |
158 | + nova_cc_config['api-rate-limit-rules'] = \ |
159 | + "( POST, '*', .*, 9999, MINUTE );" |
160 | + |
161 | keystone_config = {'admin-password': 'openstack', |
162 | 'admin-token': 'ubuntutesting'} |
163 | + |
164 | configs = {'nova-cloud-controller': nova_cc_config, |
165 | 'keystone': keystone_config, 'nova-compute': nova_config} |
166 | + |
167 | super(NovaCCBasicDeployment, self)._configure_services(configs) |
168 | |
169 | def _initialize_tests(self): |
170 | @@ -120,6 +136,11 @@ |
171 | self.nova_compute_sentry = self.d.sentry.unit['nova-compute/0'] |
172 | self.glance_sentry = self.d.sentry.unit['glance/0'] |
173 | |
174 | + u.log.debug('openstack release val: {}'.format( |
175 | + self._get_openstack_release())) |
176 | + u.log.debug('openstack release str: {}'.format( |
177 | + self._get_openstack_release_string())) |
178 | + |
179 | # Authenticate admin with keystone |
180 | self.keystone = u.authenticate_keystone_admin(self.keystone_sentry, |
181 | user='admin', |
182 | @@ -155,32 +176,33 @@ |
183 | password='password', |
184 | tenant=self.demo_tenant) |
185 | |
186 | - def test_services(self): |
187 | + def test_100_services(self): |
188 | """Verify the expected services are running on the corresponding |
189 | service units.""" |
190 | - commands = { |
191 | - self.mysql_sentry: ['status mysql'], |
192 | - self.rabbitmq_sentry: ['sudo service rabbitmq-server status'], |
193 | - self.nova_cc_sentry: ['status nova-api-ec2', |
194 | - 'status nova-api-os-compute', |
195 | - 'status nova-objectstore', |
196 | - 'status nova-cert', |
197 | - 'status nova-scheduler'], |
198 | - self.nova_compute_sentry: ['status nova-compute', |
199 | - 'status nova-network', |
200 | - 'status nova-api'], |
201 | - self.keystone_sentry: ['status keystone'], |
202 | - self.glance_sentry: ['status glance-registry', 'status glance-api'] |
203 | + u.log.debug('Checking system services on units...') |
204 | + services = { |
205 | + self.mysql_sentry: ['mysql'], |
206 | + self.rabbitmq_sentry: ['rabbitmq-server'], |
207 | + self.nova_cc_sentry: ['nova-api-ec2', |
208 | + 'nova-api-os-compute', |
209 | + 'nova-conductor', |
210 | + 'nova-objectstore', |
211 | + 'nova-cert', |
212 | + 'nova-scheduler'], |
213 | + self.nova_compute_sentry: ['nova-compute', |
214 | + 'nova-network', |
215 | + 'nova-api'], |
216 | + self.keystone_sentry: ['keystone'], |
217 | + self.glance_sentry: ['glance-registry', 'glance-api'] |
218 | } |
219 | - if self._get_openstack_release() >= self.precise_grizzly: |
220 | - commands[self.nova_cc_sentry] = ['status nova-conductor'] |
221 | |
222 | - ret = u.validate_services(commands) |
223 | + ret = u.validate_services_by_name(services) |
224 | if ret: |
225 | amulet.raise_status(amulet.FAIL, msg=ret) |
226 | |
227 | - def test_service_catalog(self): |
228 | + def test_102_service_catalog(self): |
229 | """Verify that the service catalog endpoint data is valid.""" |
230 | + u.log.debug('Checking keystone service catalog...') |
231 | endpoint_vol = {'adminURL': u.valid_url, |
232 | 'region': 'RegionOne', |
233 | 'publicURL': u.valid_url, |
234 | @@ -189,30 +211,38 @@ |
235 | 'region': 'RegionOne', |
236 | 'publicURL': u.valid_url, |
237 | 'internalURL': u.valid_url} |
238 | + |
239 | if self._get_openstack_release() >= self.precise_folsom: |
240 | endpoint_vol['id'] = u.not_null |
241 | endpoint_id['id'] = u.not_null |
242 | + |
243 | if self._get_openstack_release() >= self.trusty_kilo: |
244 | expected = {'compute': [endpoint_vol], 'identity': [endpoint_id]} |
245 | else: |
246 | expected = {'s3': [endpoint_vol], 'compute': [endpoint_vol], |
247 | 'ec2': [endpoint_vol], 'identity': [endpoint_id]} |
248 | + |
249 | actual = self.keystone_demo.service_catalog.get_endpoints() |
250 | |
251 | ret = u.validate_svc_catalog_endpoint_data(expected, actual) |
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 | + |
269 | + expected = { |
270 | + 'id': u.not_null, |
271 | + 'region': 'RegionOne', |
272 | + 'adminurl': u.valid_url, |
273 | + 'internalurl': u.valid_url, |
274 | + 'publicurl': u.valid_url, |
275 | + 'service_id': u.not_null |
276 | + } |
277 | |
278 | ret = u.validate_endpoint_data(endpoints, admin_port, internal_port, |
279 | public_port, expected) |
280 | @@ -220,19 +250,23 @@ |
281 | message = 'osapi endpoint: {}'.format(ret) |
282 | amulet.raise_status(amulet.FAIL, msg=message) |
283 | |
284 | - def test_ec2_api_endpoint(self): |
285 | + def test_106_ec2_api_endpoint(self): |
286 | """Verify the EC2 api endpoint data.""" |
287 | if self._get_openstack_release() >= self.trusty_kilo: |
288 | return |
289 | |
290 | + u.log.debug('Checking ec2 endpoint data...') |
291 | endpoints = self.keystone.endpoints.list() |
292 | admin_port = internal_port = public_port = '8773' |
293 | - expected = {'id': u.not_null, |
294 | - 'region': 'RegionOne', |
295 | - 'adminurl': u.valid_url, |
296 | - 'internalurl': u.valid_url, |
297 | - 'publicurl': u.valid_url, |
298 | - 'service_id': u.not_null} |
299 | + |
300 | + expected = { |
301 | + 'id': u.not_null, |
302 | + 'region': 'RegionOne', |
303 | + 'adminurl': u.valid_url, |
304 | + 'internalurl': u.valid_url, |
305 | + 'publicurl': u.valid_url, |
306 | + 'service_id': u.not_null |
307 | + } |
308 | |
309 | ret = u.validate_endpoint_data(endpoints, admin_port, internal_port, |
310 | public_port, expected) |
311 | @@ -240,19 +274,22 @@ |
312 | message = 'EC2 endpoint: {}'.format(ret) |
313 | amulet.raise_status(amulet.FAIL, msg=message) |
314 | |
315 | - def test_s3_api_endpoint(self): |
316 | + def test_108_s3_api_endpoint(self): |
317 | """Verify the S3 api endpoint data.""" |
318 | if self._get_openstack_release() >= self.trusty_kilo: |
319 | return |
320 | |
321 | + u.log.debug('Checking s3 endpoint data...') |
322 | endpoints = self.keystone.endpoints.list() |
323 | admin_port = internal_port = public_port = '3333' |
324 | - expected = {'id': u.not_null, |
325 | - 'region': 'RegionOne', |
326 | - 'adminurl': u.valid_url, |
327 | - 'internalurl': u.valid_url, |
328 | - 'publicurl': u.valid_url, |
329 | - 'service_id': u.not_null} |
330 | + expected = { |
331 | + 'id': u.not_null, |
332 | + 'region': 'RegionOne', |
333 | + 'adminurl': u.valid_url, |
334 | + 'internalurl': u.valid_url, |
335 | + 'publicurl': u.valid_url, |
336 | + 'service_id': u.not_null |
337 | + } |
338 | |
339 | ret = u.validate_endpoint_data(endpoints, admin_port, internal_port, |
340 | public_port, expected) |
341 | @@ -260,10 +297,12 @@ |
342 | message = 'S3 endpoint: {}'.format(ret) |
343 | amulet.raise_status(amulet.FAIL, msg=message) |
344 | |
345 | - def test_nova_cc_shared_db_relation(self): |
346 | + def test_200_nova_cc_shared_db_relation(self): |
347 | """Verify the nova-cc to mysql shared-db relation data""" |
348 | + u.log.debug('Checking n-c-c:mysql db relation data...') |
349 | unit = self.nova_cc_sentry |
350 | relation = ['shared-db', 'mysql:shared-db'] |
351 | + |
352 | expected = { |
353 | 'private-address': u.valid_ip, |
354 | 'nova_database': 'nova', |
355 | @@ -276,8 +315,9 @@ |
356 | message = u.relation_error('nova-cc shared-db', ret) |
357 | amulet.raise_status(amulet.FAIL, msg=message) |
358 | |
359 | - def test_mysql_shared_db_relation(self): |
360 | + def test_202_mysql_shared_db_relation(self): |
361 | """Verify the mysql to nova-cc shared-db relation data""" |
362 | + u.log.debug('Checking mysql:n-c-c db relation data...') |
363 | unit = self.mysql_sentry |
364 | relation = ['shared-db', 'nova-cloud-controller:shared-db'] |
365 | expected = { |
366 | @@ -291,8 +331,9 @@ |
367 | message = u.relation_error('mysql shared-db', ret) |
368 | amulet.raise_status(amulet.FAIL, msg=message) |
369 | |
370 | - def test_nova_cc_identity_service_relation(self): |
371 | + def test_204_nova_cc_identity_service_relation(self): |
372 | """Verify the nova-cc to keystone identity-service relation data""" |
373 | + u.log.debug('Checking n-c-c:keystone identity relation data...') |
374 | unit = self.nova_cc_sentry |
375 | relation = ['identity-service', 'keystone:identity-service'] |
376 | expected = { |
377 | @@ -320,8 +361,9 @@ |
378 | message = u.relation_error('nova-cc identity-service', ret) |
379 | amulet.raise_status(amulet.FAIL, msg=message) |
380 | |
381 | - def test_keystone_identity_service_relation(self): |
382 | + def test_206_keystone_identity_service_relation(self): |
383 | """Verify the keystone to nova-cc identity-service relation data""" |
384 | + u.log.debug('Checking keystone:n-c-c identity relation data...') |
385 | unit = self.keystone_sentry |
386 | relation = ['identity-service', |
387 | 'nova-cloud-controller:identity-service'] |
388 | @@ -347,8 +389,9 @@ |
389 | message = u.relation_error('keystone identity-service', ret) |
390 | amulet.raise_status(amulet.FAIL, msg=message) |
391 | |
392 | - def test_nova_cc_amqp_relation(self): |
393 | + def test_208_nova_cc_amqp_relation(self): |
394 | """Verify the nova-cc to rabbitmq-server amqp relation data""" |
395 | + u.log.debug('Checking n-c-c:rmq amqp relation data...') |
396 | unit = self.nova_cc_sentry |
397 | relation = ['amqp', 'rabbitmq-server:amqp'] |
398 | expected = { |
399 | @@ -362,8 +405,9 @@ |
400 | message = u.relation_error('nova-cc amqp', ret) |
401 | amulet.raise_status(amulet.FAIL, msg=message) |
402 | |
403 | - def test_rabbitmq_amqp_relation(self): |
404 | + def test_210_rabbitmq_amqp_relation(self): |
405 | """Verify the rabbitmq-server to nova-cc amqp relation data""" |
406 | + u.log.debug('Checking rmq:n-c-c amqp relation data...') |
407 | unit = self.rabbitmq_sentry |
408 | relation = ['amqp', 'nova-cloud-controller:amqp'] |
409 | expected = { |
410 | @@ -377,8 +421,11 @@ |
411 | message = u.relation_error('rabbitmq amqp', ret) |
412 | amulet.raise_status(amulet.FAIL, msg=message) |
413 | |
414 | - def test_nova_cc_cloud_compute_relation(self): |
415 | + def test_212_nova_cc_cloud_compute_relation(self): |
416 | """Verify the nova-cc to nova-compute cloud-compute relation data""" |
417 | + u.log.debug('Checking n-c-c:nova-compute ' |
418 | + 'cloud-compute relation data...') |
419 | + |
420 | unit = self.nova_cc_sentry |
421 | relation = ['cloud-compute', 'nova-compute:cloud-compute'] |
422 | expected = { |
423 | @@ -396,8 +443,11 @@ |
424 | message = u.relation_error('nova-cc cloud-compute', ret) |
425 | amulet.raise_status(amulet.FAIL, msg=message) |
426 | |
427 | - def test_nova_cloud_compute_relation(self): |
428 | + def test_214_nova_cloud_compute_relation(self): |
429 | """Verify the nova-compute to nova-cc cloud-compute relation data""" |
430 | + u.log.debug('Checking nova-compute:n-c-c ' |
431 | + 'cloud-compute relation data...') |
432 | + |
433 | unit = self.nova_compute_sentry |
434 | relation = ['cloud-compute', 'nova-cloud-controller:cloud-compute'] |
435 | expected = { |
436 | @@ -409,8 +459,9 @@ |
437 | message = u.relation_error('nova-compute cloud-compute', ret) |
438 | amulet.raise_status(amulet.FAIL, msg=message) |
439 | |
440 | - def test_nova_cc_image_service_relation(self): |
441 | + def test_216_nova_cc_image_service_relation(self): |
442 | """Verify the nova-cc to glance image-service relation data""" |
443 | + u.log.debug('Checking n-c-c:glance image-service relation data...') |
444 | unit = self.nova_cc_sentry |
445 | relation = ['image-service', 'glance:image-service'] |
446 | expected = { |
447 | @@ -422,8 +473,9 @@ |
448 | message = u.relation_error('nova-cc image-service', ret) |
449 | amulet.raise_status(amulet.FAIL, msg=message) |
450 | |
451 | - def test_glance_image_service_relation(self): |
452 | + def test_218_glance_image_service_relation(self): |
453 | """Verify the glance to nova-cc image-service relation data""" |
454 | + u.log.debug('Checking glance:n-c-c image-service relation data...') |
455 | unit = self.glance_sentry |
456 | relation = ['image-service', 'nova-cloud-controller:image-service'] |
457 | expected = { |
458 | @@ -436,72 +488,44 @@ |
459 | message = u.relation_error('glance image-service', ret) |
460 | amulet.raise_status(amulet.FAIL, msg=message) |
461 | |
462 | - def test_z_restart_on_config_change(self): |
463 | - """Verify that the specified services are restarted when the config |
464 | - is changed. |
465 | - |
466 | - Note(coreycb): The method name with the _z_ is a little odd |
467 | - but it forces the test to run last. It just makes things |
468 | - easier because restarting services requires re-authorization. |
469 | - """ |
470 | - # NOTE(coreycb): Skipping failing test on essex until resolved. |
471 | - # config-flags don't take effect on essex. |
472 | - if self._get_openstack_release() == self.precise_essex: |
473 | - u.log.error("Skipping failing test until resolved") |
474 | - return |
475 | - |
476 | - flags_set = 'quota_cores=20,quota_instances=40,quota_ram=102400' |
477 | - flags_reset = 'quota_cores=10,quota_instances=20,quota_ram=51200' |
478 | - |
479 | - services = ['nova-api-ec2', 'nova-api-os-compute', 'nova-objectstore', |
480 | - 'nova-cert', 'nova-scheduler', 'nova-conductor'] |
481 | - self.d.configure('nova-cloud-controller', {'config-flags': flags_set}) |
482 | - pgrep_full = True |
483 | - |
484 | - time = 20 |
485 | - conf = '/etc/nova/nova.conf' |
486 | - for s in services: |
487 | - if not u.service_restarted(self.nova_cc_sentry, s, conf, |
488 | - pgrep_full=True, sleep_time=time): |
489 | - self.d.configure('nova-cloud-controller', |
490 | - {'config-flags': flags_reset}) |
491 | - msg = "service {} didn't restart after config change".format(s) |
492 | - amulet.raise_status(amulet.FAIL, msg=msg) |
493 | - time = 0 |
494 | - |
495 | - self.d.configure('nova-cloud-controller', {'config-flags': flags_reset}) |
496 | - |
497 | - def test_nova_default_config(self): |
498 | + def test_300_nova_default_config(self): |
499 | """Verify the data in the nova config file's default section.""" |
500 | # NOTE(coreycb): Currently no way to test on essex because config file |
501 | # has no section headers. |
502 | if self._get_openstack_release() == self.precise_essex: |
503 | return |
504 | |
505 | + u.log.debug('Checking nova config file data...') |
506 | unit = self.nova_cc_sentry |
507 | conf = '/etc/nova/nova.conf' |
508 | - rabbitmq_relation = self.rabbitmq_sentry.relation('amqp', |
509 | - 'nova-cloud-controller:amqp') |
510 | - glance_relation = self.glance_sentry.relation('image-service', |
511 | - 'nova-cloud-controller:image-service') |
512 | - keystone_ep = self.keystone_demo.service_catalog.url_for(\ |
513 | - service_type='identity', |
514 | - endpoint_type='publicURL') |
515 | - keystone_ec2 = "{}/ec2tokens".format(keystone_ep) |
516 | - |
517 | - keystone_relation = self.keystone_sentry.relation('identity-service', |
518 | - 'nova-cloud-controller:identity-service') |
519 | - keystone_uri = "http://{}:{}/".format(keystone_relation['service_host'], |
520 | - keystone_relation['service_port']) |
521 | - identity_uri = "{}://{}:{}/".format(keystone_relation['auth_protocol'], |
522 | - keystone_relation['service_host'], |
523 | - keystone_relation['auth_port']) |
524 | - |
525 | - mysql_relation = self.mysql_sentry.relation('shared-db', |
526 | - 'nova-cloud-controller:shared-db') |
527 | + |
528 | + rmq_ncc_rel = self.rabbitmq_sentry.relation( |
529 | + 'amqp', 'nova-cloud-controller:amqp') |
530 | + |
531 | + gl_ncc_rel = self.glance_sentry.relation( |
532 | + 'image-service', 'nova-cloud-controller:image-service') |
533 | + |
534 | + ks_ep = self.keystone_demo.service_catalog.url_for( |
535 | + service_type='identity', endpoint_type='publicURL') |
536 | + |
537 | + ks_ec2 = "{}/ec2tokens".format(ks_ep) |
538 | + |
539 | + ks_ncc_rel = self.keystone_sentry.relation( |
540 | + 'identity-service', 'nova-cloud-controller:identity-service') |
541 | + |
542 | + ks_uri = "http://{}:{}/".format(ks_ncc_rel['service_host'], |
543 | + ks_ncc_rel['service_port']) |
544 | + |
545 | + id_uri = "{}://{}:{}/".format(ks_ncc_rel['auth_protocol'], |
546 | + ks_ncc_rel['service_host'], |
547 | + ks_ncc_rel['auth_port']) |
548 | + |
549 | + db_ncc_rel = self.mysql_sentry.relation( |
550 | + 'shared-db', 'nova-cloud-controller:shared-db') |
551 | + |
552 | db_uri = "mysql://{}:{}@{}/{}".format('nova', |
553 | - mysql_relation['nova_password'], |
554 | - mysql_relation['db_host'], |
555 | + db_ncc_rel['nova_password'], |
556 | + db_ncc_rel['db_host'], |
557 | 'nova') |
558 | |
559 | expected = { |
560 | @@ -523,7 +547,7 @@ |
561 | 'enabled_apis': 'ec2,osapi_compute,metadata', |
562 | 'auth_strategy': 'keystone', |
563 | 'compute_driver': 'libvirt.LibvirtDriver', |
564 | - 'keystone_ec2_url': keystone_ec2, |
565 | + 'keystone_ec2_url': ks_ec2, |
566 | 'network_manager': 'nova.network.manager.FlatDHCPManager', |
567 | 's3_listen_port': '3323', |
568 | 'osapi_compute_listen_port': '8764', |
569 | @@ -542,13 +566,13 @@ |
570 | } |
571 | keystone_authtoken = { |
572 | 'keystone_authtoken': { |
573 | - 'auth_uri': keystone_uri, |
574 | - 'auth_host': keystone_relation['service_host'], |
575 | - 'auth_port': keystone_relation['auth_port'], |
576 | - 'auth_protocol': keystone_relation['auth_protocol'], |
577 | - 'admin_tenant_name': keystone_relation['service_tenant'], |
578 | - 'admin_user': keystone_relation['service_username'], |
579 | - 'admin_password': keystone_relation['service_password'], |
580 | + 'auth_uri': ks_uri, |
581 | + 'auth_host': ks_ncc_rel['service_host'], |
582 | + 'auth_port': ks_ncc_rel['auth_port'], |
583 | + 'auth_protocol': ks_ncc_rel['auth_protocol'], |
584 | + 'admin_tenant_name': ks_ncc_rel['service_tenant'], |
585 | + 'admin_user': ks_ncc_rel['service_username'], |
586 | + 'admin_password': ks_ncc_rel['service_password'], |
587 | } |
588 | } |
589 | expected.update(database) |
590 | @@ -558,9 +582,9 @@ |
591 | expected[d]['compute_driver'] = 'libvirt.LibvirtDriver' |
592 | expected[d]['rabbit_userid'] = 'nova' |
593 | expected[d]['rabbit_virtual_host'] = 'openstack' |
594 | - expected[d]['rabbit_password'] = rabbitmq_relation['password'] |
595 | - expected[d]['rabbit_host'] = rabbitmq_relation['hostname'] |
596 | - expected[d]['glance_api_servers'] = glance_relation['glance-api-server'] |
597 | + expected[d]['rabbit_password'] = rmq_ncc_rel['password'] |
598 | + expected[d]['rabbit_host'] = rmq_ncc_rel['hostname'] |
599 | + expected[d]['glance_api_servers'] = gl_ncc_rel['glance-api-server'] |
600 | |
601 | else: |
602 | database = { |
603 | @@ -571,16 +595,16 @@ |
604 | } |
605 | glance = { |
606 | 'glance': { |
607 | - 'api_servers': glance_relation['glance-api-server'], |
608 | + 'api_servers': gl_ncc_rel['glance-api-server'], |
609 | } |
610 | } |
611 | keystone_authtoken = { |
612 | 'keystone_authtoken': { |
613 | - 'identity_uri': identity_uri, |
614 | - 'auth_uri': keystone_uri, |
615 | - 'admin_tenant_name': keystone_relation['service_tenant'], |
616 | - 'admin_user': keystone_relation['service_username'], |
617 | - 'admin_password': keystone_relation['service_password'], |
618 | + 'identity_uri': id_uri, |
619 | + 'auth_uri': ks_uri, |
620 | + 'admin_tenant_name': ks_ncc_rel['service_tenant'], |
621 | + 'admin_user': ks_ncc_rel['service_username'], |
622 | + 'admin_password': ks_ncc_rel['service_password'], |
623 | 'signing_dir': '/var/cache/nova', |
624 | } |
625 | } |
626 | @@ -598,8 +622,8 @@ |
627 | 'oslo_messaging_rabbit': { |
628 | 'rabbit_userid': 'nova', |
629 | 'rabbit_virtual_host': 'openstack', |
630 | - 'rabbit_password': rabbitmq_relation['password'], |
631 | - 'rabbit_host': rabbitmq_relation['hostname'], |
632 | + 'rabbit_password': rmq_ncc_rel['password'], |
633 | + 'rabbit_host': rmq_ncc_rel['hostname'], |
634 | } |
635 | } |
636 | oslo_concurrency = { |
637 | @@ -621,15 +645,41 @@ |
638 | message = "nova config error: {}".format(ret) |
639 | amulet.raise_status(amulet.FAIL, msg=message) |
640 | |
641 | - def test_image_instance_create(self): |
642 | + def test_302_api_rate_limiting_is_enabled_for_icehouse_or_more(self): |
643 | + """ |
644 | + The API rate limiting is enabled for icehouse or more. Otherwise the |
645 | + api-paste.ini file is left untouched. |
646 | + """ |
647 | + u.log.debug('Checking api-paste config file data...') |
648 | + |
649 | + unit = self.nova_cc_sentry |
650 | + conf = '/etc/nova/api-paste.ini' |
651 | + section = "filter:ratelimit" |
652 | + factory = ("nova.api.openstack.compute.limits:RateLimitingMiddleware" |
653 | + ".factory") |
654 | + |
655 | + if self._get_openstack_release() >= self.precise_icehouse: |
656 | + expected = {"paste.filter_factory": factory, |
657 | + "limits": "( POST, '*', .*, 9999, MINUTE );"} |
658 | + else: |
659 | + expected = {"paste.filter_factory": factory} |
660 | + |
661 | + ret = u.validate_config_data(unit, conf, section, expected) |
662 | + if ret: |
663 | + message = "api paste config error: {}".format(ret) |
664 | + amulet.raise_status(amulet.FAIL, msg=message) |
665 | + |
666 | + def test_400_image_instance_create(self): |
667 | """Create an image/instance, verify they exist, and delete them.""" |
668 | # NOTE(coreycb): Skipping failing test on essex until resolved. essex |
669 | - # nova API calls are getting "Malformed request url (HTTP |
670 | - # 400)". |
671 | + # nova API calls are getting "Malformed request url |
672 | + # (HTTP 400)". |
673 | if self._get_openstack_release() == self.precise_essex: |
674 | - u.log.error("Skipping failing test until resolved") |
675 | + u.log.error("Skipping test (due to Essex)") |
676 | return |
677 | |
678 | + u.log.debug('Checking nova instance creation...') |
679 | + |
680 | image = u.create_cirros_image(self.glance, "cirros-image") |
681 | if not image: |
682 | amulet.raise_status(amulet.FAIL, msg="Image create failed") |
683 | @@ -651,27 +701,56 @@ |
684 | message = "nova cirros instance does not exist" |
685 | amulet.raise_status(amulet.FAIL, msg=message) |
686 | |
687 | - u.delete_image(self.glance, image) |
688 | - u.delete_instance(self.nova_demo, instance) |
689 | - |
690 | - def test_api_rate_limiting_is_enabled_for_icehouse_or_more(self): |
691 | - """ |
692 | - The API rate limiting is enabled for icehouse or more. Otherwise the |
693 | - api-paste.ini file is left untouched. |
694 | - """ |
695 | - unit = self.nova_cc_sentry |
696 | - conf = '/etc/nova/api-paste.ini' |
697 | - section = "filter:ratelimit" |
698 | - factory = ("nova.api.openstack.compute.limits:RateLimitingMiddleware" |
699 | - ".factory") |
700 | - |
701 | - if self._get_openstack_release() >= self.precise_icehouse: |
702 | - expected = {"paste.filter_factory": factory, |
703 | - "limits": "( POST, '*', .*, 9999, MINUTE );"} |
704 | - else: |
705 | - expected = {"paste.filter_factory": factory} |
706 | - |
707 | - ret = u.validate_config_data(unit, conf, section, expected) |
708 | - if ret: |
709 | - message = "api paste config error: {}".format(ret) |
710 | - amulet.raise_status(amulet.FAIL, msg=message) |
711 | + u.delete_resource(self.glance.images, image.id, |
712 | + msg="glance image") |
713 | + |
714 | + u.delete_resource(self.nova_demo.servers, instance.id, |
715 | + msg="nova instance") |
716 | + |
717 | + def test_900_restart_on_config_change(self): |
718 | + """Verify that the specified services are restarted when the config |
719 | + is changed.""" |
720 | + if self._get_openstack_release() == self.precise_essex: |
721 | + u.log.error("Skipping test (due to Essex)") |
722 | + return |
723 | + |
724 | + u.log.info('Checking that conf files and system services respond ' |
725 | + 'to a charm config change...') |
726 | + |
727 | + sentry = self.nova_cc_sentry |
728 | + juju_service = 'nova-cloud-controller' |
729 | + |
730 | + # Process names, corresponding conf files |
731 | + conf_file = '/etc/nova/nova.conf' |
732 | + services = { |
733 | + 'nova-api-ec2': conf_file, |
734 | + 'nova-api-os-compute': conf_file, |
735 | + 'nova-objectstore': conf_file, |
736 | + 'nova-cert': conf_file, |
737 | + 'nova-scheduler': conf_file, |
738 | + 'nova-conductor': conf_file |
739 | + } |
740 | + |
741 | + # Expected default and alternate values |
742 | + flags_default = 'quota_cores=20,quota_instances=40,quota_ram=102400' |
743 | + flags_alt = 'quota_cores=10,quota_instances=20,quota_ram=51200' |
744 | + set_default = {'config-flags': flags_default} |
745 | + set_alternate = {'config-flags': flags_alt} |
746 | + |
747 | + # Make config change, check for service restarts |
748 | + u.log.debug('Making config change on {}...'.format(juju_service)) |
749 | + mtime = u.get_sentry_time(sentry) |
750 | + self.d.configure(juju_service, set_alternate) |
751 | + |
752 | + sleep_time = 60 |
753 | + for s, conf_file in services.iteritems(): |
754 | + u.log.debug("Checking that service restarted: {}".format(s)) |
755 | + if not u.validate_service_config_changed(sentry, mtime, s, |
756 | + conf_file, |
757 | + sleep_time=sleep_time): |
758 | + self.d.configure(juju_service, set_default) |
759 | + msg = "service {} didn't restart after config change".format(s) |
760 | + amulet.raise_status(amulet.FAIL, msg=msg) |
761 | + sleep_time = 0 |
762 | + |
763 | + self.d.configure(juju_service, set_default) |
764 | |
765 | === modified file 'tests/charmhelpers/contrib/openstack/amulet/deployment.py' |
766 | --- tests/charmhelpers/contrib/openstack/amulet/deployment.py 2015-09-25 14:35:19 +0000 |
767 | +++ tests/charmhelpers/contrib/openstack/amulet/deployment.py 2015-10-16 05:41:21 +0000 |
768 | @@ -14,6 +14,7 @@ |
769 | # You should have received a copy of the GNU Lesser General Public License |
770 | # along with charm-helpers. If not, see <http://www.gnu.org/licenses/>. |
771 | |
772 | +import re |
773 | import six |
774 | from collections import OrderedDict |
775 | from charmhelpers.contrib.amulet.deployment import ( |
776 | @@ -114,6 +115,45 @@ |
777 | for service, config in six.iteritems(configs): |
778 | self.d.configure(service, config) |
779 | |
780 | + def _auto_wait_for_status(self, message=None, exclude_services=None, |
781 | + timeout=1800): |
782 | + """Wait for all units to have a specific extended status, except |
783 | + for any defined as excluded. Unless specified via message, any |
784 | + status containing any case of 'ready' will be considered a match. |
785 | + |
786 | + Examples of message usage: |
787 | + |
788 | + Wait for all unit status to CONTAIN any case of 'ready' or 'ok': |
789 | + message = re.compile('.*ready.*|.*ok.*', re.IGNORECASE) |
790 | + |
791 | + Wait for all units to reach this status (exact match): |
792 | + message = 'Unit is ready' |
793 | + |
794 | + Wait for all units to reach any one of these (exact match): |
795 | + message = re.compile('Unit is ready|OK|Ready') |
796 | + |
797 | + Wait for at least one unit to reach this status (exact match): |
798 | + message = {'ready'} |
799 | + |
800 | + See Amulet's sentry.wait_for_messages() for message usage detail. |
801 | + https://github.com/juju/amulet/blob/master/amulet/sentry.py |
802 | + |
803 | + :param message: Expected status match |
804 | + :param exclude_services: List of juju service names to ignore |
805 | + :param timeout: Maximum time in seconds to wait for status match |
806 | + :returns: None. Raises if timeout is hit. |
807 | + """ |
808 | + |
809 | + if not message: |
810 | + message = re.compile('.*ready.*', re.IGNORECASE) |
811 | + |
812 | + if not exclude_services: |
813 | + exclude_services = [] |
814 | + |
815 | + services = list(set(self.d.services.keys()) - set(exclude_services)) |
816 | + service_messages = {service: message for service in services} |
817 | + self.d.sentry.wait_for_messages(service_messages, timeout=timeout) |
818 | + |
819 | def _get_openstack_release(self): |
820 | """Get openstack release. |
821 |
charm_lint_check #11792 nova-cloud- controller- next for 1chb1n mp273740
LINT OK: passed
Build: http:// 10.245. 162.77: 8080/job/ charm_lint_ check/11792/