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
=== modified file 'contrib/nova.sh'
--- contrib/nova.sh 2011-01-21 23:48:10 +0000
+++ contrib/nova.sh 2011-02-23 02:16:10 +0000
@@ -66,7 +66,7 @@
66 sudo apt-get install -y user-mode-linux kvm libvirt-bin66 sudo apt-get install -y user-mode-linux kvm libvirt-bin
67 sudo apt-get install -y screen euca2ools vlan curl rabbitmq-server67 sudo apt-get install -y screen euca2ools vlan curl rabbitmq-server
68 sudo apt-get install -y lvm2 iscsitarget open-iscsi68 sudo apt-get install -y lvm2 iscsitarget open-iscsi
69 sudo apt-get install -y socat69 sudo apt-get install -y socat unzip
70 echo "ISCSITARGET_ENABLE=true" | sudo tee /etc/default/iscsitarget70 echo "ISCSITARGET_ENABLE=true" | sudo tee /etc/default/iscsitarget
71 sudo /etc/init.d/iscsitarget restart71 sudo /etc/init.d/iscsitarget restart
72 sudo modprobe kvm72 sudo modprobe kvm
@@ -111,8 +111,7 @@
111--nodaemon111--nodaemon
112--dhcpbridge_flagfile=$NOVA_DIR/bin/nova.conf112--dhcpbridge_flagfile=$NOVA_DIR/bin/nova.conf
113--network_manager=nova.network.manager.$NET_MAN113--network_manager=nova.network.manager.$NET_MAN
114--cc_host=$HOST_IP114--my_ip=$HOST_IP
115--routing_source_ip=$HOST_IP
116--sql_connection=$SQL_CONN115--sql_connection=$SQL_CONN
117--auth_driver=nova.auth.$AUTH116--auth_driver=nova.auth.$AUTH
118--libvirt_type=$LIBVIRT_TYPE117--libvirt_type=$LIBVIRT_TYPE
@@ -151,7 +150,6 @@
151 mkdir -p $NOVA_DIR/instances150 mkdir -p $NOVA_DIR/instances
152 rm -rf $NOVA_DIR/networks151 rm -rf $NOVA_DIR/networks
153 mkdir -p $NOVA_DIR/networks152 mkdir -p $NOVA_DIR/networks
154 $NOVA_DIR/tools/clean-vlans
155 if [ ! -d "$NOVA_DIR/images" ]; then153 if [ ! -d "$NOVA_DIR/images" ]; then
156 ln -s $DIR/images $NOVA_DIR/images154 ln -s $DIR/images $NOVA_DIR/images
157 fi155 fi
@@ -169,10 +167,14 @@
169 # create a project called 'admin' with project manager of 'admin'167 # create a project called 'admin' with project manager of 'admin'
170 $NOVA_DIR/bin/nova-manage project create admin admin168 $NOVA_DIR/bin/nova-manage project create admin admin
171 # export environment variables for project 'admin' and user 'admin'169 # export environment variables for project 'admin' and user 'admin'
172 $NOVA_DIR/bin/nova-manage project environment admin admin $NOVA_DIR/novarc170 $NOVA_DIR/bin/nova-manage project zipfile admin admin $NOVA_DIR/nova.zip
171 unzip -o $NOVA_DIR/nova.zip -d $NOVA_DIR/
173 # create a small network172 # create a small network
174 $NOVA_DIR/bin/nova-manage network create 10.0.0.0/8 1 32173 $NOVA_DIR/bin/nova-manage network create 10.0.0.0/8 1 32
175174
175 # create some floating ips
176 $NOVA_DIR/bin/nova-manage floating create `hostname` 10.6.0.0/27
177
176 # nova api crashes if we start it with a regular screen command,178 # nova api crashes if we start it with a regular screen command,
177 # so send the start command by forcing text into the window.179 # so send the start command by forcing text into the window.
178 screen_it api "$NOVA_DIR/bin/nova-api"180 screen_it api "$NOVA_DIR/bin/nova-api"
179181
=== modified file 'nova/__init__.py'
--- nova/__init__.py 2010-07-15 15:52:11 +0000
+++ nova/__init__.py 2011-02-23 02:16:10 +0000
@@ -30,5 +30,3 @@
30.. moduleauthor:: Manish Singh <yosh@gimp.org>30.. moduleauthor:: Manish Singh <yosh@gimp.org>
31.. moduleauthor:: Andy Smith <andy@anarkystic.com>31.. moduleauthor:: Andy Smith <andy@anarkystic.com>
32"""32"""
33
34from exception import *
3533
=== modified file 'smoketests/base.py'
--- smoketests/base.py 2010-12-24 11:38:49 +0000
+++ smoketests/base.py 2011-02-23 02:16:10 +0000
@@ -17,19 +17,21 @@
17# under the License.17# under the License.
1818
19import boto19import boto
20import boto_v6
21import commands20import commands
22import httplib21import httplib
23import os22import os
24import paramiko23import paramiko
25import random
26import sys24import sys
25import time
27import unittest26import unittest
28from boto.ec2.regioninfo import RegionInfo27from boto.ec2.regioninfo import RegionInfo
2928
30from smoketests import flags29from smoketests import flags
3130
31SUITE_NAMES = '[image, instance, volume]'
32FLAGS = flags.FLAGS32FLAGS = flags.FLAGS
33flags.DEFINE_string('suite', None, 'Specific test suite to run ' + SUITE_NAMES)
34boto_v6 = None
3335
3436
35class SmokeTestCase(unittest.TestCase):37class SmokeTestCase(unittest.TestCase):
@@ -39,12 +41,10 @@
39 client = paramiko.SSHClient()41 client = paramiko.SSHClient()
40 client.set_missing_host_key_policy(paramiko.WarningPolicy())42 client.set_missing_host_key_policy(paramiko.WarningPolicy())
41 client.connect(ip, username='root', pkey=key)43 client.connect(ip, username='root', pkey=key)
42 stdin, stdout, stderr = client.exec_command('uptime')
43 print 'uptime: ', stdout.read()
44 return client44 return client
4545
46 def can_ping(self, ip):46 def can_ping(self, ip, command="ping"):
47 """ Attempt to ping the specified IP, and give up after 1 second. """47 """Attempt to ping the specified IP, and give up after 1 second."""
4848
49 # NOTE(devcamcar): ping timeout flag is different in OSX.49 # NOTE(devcamcar): ping timeout flag is different in OSX.
50 if sys.platform == 'darwin':50 if sys.platform == 'darwin':
@@ -52,10 +52,41 @@
52 else:52 else:
53 timeout_flag = 'w'53 timeout_flag = 'w'
5454
55 status, output = commands.getstatusoutput('ping -c1 -%s1 %s' %55 status, output = commands.getstatusoutput('%s -c1 -%s1 %s' %
56 (timeout_flag, ip))56 (command, timeout_flag, ip))
57 return status == 057 return status == 0
5858
59 def wait_for_running(self, instance, tries=60, wait=1):
60 """Wait for instance to be running"""
61 for x in xrange(tries):
62 instance.update()
63 if instance.state.startswith('running'):
64 return True
65 time.sleep(wait)
66 else:
67 return False
68
69 def wait_for_ping(self, ip, command="ping", tries=120):
70 """Wait for ip to be pingable"""
71 for x in xrange(tries):
72 if self.can_ping(ip, command):
73 return True
74 else:
75 return False
76
77 def wait_for_ssh(self, ip, key_name, tries=30, wait=5):
78 """Wait for ip to be sshable"""
79 for x in xrange(tries):
80 try:
81 conn = self.connect_ssh(ip, key_name)
82 conn.close()
83 except Exception, e:
84 time.sleep(wait)
85 else:
86 return True
87 else:
88 return False
89
59 def connection_for_env(self, **kwargs):90 def connection_for_env(self, **kwargs):
60 """91 """
61 Returns a boto ec2 connection for the current environment.92 Returns a boto ec2 connection for the current environment.
@@ -144,8 +175,21 @@
144 return True175 return True
145176
146177
178TEST_DATA = {}
179
180
181class UserSmokeTestCase(SmokeTestCase):
182 def setUp(self):
183 global TEST_DATA
184 self.conn = self.connection_for_env()
185 self.data = TEST_DATA
186
187
147def run_tests(suites):188def run_tests(suites):
148 argv = FLAGS(sys.argv)189 argv = FLAGS(sys.argv)
190 if FLAGS.use_ipv6:
191 global boto_v6
192 boto_v6 = __import__('boto_v6')
149193
150 if not os.getenv('EC2_ACCESS_KEY'):194 if not os.getenv('EC2_ACCESS_KEY'):
151 print >> sys.stderr, 'Missing EC2 environment variables. Please ' \195 print >> sys.stderr, 'Missing EC2 environment variables. Please ' \
152196
=== modified file 'smoketests/flags.py'
--- smoketests/flags.py 2010-12-24 11:38:49 +0000
+++ smoketests/flags.py 2011-02-23 02:16:10 +0000
@@ -35,5 +35,5 @@
35# http://code.google.com/p/python-gflags/source/browse/trunk/gflags.py#3935# http://code.google.com/p/python-gflags/source/browse/trunk/gflags.py#39
3636
37DEFINE_string('region', 'nova', 'Region to use')37DEFINE_string('region', 'nova', 'Region to use')
38DEFINE_string('test_image', 'ami-tiny', 'Image to use for launch tests')38DEFINE_string('test_image', 'ami-tty', 'Image to use for launch tests')
39DEFINE_string('use_ipv6', True, 'use the ipv6 or not')39DEFINE_bool('use_ipv6', False, 'use the ipv6 or not')
4040
=== added file 'smoketests/netadmin_smoketests.py'
--- smoketests/netadmin_smoketests.py 1970-01-01 00:00:00 +0000
+++ smoketests/netadmin_smoketests.py 2011-02-23 02:16:10 +0000
@@ -0,0 +1,194 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19import commands
20import os
21import random
22import sys
23import time
24import unittest
25
26# If ../nova/__init__.py exists, add ../ to Python search path, so that
27# it will override what happens to be installed in /usr/(local/)lib/python...
28possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
29 os.pardir,
30 os.pardir))
31if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
32 sys.path.insert(0, possible_topdir)
33
34from smoketests import flags
35from smoketests import base
36
37
38FLAGS = flags.FLAGS
39
40TEST_PREFIX = 'test%s' % int(random.random() * 1000000)
41TEST_BUCKET = '%s_bucket' % TEST_PREFIX
42TEST_KEY = '%s_key' % TEST_PREFIX
43TEST_GROUP = '%s_group' % TEST_PREFIX
44
45
46class AddressTests(base.UserSmokeTestCase):
47 def test_000_setUp(self):
48 self.create_key_pair(self.conn, TEST_KEY)
49 reservation = self.conn.run_instances(FLAGS.test_image,
50 instance_type='m1.tiny',
51 key_name=TEST_KEY)
52 self.data['instance'] = reservation.instances[0]
53 if not self.wait_for_running(self.data['instance']):
54 self.fail('instance failed to start')
55 self.data['instance'].update()
56 if not self.wait_for_ping(self.data['instance'].private_dns_name):
57 self.fail('could not ping instance')
58 if not self.wait_for_ssh(self.data['instance'].private_dns_name,
59 TEST_KEY):
60 self.fail('could not ssh to instance')
61
62 def test_001_can_allocate_floating_ip(self):
63 result = self.conn.allocate_address()
64 self.assertTrue(hasattr(result, 'public_ip'))
65 self.data['public_ip'] = result.public_ip
66
67 def test_002_can_associate_ip_with_instance(self):
68 result = self.conn.associate_address(self.data['instance'].id,
69 self.data['public_ip'])
70 self.assertTrue(result)
71
72 def test_003_can_ssh_with_public_ip(self):
73 ssh_authorized = False
74 groups = self.conn.get_all_security_groups(['default'])
75 for rule in groups[0].rules:
76 if (rule.ip_protocol == 'tcp' and
77 rule.from_port <= 22 and rule.to_port >= 22):
78 ssh_authorized = True
79 if not ssh_authorized:
80 self.conn.authorize_security_group('default',
81 ip_protocol='tcp',
82 from_port=22,
83 to_port=22)
84 try:
85 if not self.wait_for_ssh(self.data['public_ip'], TEST_KEY):
86 self.fail('could not ssh to public ip')
87 finally:
88 if not ssh_authorized:
89 self.conn.revoke_security_group('default',
90 ip_protocol='tcp',
91 from_port=22,
92 to_port=22)
93
94 def test_004_can_disassociate_ip_from_instance(self):
95 result = self.conn.disassociate_address(self.data['public_ip'])
96 self.assertTrue(result)
97
98 def test_005_can_deallocate_floating_ip(self):
99 result = self.conn.release_address(self.data['public_ip'])
100 self.assertTrue(result)
101
102 def test_999_tearDown(self):
103 self.delete_key_pair(self.conn, TEST_KEY)
104 self.conn.terminate_instances([self.data['instance'].id])
105
106
107class SecurityGroupTests(base.UserSmokeTestCase):
108
109 def __public_instance_is_accessible(self):
110 id_url = "latest/meta-data/instance-id"
111 options = "-s --max-time 1"
112 command = "curl %s %s/%s" % (options, self.data['public_ip'], id_url)
113 instance_id = commands.getoutput(command).strip()
114 if not instance_id:
115 return False
116 if instance_id != self.data['instance'].id:
117 raise Exception("Wrong instance id")
118 return True
119
120 def test_001_can_create_security_group(self):
121 self.conn.create_security_group(TEST_GROUP, description='test')
122
123 groups = self.conn.get_all_security_groups()
124 self.assertTrue(TEST_GROUP in [group.name for group in groups])
125
126 def test_002_can_launch_instance_in_security_group(self):
127 with open("proxy.sh") as f:
128 user_data = f.read()
129 self.create_key_pair(self.conn, TEST_KEY)
130 reservation = self.conn.run_instances(FLAGS.test_image,
131 key_name=TEST_KEY,
132 security_groups=[TEST_GROUP],
133 user_data=user_data,
134 instance_type='m1.tiny')
135
136 self.data['instance'] = reservation.instances[0]
137 if not self.wait_for_running(self.data['instance']):
138 self.fail('instance failed to start')
139 self.data['instance'].update()
140 if not self.wait_for_ping(self.data['instance'].private_dns_name):
141 self.fail('could not ping instance')
142 if not self.wait_for_ssh(self.data['instance'].private_dns_name,
143 TEST_KEY):
144 self.fail('could not ssh to instance')
145
146 def test_003_can_authorize_security_group_ingress(self):
147 self.assertTrue(self.conn.authorize_security_group(TEST_GROUP,
148 ip_protocol='tcp',
149 from_port=80,
150 to_port=80))
151
152 def test_004_can_access_metadata_over_public_ip(self):
153 result = self.conn.allocate_address()
154 self.assertTrue(hasattr(result, 'public_ip'))
155 self.data['public_ip'] = result.public_ip
156
157 result = self.conn.associate_address(self.data['instance'].id,
158 self.data['public_ip'])
159 start_time = time.time()
160 try:
161 while not self.__public_instance_is_accessible():
162 # 1 minute to launch
163 if time.time() - start_time > 60:
164 raise Exception("Timeout")
165 time.sleep(1)
166 finally:
167 result = self.conn.disassociate_address(self.data['public_ip'])
168
169 def test_005_can_revoke_security_group_ingress(self):
170 self.assertTrue(self.conn.revoke_security_group(TEST_GROUP,
171 ip_protocol='tcp',
172 from_port=80,
173 to_port=80))
174 start_time = time.time()
175 while self.__public_instance_is_accessible():
176 # 1 minute to teardown
177 if time.time() - start_time > 60:
178 raise Exception("Timeout")
179 time.sleep(1)
180
181 def test_999_tearDown(self):
182 self.conn.delete_key_pair(TEST_KEY)
183 self.conn.delete_security_group(TEST_GROUP)
184 groups = self.conn.get_all_security_groups()
185 self.assertFalse(TEST_GROUP in [group.name for group in groups])
186 self.conn.terminate_instances([self.data['instance'].id])
187 self.assertTrue(self.conn.release_address(self.data['public_ip']))
188
189
190if __name__ == "__main__":
191 suites = {'address': unittest.makeSuite(AddressTests),
192 'security_group': unittest.makeSuite(SecurityGroupTests)
193 }
194 sys.exit(base.run_tests(suites))
0195
=== added file 'smoketests/proxy.sh'
--- smoketests/proxy.sh 1970-01-01 00:00:00 +0000
+++ smoketests/proxy.sh 2011-02-23 02:16:10 +0000
@@ -0,0 +1,22 @@
1#!/usr/bin/env bash
2
3# This is a simple shell script that uses netcat to set up a proxy to the
4# metadata server on port 80 and to a google ip on port 8080. This is meant
5# to be passed in by a script to an instance via user data, so that
6# automatic testing of network connectivity can be performed.
7
8# Example usage:
9# euca-run-instances -t m1.tiny -f proxy.sh ami-tty
10
11mkfifo backpipe1
12mkfifo backpipe2
13
14# NOTE(vish): proxy metadata on port 80
15while true; do
16 nc -l -p 80 0<backpipe1 | nc 169.254.169.254 80 1>backpipe1
17done &
18
19# NOTE(vish): proxy google on port 8080
20while true; do
21 nc -l -p 8080 0<backpipe2 | nc 74.125.19.99 80 1>backpipe2
22done &
023
=== modified file 'smoketests/public_network_smoketests.py'
--- smoketests/public_network_smoketests.py 2010-12-24 11:38:49 +0000
+++ smoketests/public_network_smoketests.py 2011-02-23 02:16:10 +0000
@@ -24,9 +24,16 @@
24import time24import time
25import unittest25import unittest
2626
27# If ../nova/__init__.py exists, add ../ to Python search path, so that
28# it will override what happens to be installed in /usr/(local/)lib/python...
29possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
30 os.pardir,
31 os.pardir))
32if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
33 sys.path.insert(0, possible_topdir)
34
27from smoketests import flags35from smoketests import flags
28from smoketests import base36from smoketests import base
29from smoketests import user_smoketests
3037
31#Note that this test should run from38#Note that this test should run from
32#public network (outside of private network segments)39#public network (outside of private network segments)
@@ -42,7 +49,7 @@
42TEST_DATA = {}49TEST_DATA = {}
4350
4451
45class InstanceTestsFromPublic(user_smoketests.UserSmokeTestCase):52class InstanceTestsFromPublic(base.UserSmokeTestCase):
46 def test_001_can_create_keypair(self):53 def test_001_can_create_keypair(self):
47 key = self.create_key_pair(self.conn, TEST_KEY)54 key = self.create_key_pair(self.conn, TEST_KEY)
48 self.assertEqual(key.name, TEST_KEY)55 self.assertEqual(key.name, TEST_KEY)
4956
=== renamed file 'smoketests/user_smoketests.py' => 'smoketests/sysadmin_smoketests.py'
--- smoketests/user_smoketests.py 2011-01-12 08:47:54 +0000
+++ smoketests/sysadmin_smoketests.py 2011-02-23 02:16:10 +0000
@@ -19,7 +19,6 @@
19import commands19import commands
20import os20import os
21import random21import random
22import socket
23import sys22import sys
24import time23import time
25import unittest24import unittest
@@ -36,10 +35,8 @@
36from smoketests import base35from smoketests import base
3736
3837
39SUITE_NAMES = '[image, instance, volume]'
4038
41FLAGS = flags.FLAGS39FLAGS = flags.FLAGS
42flags.DEFINE_string('suite', None, 'Specific test suite to run ' + SUITE_NAMES)
43flags.DEFINE_string('bundle_kernel', 'openwrt-x86-vmlinuz',40flags.DEFINE_string('bundle_kernel', 'openwrt-x86-vmlinuz',
44 'Local kernel file to use for bundling tests')41 'Local kernel file to use for bundling tests')
45flags.DEFINE_string('bundle_image', 'openwrt-x86-ext2.image',42flags.DEFINE_string('bundle_image', 'openwrt-x86-ext2.image',
@@ -49,17 +46,7 @@
49TEST_BUCKET = '%s_bucket' % TEST_PREFIX46TEST_BUCKET = '%s_bucket' % TEST_PREFIX
50TEST_KEY = '%s_key' % TEST_PREFIX47TEST_KEY = '%s_key' % TEST_PREFIX
51TEST_GROUP = '%s_group' % TEST_PREFIX48TEST_GROUP = '%s_group' % TEST_PREFIX
52TEST_DATA = {}49class ImageTests(base.UserSmokeTestCase):
53
54
55class UserSmokeTestCase(base.SmokeTestCase):
56 def setUp(self):
57 global TEST_DATA
58 self.conn = self.connection_for_env()
59 self.data = TEST_DATA
60
61
62class ImageTests(UserSmokeTestCase):
63 def test_001_can_bundle_image(self):50 def test_001_can_bundle_image(self):
64 self.assertTrue(self.bundle_image(FLAGS.bundle_image))51 self.assertTrue(self.bundle_image(FLAGS.bundle_image))
6552
@@ -91,7 +78,6 @@
91 break78 break
92 time.sleep(1)79 time.sleep(1)
93 else:80 else:
94 print image.state
95 self.assert_(False) # wasn't available within 10 seconds81 self.assert_(False) # wasn't available within 10 seconds
96 self.assert_(image.type == 'machine')82 self.assert_(image.type == 'machine')
9783
@@ -133,7 +119,7 @@
133 self.assertTrue(self.delete_bundle_bucket(TEST_BUCKET))119 self.assertTrue(self.delete_bundle_bucket(TEST_BUCKET))
134120
135121
136class InstanceTests(UserSmokeTestCase):122class InstanceTests(base.UserSmokeTestCase):
137 def test_001_can_create_keypair(self):123 def test_001_can_create_keypair(self):
138 key = self.create_key_pair(self.conn, TEST_KEY)124 key = self.create_key_pair(self.conn, TEST_KEY)
139 self.assertEqual(key.name, TEST_KEY)125 self.assertEqual(key.name, TEST_KEY)
@@ -143,109 +129,44 @@
143 key_name=TEST_KEY,129 key_name=TEST_KEY,
144 instance_type='m1.tiny')130 instance_type='m1.tiny')
145 self.assertEqual(len(reservation.instances), 1)131 self.assertEqual(len(reservation.instances), 1)
146 self.data['instance_id'] = reservation.instances[0].id132 self.data['instance'] = reservation.instances[0]
147133
148 def test_003_instance_runs_within_60_seconds(self):134 def test_003_instance_runs_within_60_seconds(self):
149 reservations = self.conn.get_all_instances([self.data['instance_id']])135 instance = self.data['instance']
150 instance = reservations[0].instances[0]
151 # allow 60 seconds to exit pending with IP136 # allow 60 seconds to exit pending with IP
152 for x in xrange(60):137 if not self.wait_for_running(self.data['instance']):
153 instance.update()
154 if instance.state == u'running':
155 break
156 time.sleep(1)
157 else:
158 self.fail('instance failed to start')138 self.fail('instance failed to start')
159 ip = reservations[0].instances[0].private_dns_name139 self.data['instance'].update()
140 ip = self.data['instance'].private_dns_name
160 self.failIf(ip == '0.0.0.0')141 self.failIf(ip == '0.0.0.0')
161 self.data['private_ip'] = ip
162 if FLAGS.use_ipv6:142 if FLAGS.use_ipv6:
163 ipv6 = reservations[0].instances[0].dns_name_v6143 ipv6 = self.data['instance'].dns_name_v6
164 self.failIf(ipv6 is None)144 self.failIf(ipv6 is None)
165 self.data['ip_v6'] = ipv6
166145
167 def test_004_can_ping_private_ip(self):146 def test_004_can_ping_private_ip(self):
168 for x in xrange(120):147 if not self.wait_for_ping(self.data['instance'].private_dns_name):
169 # ping waits for 1 second
170 status, output = commands.getstatusoutput(
171 'ping -c1 %s' % self.data['private_ip'])
172 if status == 0:
173 break
174 else:
175 self.fail('could not ping instance')148 self.fail('could not ping instance')
176149
177 if FLAGS.use_ipv6:150 if FLAGS.use_ipv6:
178 for x in xrange(120):151 if not self.wait_for_ping(self.data['instance'].ip_v6, "ping6"):
179 # ping waits for 1 second152 self.fail('could not ping instance v6')
180 status, output = commands.getstatusoutput(
181 'ping6 -c1 %s' % self.data['ip_v6'])
182 if status == 0:
183 break
184 else:
185 self.fail('could not ping instance')
186153
187 def test_005_can_ssh_to_private_ip(self):154 def test_005_can_ssh_to_private_ip(self):
188 for x in xrange(30):155 if not self.wait_for_ssh(self.data['instance'].private_dns_name,
189 try:156 TEST_KEY):
190 conn = self.connect_ssh(self.data['private_ip'], TEST_KEY)
191 conn.close()
192 except Exception:
193 time.sleep(1)
194 else:
195 break
196 else:
197 self.fail('could not ssh to instance')157 self.fail('could not ssh to instance')
198158
199 if FLAGS.use_ipv6:159 if FLAGS.use_ipv6:
200 for x in xrange(30):160 if not self.wait_for_ssh(self.data['instance'].ip_v6,
201 try:161 TEST_KEY):
202 conn = self.connect_ssh(
203 self.data['ip_v6'], TEST_KEY)
204 conn.close()
205 except Exception:
206 time.sleep(1)
207 else:
208 break
209 else:
210 self.fail('could not ssh to instance v6')162 self.fail('could not ssh to instance v6')
211163
212 def test_006_can_allocate_elastic_ip(self):
213 result = self.conn.allocate_address()
214 self.assertTrue(hasattr(result, 'public_ip'))
215 self.data['public_ip'] = result.public_ip
216
217 def test_007_can_associate_ip_with_instance(self):
218 result = self.conn.associate_address(self.data['instance_id'],
219 self.data['public_ip'])
220 self.assertTrue(result)
221
222 def test_008_can_ssh_with_public_ip(self):
223 for x in xrange(30):
224 try:
225 conn = self.connect_ssh(self.data['public_ip'], TEST_KEY)
226 conn.close()
227 except socket.error:
228 time.sleep(1)
229 else:
230 break
231 else:
232 self.fail('could not ssh to instance')
233
234 def test_009_can_disassociate_ip_from_instance(self):
235 result = self.conn.disassociate_address(self.data['public_ip'])
236 self.assertTrue(result)
237
238 def test_010_can_deallocate_elastic_ip(self):
239 result = self.conn.release_address(self.data['public_ip'])
240 self.assertTrue(result)
241
242 def test_999_tearDown(self):164 def test_999_tearDown(self):
243 self.delete_key_pair(self.conn, TEST_KEY)165 self.delete_key_pair(self.conn, TEST_KEY)
244 if self.data.has_key('instance_id'):166 self.conn.terminate_instances([self.data['instance'].id])
245 self.conn.terminate_instances([self.data['instance_id']])167
246168
247169class VolumeTests(base.UserSmokeTestCase):
248class VolumeTests(UserSmokeTestCase):
249 def setUp(self):170 def setUp(self):
250 super(VolumeTests, self).setUp()171 super(VolumeTests, self).setUp()
251 self.device = '/dev/vdb'172 self.device = '/dev/vdb'
@@ -255,55 +176,65 @@
255 reservation = self.conn.run_instances(FLAGS.test_image,176 reservation = self.conn.run_instances(FLAGS.test_image,
256 instance_type='m1.tiny',177 instance_type='m1.tiny',
257 key_name=TEST_KEY)178 key_name=TEST_KEY)
258 instance = reservation.instances[0]179 self.data['instance'] = reservation.instances[0]
259 self.data['instance'] = instance180 if not self.wait_for_running(self.data['instance']):
260 for x in xrange(120):181 self.fail('instance failed to start')
261 if self.can_ping(instance.private_dns_name):182 self.data['instance'].update()
262 break183 if not self.wait_for_ping(self.data['instance'].private_dns_name):
263 else:184 self.fail('could not ping instance')
264 self.fail('unable to start instance')185 if not self.wait_for_ssh(self.data['instance'].private_dns_name,
186 TEST_KEY):
187 self.fail('could not ssh to instance')
265188
266 def test_001_can_create_volume(self):189 def test_001_can_create_volume(self):
267 volume = self.conn.create_volume(1, 'nova')190 volume = self.conn.create_volume(1, 'nova')
268 self.assertEqual(volume.size, 1)191 self.assertEqual(volume.size, 1)
269 self.data['volume'] = volume192 self.data['volume'] = volume
270 # Give network time to find volume.193 # Give network time to find volume.
271 time.sleep(5)194 time.sleep(10)
272195
273 def test_002_can_attach_volume(self):196 def test_002_can_attach_volume(self):
274 volume = self.data['volume']197 volume = self.data['volume']
275198
276 for x in xrange(10):199 for x in xrange(10):
277 if volume.status == u'available':200 volume.update()
201 if volume.status.startswith('available'):
278 break202 break
279 time.sleep(5)203 time.sleep(1)
280 volume.update()
281 else:204 else:
282 self.fail('cannot attach volume with state %s' % volume.status)205 self.fail('cannot attach volume with state %s' % volume.status)
283206
284 volume.attach(self.data['instance'].id, self.device)207 volume.attach(self.data['instance'].id, self.device)
285208
286 # Volumes seems to report "available" too soon.209 # wait
287 for x in xrange(10):210 for x in xrange(10):
288 if volume.status == u'in-use':211 volume.update()
212 if volume.status.startswith('in-use'):
289 break213 break
290 time.sleep(5)214 time.sleep(1)
291 volume.update()215 else:
216 self.fail('volume never got to in use')
292217
293 self.assertEqual(volume.status, u'in-use')218 self.assertTrue(volume.status.startswith('in-use'))
294219
295 # Give instance time to recognize volume.220 # Give instance time to recognize volume.
296 time.sleep(5)221 time.sleep(10)
297222
298 def test_003_can_mount_volume(self):223 def test_003_can_mount_volume(self):
299 ip = self.data['instance'].private_dns_name224 ip = self.data['instance'].private_dns_name
300 conn = self.connect_ssh(ip, TEST_KEY)225 conn = self.connect_ssh(ip, TEST_KEY)
301 commands = []226 # NOTE(vish): this will create an dev for images that don't have
302 commands.append('mkdir -p /mnt/vol')227 # udev rules
303 commands.append('mkfs.ext2 %s' % self.device)228 stdin, stdout, stderr = conn.exec_command(
304 commands.append('mount %s /mnt/vol' % self.device)229 'grep %s /proc/partitions | '
305 commands.append('echo success')230 '`awk \'{print "mknod /dev/"\\$4" b "\\$1" "\\$2}\'`'
306 stdin, stdout, stderr = conn.exec_command(' && '.join(commands))231 % self.device.rpartition('/')[2])
232 exec_list = []
233 exec_list.append('mkdir -p /mnt/vol')
234 exec_list.append('/sbin/mke2fs %s' % self.device)
235 exec_list.append('mount %s /mnt/vol' % self.device)
236 exec_list.append('echo success')
237 stdin, stdout, stderr = conn.exec_command(' && '.join(exec_list))
307 out = stdout.read()238 out = stdout.read()
308 conn.close()239 conn.close()
309 if not out.strip().endswith('success'):240 if not out.strip().endswith('success'):
@@ -327,7 +258,7 @@
327 "df -h | grep %s | awk {'print $2'}" % self.device)258 "df -h | grep %s | awk {'print $2'}" % self.device)
328 out = stdout.read()259 out = stdout.read()
329 conn.close()260 conn.close()
330 if not out.strip() == '1008M':261 if not out.strip() == '1007.9M':
331 self.fail('Volume is not the right size: %s %s' %262 self.fail('Volume is not the right size: %s %s' %
332 (out, stderr.read()))263 (out, stderr.read()))
333264
@@ -354,79 +285,9 @@
354 self.conn.delete_key_pair(TEST_KEY)285 self.conn.delete_key_pair(TEST_KEY)
355286
356287
357class SecurityGroupTests(UserSmokeTestCase):
358
359 def __public_instance_is_accessible(self):
360 id_url = "latest/meta-data/instance-id"
361 options = "-s --max-time 1"
362 command = "curl %s %s/%s" % (options, self.data['public_ip'], id_url)
363 instance_id = commands.getoutput(command).strip()
364 if not instance_id:
365 return False
366 if instance_id != self.data['instance_id']:
367 raise Exception("Wrong instance id")
368 return True
369
370 def test_001_can_create_security_group(self):
371 self.conn.create_security_group(TEST_GROUP, description='test')
372
373 groups = self.conn.get_all_security_groups()
374 self.assertTrue(TEST_GROUP in [group.name for group in groups])
375
376 def test_002_can_launch_instance_in_security_group(self):
377 self.create_key_pair(self.conn, TEST_KEY)
378 reservation = self.conn.run_instances(FLAGS.test_image,
379 key_name=TEST_KEY,
380 security_groups=[TEST_GROUP],
381 instance_type='m1.tiny')
382
383 self.data['instance_id'] = reservation.instances[0].id
384
385 def test_003_can_authorize_security_group_ingress(self):
386 self.assertTrue(self.conn.authorize_security_group(TEST_GROUP,
387 ip_protocol='tcp',
388 from_port=80,
389 to_port=80))
390
391 def test_004_can_access_instance_over_public_ip(self):
392 result = self.conn.allocate_address()
393 self.assertTrue(hasattr(result, 'public_ip'))
394 self.data['public_ip'] = result.public_ip
395
396 result = self.conn.associate_address(self.data['instance_id'],
397 self.data['public_ip'])
398 start_time = time.time()
399 while not self.__public_instance_is_accessible():
400 # 1 minute to launch
401 if time.time() - start_time > 60:
402 raise Exception("Timeout")
403 time.sleep(1)
404
405 def test_005_can_revoke_security_group_ingress(self):
406 self.assertTrue(self.conn.revoke_security_group(TEST_GROUP,
407 ip_protocol='tcp',
408 from_port=80,
409 to_port=80))
410 start_time = time.time()
411 while self.__public_instance_is_accessible():
412 # 1 minute to teardown
413 if time.time() - start_time > 60:
414 raise Exception("Timeout")
415 time.sleep(1)
416
417 def test_999_tearDown(self):
418 self.conn.delete_key_pair(TEST_KEY)
419 self.conn.delete_security_group(TEST_GROUP)
420 groups = self.conn.get_all_security_groups()
421 self.assertFalse(TEST_GROUP in [group.name for group in groups])
422 self.conn.terminate_instances([self.data['instance_id']])
423 self.assertTrue(self.conn.release_address(self.data['public_ip']))
424
425
426if __name__ == "__main__":288if __name__ == "__main__":
427 suites = {'image': unittest.makeSuite(ImageTests),289 suites = {'image': unittest.makeSuite(ImageTests),
428 'instance': unittest.makeSuite(InstanceTests),290 'instance': unittest.makeSuite(InstanceTests),
429 'security_group': unittest.makeSuite(SecurityGroupTests),
430 'volume': unittest.makeSuite(VolumeTests)291 'volume': unittest.makeSuite(VolumeTests)
431 }292 }
432 sys.exit(base.run_tests(suites))293 sys.exit(base.run_tests(suites))