Merge lp:~anso/nova/smoketests_fixes into lp:~hudson-openstack/nova/trunk
- smoketests_fixes
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Vish Ishaya |
Approved revision: | 529 |
Merged at revision: | 722 |
Proposed branch: | lp:~anso/nova/smoketests_fixes |
Merge into: | lp:~hudson-openstack/nova/trunk |
Prerequisite: | lp:~vishvananda/nova/fix-describe-groups |
Diff against target: |
798 lines (+339/-211) 8 files modified
contrib/nova.sh (+7/-5) nova/__init__.py (+0/-2) smoketests/base.py (+52/-8) smoketests/flags.py (+2/-2) smoketests/netadmin_smoketests.py (+194/-0) smoketests/proxy.sh (+22/-0) smoketests/public_network_smoketests.py (+9/-2) smoketests/sysadmin_smoketests.py (+53/-192) |
To merge this branch: | bzr merge lp:~anso/nova/smoketests_fixes |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Devin Carlen (community) | Approve | ||
Jay Pipes (community) | Approve | ||
Review via email: mp+50850@code.launchpad.net |
Commit message
Fixes existing smoketests and splits out sysadmin tests from netadmin tests.
* sets use_ipv6 = False by default
* switches to ami-tty for tests
* generally improves error handling
Description of the change
Fixes existing smoketests and splits out sysadmin tests from netadmin tests.
* sets use_ipv6 = False by default
* switches to ami-tty for tests
* generally improves error handling
There is a lot more that can be done here, but I want to get this out so people actually start running them and adding more.
To run the tests:
source an rc file (make sure that it comes from a nova.zip if you want to test image uploading)
cd smoketests
python admin_smoketests.py
python sysadmin_
python netadmin_
Future cleanup:
* Run all of the available tests with nose
* Prettify the output (a la our tests in nova)
* Some of public_
* Add more tests for other api commands.
* Tests for functionality (can the instance get to the public internet, etc.)
Devin Carlen (devcamcar) wrote : | # |
cool, looks good
OpenStack Infra (hudson-openstack) wrote : | # |
The prerequisite lp:~vishvananda/nova/fix-describe-groups has not yet been merged into lp:nova.
Vish Ishaya (vishvananda) wrote : | # |
reapproving now that prereq branch is in.
Nachi Ueno (nati-ueno) wrote : | # |
Hi Vish
We will work for
* Some of public_
If you have any idea for design test for some network topology ( Single Node environment in which Compute node and Network node stay in same box, Multi-Node in which Compute node and Network node stay in different box or Multiple Network node environment, would you tell me that?
Preview Diff
1 | === modified file 'contrib/nova.sh' |
2 | --- contrib/nova.sh 2011-01-21 23:48:10 +0000 |
3 | +++ contrib/nova.sh 2011-02-23 02:16:10 +0000 |
4 | @@ -66,7 +66,7 @@ |
5 | sudo apt-get install -y user-mode-linux kvm libvirt-bin |
6 | sudo apt-get install -y screen euca2ools vlan curl rabbitmq-server |
7 | sudo apt-get install -y lvm2 iscsitarget open-iscsi |
8 | - sudo apt-get install -y socat |
9 | + sudo apt-get install -y socat unzip |
10 | echo "ISCSITARGET_ENABLE=true" | sudo tee /etc/default/iscsitarget |
11 | sudo /etc/init.d/iscsitarget restart |
12 | sudo modprobe kvm |
13 | @@ -111,8 +111,7 @@ |
14 | --nodaemon |
15 | --dhcpbridge_flagfile=$NOVA_DIR/bin/nova.conf |
16 | --network_manager=nova.network.manager.$NET_MAN |
17 | ---cc_host=$HOST_IP |
18 | ---routing_source_ip=$HOST_IP |
19 | +--my_ip=$HOST_IP |
20 | --sql_connection=$SQL_CONN |
21 | --auth_driver=nova.auth.$AUTH |
22 | --libvirt_type=$LIBVIRT_TYPE |
23 | @@ -151,7 +150,6 @@ |
24 | mkdir -p $NOVA_DIR/instances |
25 | rm -rf $NOVA_DIR/networks |
26 | mkdir -p $NOVA_DIR/networks |
27 | - $NOVA_DIR/tools/clean-vlans |
28 | if [ ! -d "$NOVA_DIR/images" ]; then |
29 | ln -s $DIR/images $NOVA_DIR/images |
30 | fi |
31 | @@ -169,10 +167,14 @@ |
32 | # create a project called 'admin' with project manager of 'admin' |
33 | $NOVA_DIR/bin/nova-manage project create admin admin |
34 | # export environment variables for project 'admin' and user 'admin' |
35 | - $NOVA_DIR/bin/nova-manage project environment admin admin $NOVA_DIR/novarc |
36 | + $NOVA_DIR/bin/nova-manage project zipfile admin admin $NOVA_DIR/nova.zip |
37 | + unzip -o $NOVA_DIR/nova.zip -d $NOVA_DIR/ |
38 | # create a small network |
39 | $NOVA_DIR/bin/nova-manage network create 10.0.0.0/8 1 32 |
40 | |
41 | + # create some floating ips |
42 | + $NOVA_DIR/bin/nova-manage floating create `hostname` 10.6.0.0/27 |
43 | + |
44 | # nova api crashes if we start it with a regular screen command, |
45 | # so send the start command by forcing text into the window. |
46 | screen_it api "$NOVA_DIR/bin/nova-api" |
47 | |
48 | === modified file 'nova/__init__.py' |
49 | --- nova/__init__.py 2010-07-15 15:52:11 +0000 |
50 | +++ nova/__init__.py 2011-02-23 02:16:10 +0000 |
51 | @@ -30,5 +30,3 @@ |
52 | .. moduleauthor:: Manish Singh <yosh@gimp.org> |
53 | .. moduleauthor:: Andy Smith <andy@anarkystic.com> |
54 | """ |
55 | - |
56 | -from exception import * |
57 | |
58 | === modified file 'smoketests/base.py' |
59 | --- smoketests/base.py 2010-12-24 11:38:49 +0000 |
60 | +++ smoketests/base.py 2011-02-23 02:16:10 +0000 |
61 | @@ -17,19 +17,21 @@ |
62 | # under the License. |
63 | |
64 | import boto |
65 | -import boto_v6 |
66 | import commands |
67 | import httplib |
68 | import os |
69 | import paramiko |
70 | -import random |
71 | import sys |
72 | +import time |
73 | import unittest |
74 | from boto.ec2.regioninfo import RegionInfo |
75 | |
76 | from smoketests import flags |
77 | |
78 | +SUITE_NAMES = '[image, instance, volume]' |
79 | FLAGS = flags.FLAGS |
80 | +flags.DEFINE_string('suite', None, 'Specific test suite to run ' + SUITE_NAMES) |
81 | +boto_v6 = None |
82 | |
83 | |
84 | class SmokeTestCase(unittest.TestCase): |
85 | @@ -39,12 +41,10 @@ |
86 | client = paramiko.SSHClient() |
87 | client.set_missing_host_key_policy(paramiko.WarningPolicy()) |
88 | client.connect(ip, username='root', pkey=key) |
89 | - stdin, stdout, stderr = client.exec_command('uptime') |
90 | - print 'uptime: ', stdout.read() |
91 | return client |
92 | |
93 | - def can_ping(self, ip): |
94 | - """ Attempt to ping the specified IP, and give up after 1 second. """ |
95 | + def can_ping(self, ip, command="ping"): |
96 | + """Attempt to ping the specified IP, and give up after 1 second.""" |
97 | |
98 | # NOTE(devcamcar): ping timeout flag is different in OSX. |
99 | if sys.platform == 'darwin': |
100 | @@ -52,10 +52,41 @@ |
101 | else: |
102 | timeout_flag = 'w' |
103 | |
104 | - status, output = commands.getstatusoutput('ping -c1 -%s1 %s' % |
105 | - (timeout_flag, ip)) |
106 | + status, output = commands.getstatusoutput('%s -c1 -%s1 %s' % |
107 | + (command, timeout_flag, ip)) |
108 | return status == 0 |
109 | |
110 | + def wait_for_running(self, instance, tries=60, wait=1): |
111 | + """Wait for instance to be running""" |
112 | + for x in xrange(tries): |
113 | + instance.update() |
114 | + if instance.state.startswith('running'): |
115 | + return True |
116 | + time.sleep(wait) |
117 | + else: |
118 | + return False |
119 | + |
120 | + def wait_for_ping(self, ip, command="ping", tries=120): |
121 | + """Wait for ip to be pingable""" |
122 | + for x in xrange(tries): |
123 | + if self.can_ping(ip, command): |
124 | + return True |
125 | + else: |
126 | + return False |
127 | + |
128 | + def wait_for_ssh(self, ip, key_name, tries=30, wait=5): |
129 | + """Wait for ip to be sshable""" |
130 | + for x in xrange(tries): |
131 | + try: |
132 | + conn = self.connect_ssh(ip, key_name) |
133 | + conn.close() |
134 | + except Exception, e: |
135 | + time.sleep(wait) |
136 | + else: |
137 | + return True |
138 | + else: |
139 | + return False |
140 | + |
141 | def connection_for_env(self, **kwargs): |
142 | """ |
143 | Returns a boto ec2 connection for the current environment. |
144 | @@ -144,8 +175,21 @@ |
145 | return True |
146 | |
147 | |
148 | +TEST_DATA = {} |
149 | + |
150 | + |
151 | +class UserSmokeTestCase(SmokeTestCase): |
152 | + def setUp(self): |
153 | + global TEST_DATA |
154 | + self.conn = self.connection_for_env() |
155 | + self.data = TEST_DATA |
156 | + |
157 | + |
158 | def run_tests(suites): |
159 | argv = FLAGS(sys.argv) |
160 | + if FLAGS.use_ipv6: |
161 | + global boto_v6 |
162 | + boto_v6 = __import__('boto_v6') |
163 | |
164 | if not os.getenv('EC2_ACCESS_KEY'): |
165 | print >> sys.stderr, 'Missing EC2 environment variables. Please ' \ |
166 | |
167 | === modified file 'smoketests/flags.py' |
168 | --- smoketests/flags.py 2010-12-24 11:38:49 +0000 |
169 | +++ smoketests/flags.py 2011-02-23 02:16:10 +0000 |
170 | @@ -35,5 +35,5 @@ |
171 | # http://code.google.com/p/python-gflags/source/browse/trunk/gflags.py#39 |
172 | |
173 | DEFINE_string('region', 'nova', 'Region to use') |
174 | -DEFINE_string('test_image', 'ami-tiny', 'Image to use for launch tests') |
175 | -DEFINE_string('use_ipv6', True, 'use the ipv6 or not') |
176 | +DEFINE_string('test_image', 'ami-tty', 'Image to use for launch tests') |
177 | +DEFINE_bool('use_ipv6', False, 'use the ipv6 or not') |
178 | |
179 | === added file 'smoketests/netadmin_smoketests.py' |
180 | --- smoketests/netadmin_smoketests.py 1970-01-01 00:00:00 +0000 |
181 | +++ smoketests/netadmin_smoketests.py 2011-02-23 02:16:10 +0000 |
182 | @@ -0,0 +1,194 @@ |
183 | +# vim: tabstop=4 shiftwidth=4 softtabstop=4 |
184 | + |
185 | +# Copyright 2010 United States Government as represented by the |
186 | +# Administrator of the National Aeronautics and Space Administration. |
187 | +# All Rights Reserved. |
188 | +# |
189 | +# Licensed under the Apache License, Version 2.0 (the "License"); you may |
190 | +# not use this file except in compliance with the License. You may obtain |
191 | +# a copy of the License at |
192 | +# |
193 | +# http://www.apache.org/licenses/LICENSE-2.0 |
194 | +# |
195 | +# Unless required by applicable law or agreed to in writing, software |
196 | +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
197 | +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
198 | +# License for the specific language governing permissions and limitations |
199 | +# under the License. |
200 | + |
201 | +import commands |
202 | +import os |
203 | +import random |
204 | +import sys |
205 | +import time |
206 | +import unittest |
207 | + |
208 | +# If ../nova/__init__.py exists, add ../ to Python search path, so that |
209 | +# it will override what happens to be installed in /usr/(local/)lib/python... |
210 | +possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), |
211 | + os.pardir, |
212 | + os.pardir)) |
213 | +if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')): |
214 | + sys.path.insert(0, possible_topdir) |
215 | + |
216 | +from smoketests import flags |
217 | +from smoketests import base |
218 | + |
219 | + |
220 | +FLAGS = flags.FLAGS |
221 | + |
222 | +TEST_PREFIX = 'test%s' % int(random.random() * 1000000) |
223 | +TEST_BUCKET = '%s_bucket' % TEST_PREFIX |
224 | +TEST_KEY = '%s_key' % TEST_PREFIX |
225 | +TEST_GROUP = '%s_group' % TEST_PREFIX |
226 | + |
227 | + |
228 | +class AddressTests(base.UserSmokeTestCase): |
229 | + def test_000_setUp(self): |
230 | + self.create_key_pair(self.conn, TEST_KEY) |
231 | + reservation = self.conn.run_instances(FLAGS.test_image, |
232 | + instance_type='m1.tiny', |
233 | + key_name=TEST_KEY) |
234 | + self.data['instance'] = reservation.instances[0] |
235 | + if not self.wait_for_running(self.data['instance']): |
236 | + self.fail('instance failed to start') |
237 | + self.data['instance'].update() |
238 | + if not self.wait_for_ping(self.data['instance'].private_dns_name): |
239 | + self.fail('could not ping instance') |
240 | + if not self.wait_for_ssh(self.data['instance'].private_dns_name, |
241 | + TEST_KEY): |
242 | + self.fail('could not ssh to instance') |
243 | + |
244 | + def test_001_can_allocate_floating_ip(self): |
245 | + result = self.conn.allocate_address() |
246 | + self.assertTrue(hasattr(result, 'public_ip')) |
247 | + self.data['public_ip'] = result.public_ip |
248 | + |
249 | + def test_002_can_associate_ip_with_instance(self): |
250 | + result = self.conn.associate_address(self.data['instance'].id, |
251 | + self.data['public_ip']) |
252 | + self.assertTrue(result) |
253 | + |
254 | + def test_003_can_ssh_with_public_ip(self): |
255 | + ssh_authorized = False |
256 | + groups = self.conn.get_all_security_groups(['default']) |
257 | + for rule in groups[0].rules: |
258 | + if (rule.ip_protocol == 'tcp' and |
259 | + rule.from_port <= 22 and rule.to_port >= 22): |
260 | + ssh_authorized = True |
261 | + if not ssh_authorized: |
262 | + self.conn.authorize_security_group('default', |
263 | + ip_protocol='tcp', |
264 | + from_port=22, |
265 | + to_port=22) |
266 | + try: |
267 | + if not self.wait_for_ssh(self.data['public_ip'], TEST_KEY): |
268 | + self.fail('could not ssh to public ip') |
269 | + finally: |
270 | + if not ssh_authorized: |
271 | + self.conn.revoke_security_group('default', |
272 | + ip_protocol='tcp', |
273 | + from_port=22, |
274 | + to_port=22) |
275 | + |
276 | + def test_004_can_disassociate_ip_from_instance(self): |
277 | + result = self.conn.disassociate_address(self.data['public_ip']) |
278 | + self.assertTrue(result) |
279 | + |
280 | + def test_005_can_deallocate_floating_ip(self): |
281 | + result = self.conn.release_address(self.data['public_ip']) |
282 | + self.assertTrue(result) |
283 | + |
284 | + def test_999_tearDown(self): |
285 | + self.delete_key_pair(self.conn, TEST_KEY) |
286 | + self.conn.terminate_instances([self.data['instance'].id]) |
287 | + |
288 | + |
289 | +class SecurityGroupTests(base.UserSmokeTestCase): |
290 | + |
291 | + def __public_instance_is_accessible(self): |
292 | + id_url = "latest/meta-data/instance-id" |
293 | + options = "-s --max-time 1" |
294 | + command = "curl %s %s/%s" % (options, self.data['public_ip'], id_url) |
295 | + instance_id = commands.getoutput(command).strip() |
296 | + if not instance_id: |
297 | + return False |
298 | + if instance_id != self.data['instance'].id: |
299 | + raise Exception("Wrong instance id") |
300 | + return True |
301 | + |
302 | + def test_001_can_create_security_group(self): |
303 | + self.conn.create_security_group(TEST_GROUP, description='test') |
304 | + |
305 | + groups = self.conn.get_all_security_groups() |
306 | + self.assertTrue(TEST_GROUP in [group.name for group in groups]) |
307 | + |
308 | + def test_002_can_launch_instance_in_security_group(self): |
309 | + with open("proxy.sh") as f: |
310 | + user_data = f.read() |
311 | + self.create_key_pair(self.conn, TEST_KEY) |
312 | + reservation = self.conn.run_instances(FLAGS.test_image, |
313 | + key_name=TEST_KEY, |
314 | + security_groups=[TEST_GROUP], |
315 | + user_data=user_data, |
316 | + instance_type='m1.tiny') |
317 | + |
318 | + self.data['instance'] = reservation.instances[0] |
319 | + if not self.wait_for_running(self.data['instance']): |
320 | + self.fail('instance failed to start') |
321 | + self.data['instance'].update() |
322 | + if not self.wait_for_ping(self.data['instance'].private_dns_name): |
323 | + self.fail('could not ping instance') |
324 | + if not self.wait_for_ssh(self.data['instance'].private_dns_name, |
325 | + TEST_KEY): |
326 | + self.fail('could not ssh to instance') |
327 | + |
328 | + def test_003_can_authorize_security_group_ingress(self): |
329 | + self.assertTrue(self.conn.authorize_security_group(TEST_GROUP, |
330 | + ip_protocol='tcp', |
331 | + from_port=80, |
332 | + to_port=80)) |
333 | + |
334 | + def test_004_can_access_metadata_over_public_ip(self): |
335 | + result = self.conn.allocate_address() |
336 | + self.assertTrue(hasattr(result, 'public_ip')) |
337 | + self.data['public_ip'] = result.public_ip |
338 | + |
339 | + result = self.conn.associate_address(self.data['instance'].id, |
340 | + self.data['public_ip']) |
341 | + start_time = time.time() |
342 | + try: |
343 | + while not self.__public_instance_is_accessible(): |
344 | + # 1 minute to launch |
345 | + if time.time() - start_time > 60: |
346 | + raise Exception("Timeout") |
347 | + time.sleep(1) |
348 | + finally: |
349 | + result = self.conn.disassociate_address(self.data['public_ip']) |
350 | + |
351 | + def test_005_can_revoke_security_group_ingress(self): |
352 | + self.assertTrue(self.conn.revoke_security_group(TEST_GROUP, |
353 | + ip_protocol='tcp', |
354 | + from_port=80, |
355 | + to_port=80)) |
356 | + start_time = time.time() |
357 | + while self.__public_instance_is_accessible(): |
358 | + # 1 minute to teardown |
359 | + if time.time() - start_time > 60: |
360 | + raise Exception("Timeout") |
361 | + time.sleep(1) |
362 | + |
363 | + def test_999_tearDown(self): |
364 | + self.conn.delete_key_pair(TEST_KEY) |
365 | + self.conn.delete_security_group(TEST_GROUP) |
366 | + groups = self.conn.get_all_security_groups() |
367 | + self.assertFalse(TEST_GROUP in [group.name for group in groups]) |
368 | + self.conn.terminate_instances([self.data['instance'].id]) |
369 | + self.assertTrue(self.conn.release_address(self.data['public_ip'])) |
370 | + |
371 | + |
372 | +if __name__ == "__main__": |
373 | + suites = {'address': unittest.makeSuite(AddressTests), |
374 | + 'security_group': unittest.makeSuite(SecurityGroupTests) |
375 | + } |
376 | + sys.exit(base.run_tests(suites)) |
377 | |
378 | === added file 'smoketests/proxy.sh' |
379 | --- smoketests/proxy.sh 1970-01-01 00:00:00 +0000 |
380 | +++ smoketests/proxy.sh 2011-02-23 02:16:10 +0000 |
381 | @@ -0,0 +1,22 @@ |
382 | +#!/usr/bin/env bash |
383 | + |
384 | +# This is a simple shell script that uses netcat to set up a proxy to the |
385 | +# metadata server on port 80 and to a google ip on port 8080. This is meant |
386 | +# to be passed in by a script to an instance via user data, so that |
387 | +# automatic testing of network connectivity can be performed. |
388 | + |
389 | +# Example usage: |
390 | +# euca-run-instances -t m1.tiny -f proxy.sh ami-tty |
391 | + |
392 | +mkfifo backpipe1 |
393 | +mkfifo backpipe2 |
394 | + |
395 | +# NOTE(vish): proxy metadata on port 80 |
396 | +while true; do |
397 | + nc -l -p 80 0<backpipe1 | nc 169.254.169.254 80 1>backpipe1 |
398 | +done & |
399 | + |
400 | +# NOTE(vish): proxy google on port 8080 |
401 | +while true; do |
402 | + nc -l -p 8080 0<backpipe2 | nc 74.125.19.99 80 1>backpipe2 |
403 | +done & |
404 | |
405 | === modified file 'smoketests/public_network_smoketests.py' |
406 | --- smoketests/public_network_smoketests.py 2010-12-24 11:38:49 +0000 |
407 | +++ smoketests/public_network_smoketests.py 2011-02-23 02:16:10 +0000 |
408 | @@ -24,9 +24,16 @@ |
409 | import time |
410 | import unittest |
411 | |
412 | +# If ../nova/__init__.py exists, add ../ to Python search path, so that |
413 | +# it will override what happens to be installed in /usr/(local/)lib/python... |
414 | +possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), |
415 | + os.pardir, |
416 | + os.pardir)) |
417 | +if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')): |
418 | + sys.path.insert(0, possible_topdir) |
419 | + |
420 | from smoketests import flags |
421 | from smoketests import base |
422 | -from smoketests import user_smoketests |
423 | |
424 | #Note that this test should run from |
425 | #public network (outside of private network segments) |
426 | @@ -42,7 +49,7 @@ |
427 | TEST_DATA = {} |
428 | |
429 | |
430 | -class InstanceTestsFromPublic(user_smoketests.UserSmokeTestCase): |
431 | +class InstanceTestsFromPublic(base.UserSmokeTestCase): |
432 | def test_001_can_create_keypair(self): |
433 | key = self.create_key_pair(self.conn, TEST_KEY) |
434 | self.assertEqual(key.name, TEST_KEY) |
435 | |
436 | === renamed file 'smoketests/user_smoketests.py' => 'smoketests/sysadmin_smoketests.py' |
437 | --- smoketests/user_smoketests.py 2011-01-12 08:47:54 +0000 |
438 | +++ smoketests/sysadmin_smoketests.py 2011-02-23 02:16:10 +0000 |
439 | @@ -19,7 +19,6 @@ |
440 | import commands |
441 | import os |
442 | import random |
443 | -import socket |
444 | import sys |
445 | import time |
446 | import unittest |
447 | @@ -36,10 +35,8 @@ |
448 | from smoketests import base |
449 | |
450 | |
451 | -SUITE_NAMES = '[image, instance, volume]' |
452 | |
453 | FLAGS = flags.FLAGS |
454 | -flags.DEFINE_string('suite', None, 'Specific test suite to run ' + SUITE_NAMES) |
455 | flags.DEFINE_string('bundle_kernel', 'openwrt-x86-vmlinuz', |
456 | 'Local kernel file to use for bundling tests') |
457 | flags.DEFINE_string('bundle_image', 'openwrt-x86-ext2.image', |
458 | @@ -49,17 +46,7 @@ |
459 | TEST_BUCKET = '%s_bucket' % TEST_PREFIX |
460 | TEST_KEY = '%s_key' % TEST_PREFIX |
461 | TEST_GROUP = '%s_group' % TEST_PREFIX |
462 | -TEST_DATA = {} |
463 | - |
464 | - |
465 | -class UserSmokeTestCase(base.SmokeTestCase): |
466 | - def setUp(self): |
467 | - global TEST_DATA |
468 | - self.conn = self.connection_for_env() |
469 | - self.data = TEST_DATA |
470 | - |
471 | - |
472 | -class ImageTests(UserSmokeTestCase): |
473 | +class ImageTests(base.UserSmokeTestCase): |
474 | def test_001_can_bundle_image(self): |
475 | self.assertTrue(self.bundle_image(FLAGS.bundle_image)) |
476 | |
477 | @@ -91,7 +78,6 @@ |
478 | break |
479 | time.sleep(1) |
480 | else: |
481 | - print image.state |
482 | self.assert_(False) # wasn't available within 10 seconds |
483 | self.assert_(image.type == 'machine') |
484 | |
485 | @@ -133,7 +119,7 @@ |
486 | self.assertTrue(self.delete_bundle_bucket(TEST_BUCKET)) |
487 | |
488 | |
489 | -class InstanceTests(UserSmokeTestCase): |
490 | +class InstanceTests(base.UserSmokeTestCase): |
491 | def test_001_can_create_keypair(self): |
492 | key = self.create_key_pair(self.conn, TEST_KEY) |
493 | self.assertEqual(key.name, TEST_KEY) |
494 | @@ -143,109 +129,44 @@ |
495 | key_name=TEST_KEY, |
496 | instance_type='m1.tiny') |
497 | self.assertEqual(len(reservation.instances), 1) |
498 | - self.data['instance_id'] = reservation.instances[0].id |
499 | + self.data['instance'] = reservation.instances[0] |
500 | |
501 | def test_003_instance_runs_within_60_seconds(self): |
502 | - reservations = self.conn.get_all_instances([self.data['instance_id']]) |
503 | - instance = reservations[0].instances[0] |
504 | + instance = self.data['instance'] |
505 | # allow 60 seconds to exit pending with IP |
506 | - for x in xrange(60): |
507 | - instance.update() |
508 | - if instance.state == u'running': |
509 | - break |
510 | - time.sleep(1) |
511 | - else: |
512 | + if not self.wait_for_running(self.data['instance']): |
513 | self.fail('instance failed to start') |
514 | - ip = reservations[0].instances[0].private_dns_name |
515 | + self.data['instance'].update() |
516 | + ip = self.data['instance'].private_dns_name |
517 | self.failIf(ip == '0.0.0.0') |
518 | - self.data['private_ip'] = ip |
519 | if FLAGS.use_ipv6: |
520 | - ipv6 = reservations[0].instances[0].dns_name_v6 |
521 | + ipv6 = self.data['instance'].dns_name_v6 |
522 | self.failIf(ipv6 is None) |
523 | - self.data['ip_v6'] = ipv6 |
524 | |
525 | def test_004_can_ping_private_ip(self): |
526 | - for x in xrange(120): |
527 | - # ping waits for 1 second |
528 | - status, output = commands.getstatusoutput( |
529 | - 'ping -c1 %s' % self.data['private_ip']) |
530 | - if status == 0: |
531 | - break |
532 | - else: |
533 | + if not self.wait_for_ping(self.data['instance'].private_dns_name): |
534 | self.fail('could not ping instance') |
535 | |
536 | if FLAGS.use_ipv6: |
537 | - for x in xrange(120): |
538 | - # ping waits for 1 second |
539 | - status, output = commands.getstatusoutput( |
540 | - 'ping6 -c1 %s' % self.data['ip_v6']) |
541 | - if status == 0: |
542 | - break |
543 | - else: |
544 | - self.fail('could not ping instance') |
545 | + if not self.wait_for_ping(self.data['instance'].ip_v6, "ping6"): |
546 | + self.fail('could not ping instance v6') |
547 | |
548 | def test_005_can_ssh_to_private_ip(self): |
549 | - for x in xrange(30): |
550 | - try: |
551 | - conn = self.connect_ssh(self.data['private_ip'], TEST_KEY) |
552 | - conn.close() |
553 | - except Exception: |
554 | - time.sleep(1) |
555 | - else: |
556 | - break |
557 | - else: |
558 | + if not self.wait_for_ssh(self.data['instance'].private_dns_name, |
559 | + TEST_KEY): |
560 | self.fail('could not ssh to instance') |
561 | |
562 | if FLAGS.use_ipv6: |
563 | - for x in xrange(30): |
564 | - try: |
565 | - conn = self.connect_ssh( |
566 | - self.data['ip_v6'], TEST_KEY) |
567 | - conn.close() |
568 | - except Exception: |
569 | - time.sleep(1) |
570 | - else: |
571 | - break |
572 | - else: |
573 | + if not self.wait_for_ssh(self.data['instance'].ip_v6, |
574 | + TEST_KEY): |
575 | self.fail('could not ssh to instance v6') |
576 | |
577 | - def test_006_can_allocate_elastic_ip(self): |
578 | - result = self.conn.allocate_address() |
579 | - self.assertTrue(hasattr(result, 'public_ip')) |
580 | - self.data['public_ip'] = result.public_ip |
581 | - |
582 | - def test_007_can_associate_ip_with_instance(self): |
583 | - result = self.conn.associate_address(self.data['instance_id'], |
584 | - self.data['public_ip']) |
585 | - self.assertTrue(result) |
586 | - |
587 | - def test_008_can_ssh_with_public_ip(self): |
588 | - for x in xrange(30): |
589 | - try: |
590 | - conn = self.connect_ssh(self.data['public_ip'], TEST_KEY) |
591 | - conn.close() |
592 | - except socket.error: |
593 | - time.sleep(1) |
594 | - else: |
595 | - break |
596 | - else: |
597 | - self.fail('could not ssh to instance') |
598 | - |
599 | - def test_009_can_disassociate_ip_from_instance(self): |
600 | - result = self.conn.disassociate_address(self.data['public_ip']) |
601 | - self.assertTrue(result) |
602 | - |
603 | - def test_010_can_deallocate_elastic_ip(self): |
604 | - result = self.conn.release_address(self.data['public_ip']) |
605 | - self.assertTrue(result) |
606 | - |
607 | def test_999_tearDown(self): |
608 | self.delete_key_pair(self.conn, TEST_KEY) |
609 | - if self.data.has_key('instance_id'): |
610 | - self.conn.terminate_instances([self.data['instance_id']]) |
611 | - |
612 | - |
613 | -class VolumeTests(UserSmokeTestCase): |
614 | + self.conn.terminate_instances([self.data['instance'].id]) |
615 | + |
616 | + |
617 | +class VolumeTests(base.UserSmokeTestCase): |
618 | def setUp(self): |
619 | super(VolumeTests, self).setUp() |
620 | self.device = '/dev/vdb' |
621 | @@ -255,55 +176,65 @@ |
622 | reservation = self.conn.run_instances(FLAGS.test_image, |
623 | instance_type='m1.tiny', |
624 | key_name=TEST_KEY) |
625 | - instance = reservation.instances[0] |
626 | - self.data['instance'] = instance |
627 | - for x in xrange(120): |
628 | - if self.can_ping(instance.private_dns_name): |
629 | - break |
630 | - else: |
631 | - self.fail('unable to start instance') |
632 | + self.data['instance'] = reservation.instances[0] |
633 | + if not self.wait_for_running(self.data['instance']): |
634 | + self.fail('instance failed to start') |
635 | + self.data['instance'].update() |
636 | + if not self.wait_for_ping(self.data['instance'].private_dns_name): |
637 | + self.fail('could not ping instance') |
638 | + if not self.wait_for_ssh(self.data['instance'].private_dns_name, |
639 | + TEST_KEY): |
640 | + self.fail('could not ssh to instance') |
641 | |
642 | def test_001_can_create_volume(self): |
643 | volume = self.conn.create_volume(1, 'nova') |
644 | self.assertEqual(volume.size, 1) |
645 | self.data['volume'] = volume |
646 | # Give network time to find volume. |
647 | - time.sleep(5) |
648 | + time.sleep(10) |
649 | |
650 | def test_002_can_attach_volume(self): |
651 | volume = self.data['volume'] |
652 | |
653 | for x in xrange(10): |
654 | - if volume.status == u'available': |
655 | + volume.update() |
656 | + if volume.status.startswith('available'): |
657 | break |
658 | - time.sleep(5) |
659 | - volume.update() |
660 | + time.sleep(1) |
661 | else: |
662 | self.fail('cannot attach volume with state %s' % volume.status) |
663 | |
664 | volume.attach(self.data['instance'].id, self.device) |
665 | |
666 | - # Volumes seems to report "available" too soon. |
667 | + # wait |
668 | for x in xrange(10): |
669 | - if volume.status == u'in-use': |
670 | + volume.update() |
671 | + if volume.status.startswith('in-use'): |
672 | break |
673 | - time.sleep(5) |
674 | - volume.update() |
675 | + time.sleep(1) |
676 | + else: |
677 | + self.fail('volume never got to in use') |
678 | |
679 | - self.assertEqual(volume.status, u'in-use') |
680 | + self.assertTrue(volume.status.startswith('in-use')) |
681 | |
682 | # Give instance time to recognize volume. |
683 | - time.sleep(5) |
684 | + time.sleep(10) |
685 | |
686 | def test_003_can_mount_volume(self): |
687 | ip = self.data['instance'].private_dns_name |
688 | conn = self.connect_ssh(ip, TEST_KEY) |
689 | - commands = [] |
690 | - commands.append('mkdir -p /mnt/vol') |
691 | - commands.append('mkfs.ext2 %s' % self.device) |
692 | - commands.append('mount %s /mnt/vol' % self.device) |
693 | - commands.append('echo success') |
694 | - stdin, stdout, stderr = conn.exec_command(' && '.join(commands)) |
695 | + # NOTE(vish): this will create an dev for images that don't have |
696 | + # udev rules |
697 | + stdin, stdout, stderr = conn.exec_command( |
698 | + 'grep %s /proc/partitions | ' |
699 | + '`awk \'{print "mknod /dev/"\\$4" b "\\$1" "\\$2}\'`' |
700 | + % self.device.rpartition('/')[2]) |
701 | + exec_list = [] |
702 | + exec_list.append('mkdir -p /mnt/vol') |
703 | + exec_list.append('/sbin/mke2fs %s' % self.device) |
704 | + exec_list.append('mount %s /mnt/vol' % self.device) |
705 | + exec_list.append('echo success') |
706 | + stdin, stdout, stderr = conn.exec_command(' && '.join(exec_list)) |
707 | out = stdout.read() |
708 | conn.close() |
709 | if not out.strip().endswith('success'): |
710 | @@ -327,7 +258,7 @@ |
711 | "df -h | grep %s | awk {'print $2'}" % self.device) |
712 | out = stdout.read() |
713 | conn.close() |
714 | - if not out.strip() == '1008M': |
715 | + if not out.strip() == '1007.9M': |
716 | self.fail('Volume is not the right size: %s %s' % |
717 | (out, stderr.read())) |
718 | |
719 | @@ -354,79 +285,9 @@ |
720 | self.conn.delete_key_pair(TEST_KEY) |
721 | |
722 | |
723 | -class SecurityGroupTests(UserSmokeTestCase): |
724 | - |
725 | - def __public_instance_is_accessible(self): |
726 | - id_url = "latest/meta-data/instance-id" |
727 | - options = "-s --max-time 1" |
728 | - command = "curl %s %s/%s" % (options, self.data['public_ip'], id_url) |
729 | - instance_id = commands.getoutput(command).strip() |
730 | - if not instance_id: |
731 | - return False |
732 | - if instance_id != self.data['instance_id']: |
733 | - raise Exception("Wrong instance id") |
734 | - return True |
735 | - |
736 | - def test_001_can_create_security_group(self): |
737 | - self.conn.create_security_group(TEST_GROUP, description='test') |
738 | - |
739 | - groups = self.conn.get_all_security_groups() |
740 | - self.assertTrue(TEST_GROUP in [group.name for group in groups]) |
741 | - |
742 | - def test_002_can_launch_instance_in_security_group(self): |
743 | - self.create_key_pair(self.conn, TEST_KEY) |
744 | - reservation = self.conn.run_instances(FLAGS.test_image, |
745 | - key_name=TEST_KEY, |
746 | - security_groups=[TEST_GROUP], |
747 | - instance_type='m1.tiny') |
748 | - |
749 | - self.data['instance_id'] = reservation.instances[0].id |
750 | - |
751 | - def test_003_can_authorize_security_group_ingress(self): |
752 | - self.assertTrue(self.conn.authorize_security_group(TEST_GROUP, |
753 | - ip_protocol='tcp', |
754 | - from_port=80, |
755 | - to_port=80)) |
756 | - |
757 | - def test_004_can_access_instance_over_public_ip(self): |
758 | - result = self.conn.allocate_address() |
759 | - self.assertTrue(hasattr(result, 'public_ip')) |
760 | - self.data['public_ip'] = result.public_ip |
761 | - |
762 | - result = self.conn.associate_address(self.data['instance_id'], |
763 | - self.data['public_ip']) |
764 | - start_time = time.time() |
765 | - while not self.__public_instance_is_accessible(): |
766 | - # 1 minute to launch |
767 | - if time.time() - start_time > 60: |
768 | - raise Exception("Timeout") |
769 | - time.sleep(1) |
770 | - |
771 | - def test_005_can_revoke_security_group_ingress(self): |
772 | - self.assertTrue(self.conn.revoke_security_group(TEST_GROUP, |
773 | - ip_protocol='tcp', |
774 | - from_port=80, |
775 | - to_port=80)) |
776 | - start_time = time.time() |
777 | - while self.__public_instance_is_accessible(): |
778 | - # 1 minute to teardown |
779 | - if time.time() - start_time > 60: |
780 | - raise Exception("Timeout") |
781 | - time.sleep(1) |
782 | - |
783 | - def test_999_tearDown(self): |
784 | - self.conn.delete_key_pair(TEST_KEY) |
785 | - self.conn.delete_security_group(TEST_GROUP) |
786 | - groups = self.conn.get_all_security_groups() |
787 | - self.assertFalse(TEST_GROUP in [group.name for group in groups]) |
788 | - self.conn.terminate_instances([self.data['instance_id']]) |
789 | - self.assertTrue(self.conn.release_address(self.data['public_ip'])) |
790 | - |
791 | - |
792 | if __name__ == "__main__": |
793 | suites = {'image': unittest.makeSuite(ImageTests), |
794 | 'instance': unittest.makeSuite(InstanceTests), |
795 | - 'security_group': unittest.makeSuite(SecurityGroupTests), |
796 | 'volume': unittest.makeSuite(VolumeTests) |
797 | } |
798 | sys.exit(base.run_tests(suites)) |
This is excellent refactoring, Vishy. Very impressed. Looking forward to your future cleanups. Now, let's get these running on some test machines from Hudson!