Merge lp:~anso/nova/smoketests_fixes into lp:~hudson-openstack/nova/trunk

Proposed by Vish Ishaya
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
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_smoketests.py
python netadmin_smoketests.py

Future cleanup:

* Run all of the available tests with nose
* Prettify the output (a la our tests in nova)
* Some of public_network_smoketests have redundant code and are broken (I'm hoping the guys who did IPV6 can add the ipv6 tests in where appropriate to the other tests and we can delete it)
* Add more tests for other api commands.
* Tests for functionality (can the instance get to the public internet, etc.)

To post a comment you must log in.
Revision history for this message
Jay Pipes (jaypipes) wrote :

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!

review: Approve
Revision history for this message
Devin Carlen (devcamcar) wrote :

cool, looks good

review: Approve
Revision history for this message
OpenStack Infra (hudson-openstack) wrote :

The prerequisite lp:~vishvananda/nova/fix-describe-groups has not yet been merged into lp:nova.

Revision history for this message
Vish Ishaya (vishvananda) wrote :

reapproving now that prereq branch is in.

Revision history for this message
Nachi Ueno (nati-ueno) wrote :

Hi Vish
We will work for

* Some of public_network_smoketests have redundant code and are broken (I'm hoping the guys who did IPV6 can add the ipv6 tests in where appropriate to the other tests and we can delete it)

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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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))