blob: 2c68d6b80f701cc7e4f6930774cd047e14a6e778 [file] [log] [blame]
ZhiQiang Fan39f97222013-09-20 04:49:44 +08001# Copyright 2012 OpenStack Foundation
Attila Fazekasa23f5002012-10-23 19:32:45 +02002# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
Attila Fazekas234d3e82013-02-22 16:39:49 +010016from boto import exception
Matthew Treinisha83a16e2012-12-07 13:44:02 -050017
Masayuki Igawa259c1132013-10-31 17:48:44 +090018from tempest.common.utils import data_utils
Masayuki Igawa224a8272014-02-17 15:07:43 +090019from tempest.common.utils.linux import remote_client
Matthew Treinish88f49ef2014-01-29 18:36:27 +000020from tempest import config
Attila Fazekas234d3e82013-02-22 16:39:49 +010021from tempest import exceptions
Matthew Treinishf4a9b0f2013-07-26 16:58:26 -040022from tempest.openstack.common import log as logging
Masayuki Igawa224a8272014-02-17 15:07:43 +090023from tempest.thirdparty.boto import test as boto_test
24from tempest.thirdparty.boto.utils import s3
25from tempest.thirdparty.boto.utils import wait
Attila Fazekasa23f5002012-10-23 19:32:45 +020026
Matthew Treinish88f49ef2014-01-29 18:36:27 +000027CONF = config.CONF
28
Attila Fazekasa23f5002012-10-23 19:32:45 +020029LOG = logging.getLogger(__name__)
30
31
Masayuki Igawa224a8272014-02-17 15:07:43 +090032class InstanceRunTest(boto_test.BotoTestCase):
Attila Fazekasa23f5002012-10-23 19:32:45 +020033
34 @classmethod
35 def setUpClass(cls):
36 super(InstanceRunTest, cls).setUpClass()
Attila Fazekas234d3e82013-02-22 16:39:49 +010037 if not cls.conclusion['A_I_IMAGES_READY']:
ivan-zhu1feeb382013-01-24 10:14:39 +080038 raise cls.skipException("".join(("EC2 ", cls.__name__,
39 ": requires ami/aki/ari manifest")))
Attila Fazekasa23f5002012-10-23 19:32:45 +020040 cls.s3_client = cls.os.s3_client
41 cls.ec2_client = cls.os.ec2api_client
Attila Fazekas27dd92e2014-02-21 14:49:40 +010042 cls.zone = CONF.boto.aws_zone
Matthew Treinish88f49ef2014-01-29 18:36:27 +000043 cls.materials_path = CONF.boto.s3_materials_path
44 ami_manifest = CONF.boto.ami_manifest
45 aki_manifest = CONF.boto.aki_manifest
46 ari_manifest = CONF.boto.ari_manifest
47 cls.instance_type = CONF.boto.instance_type
Masayuki Igawa259c1132013-10-31 17:48:44 +090048 cls.bucket_name = data_utils.rand_name("s3bucket-")
49 cls.keypair_name = data_utils.rand_name("keypair-")
Attila Fazekasa23f5002012-10-23 19:32:45 +020050 cls.keypair = cls.ec2_client.create_key_pair(cls.keypair_name)
51 cls.addResourceCleanUp(cls.ec2_client.delete_key_pair,
52 cls.keypair_name)
53 bucket = cls.s3_client.create_bucket(cls.bucket_name)
54 cls.addResourceCleanUp(cls.destroy_bucket,
55 cls.s3_client.connection_data,
56 cls.bucket_name)
Masayuki Igawa224a8272014-02-17 15:07:43 +090057 s3.s3_upload_dir(bucket, cls.materials_path)
Attila Fazekasa23f5002012-10-23 19:32:45 +020058 cls.images = {"ami":
Masayuki Igawa259c1132013-10-31 17:48:44 +090059 {"name": data_utils.rand_name("ami-name-"),
Attila Fazekasa23f5002012-10-23 19:32:45 +020060 "location": cls.bucket_name + "/" + ami_manifest},
61 "aki":
Masayuki Igawa259c1132013-10-31 17:48:44 +090062 {"name": data_utils.rand_name("aki-name-"),
Attila Fazekasa23f5002012-10-23 19:32:45 +020063 "location": cls.bucket_name + "/" + aki_manifest},
64 "ari":
Masayuki Igawa259c1132013-10-31 17:48:44 +090065 {"name": data_utils.rand_name("ari-name-"),
Attila Fazekasa23f5002012-10-23 19:32:45 +020066 "location": cls.bucket_name + "/" + ari_manifest}}
67 for image in cls.images.itervalues():
68 image["image_id"] = cls.ec2_client.register_image(
Sean Dague14c68182013-04-14 15:34:30 -040069 name=image["name"],
70 image_location=image["location"])
Attila Fazekasa23f5002012-10-23 19:32:45 +020071 cls.addResourceCleanUp(cls.ec2_client.deregister_image,
72 image["image_id"])
73
74 for image in cls.images.itervalues():
75 def _state():
76 retr = cls.ec2_client.get_image(image["image_id"])
77 return retr.state
Masayuki Igawa224a8272014-02-17 15:07:43 +090078 state = wait.state_wait(_state, "available")
Attila Fazekasa23f5002012-10-23 19:32:45 +020079 if state != "available":
80 for _image in cls.images.itervalues():
Attila Fazekasfa756cb2013-02-12 10:52:42 +010081 cls.ec2_client.deregister_image(_image["image_id"])
Matthew Treinish57160582014-06-09 17:13:48 -040082 raise exceptions.EC2RegisterImageException(
83 image_id=image["image_id"])
Attila Fazekasa23f5002012-10-23 19:32:45 +020084
Burt Holzmanf70f2222013-07-18 23:36:31 -050085 def test_run_idempotent_instances(self):
86 # EC2 run instances idempotently
87
88 def _run_instance(client_token):
89 reservation = self.ec2_client.run_instances(
90 image_id=self.images["ami"]["image_id"],
91 kernel_id=self.images["aki"]["image_id"],
92 ramdisk_id=self.images["ari"]["image_id"],
93 instance_type=self.instance_type,
94 client_token=client_token)
95 rcuk = self.addResourceCleanUp(self.destroy_reservation,
96 reservation)
97 return (reservation, rcuk)
98
99 def _terminate_reservation(reservation, rcuk):
100 for instance in reservation.instances:
101 instance.terminate()
102 self.cancelResourceCleanUp(rcuk)
103
104 reservation_1, rcuk_1 = _run_instance('token_1')
105 reservation_2, rcuk_2 = _run_instance('token_2')
106 reservation_1a, rcuk_1a = _run_instance('token_1')
107
108 self.assertIsNotNone(reservation_1)
109 self.assertIsNotNone(reservation_2)
110 self.assertIsNotNone(reservation_1a)
111
112 # same reservation for token_1
113 self.assertEqual(reservation_1.id, reservation_1a.id)
114
115 # Cancel cleanup -- since it's a duplicate, it's
116 # handled by rcuk1
117 self.cancelResourceCleanUp(rcuk_1a)
118
119 _terminate_reservation(reservation_1, rcuk_1)
120 _terminate_reservation(reservation_2, rcuk_2)
121
Attila Fazekasa23f5002012-10-23 19:32:45 +0200122 def test_run_stop_terminate_instance(self):
Sean Dague64ef48d2013-01-03 17:54:36 -0500123 # EC2 run, stop and terminate instance
Attila Fazekasa23f5002012-10-23 19:32:45 +0200124 image_ami = self.ec2_client.get_image(self.images["ami"]
125 ["image_id"])
126 reservation = image_ami.run(kernel_id=self.images["aki"]["image_id"],
127 ramdisk_id=self.images["ari"]["image_id"],
128 instance_type=self.instance_type)
129 rcuk = self.addResourceCleanUp(self.destroy_reservation, reservation)
130
Attila Fazekasa23f5002012-10-23 19:32:45 +0200131 for instance in reservation.instances:
132 LOG.info("state: %s", instance.state)
133 if instance.state != "running":
Attila Fazekas40aa3612013-01-19 22:16:38 +0100134 self.assertInstanceStateWait(instance, "running")
Attila Fazekasa23f5002012-10-23 19:32:45 +0200135
136 for instance in reservation.instances:
137 instance.stop()
138 LOG.info("state: %s", instance.state)
139 if instance.state != "stopped":
Attila Fazekas40aa3612013-01-19 22:16:38 +0100140 self.assertInstanceStateWait(instance, "stopped")
Attila Fazekasa23f5002012-10-23 19:32:45 +0200141
142 for instance in reservation.instances:
143 instance.terminate()
144 self.cancelResourceCleanUp(rcuk)
145
Burt Holzmanbb575e12013-07-14 00:23:30 -0500146 def test_run_stop_terminate_instance_with_tags(self):
147 # EC2 run, stop and terminate instance with tags
148 image_ami = self.ec2_client.get_image(self.images["ami"]
149 ["image_id"])
150 reservation = image_ami.run(kernel_id=self.images["aki"]["image_id"],
151 ramdisk_id=self.images["ari"]["image_id"],
152 instance_type=self.instance_type)
153 rcuk = self.addResourceCleanUp(self.destroy_reservation, reservation)
154
155 for instance in reservation.instances:
156 LOG.info("state: %s", instance.state)
157 if instance.state != "running":
158 self.assertInstanceStateWait(instance, "running")
159 instance.add_tag('key1', value='value1')
160
161 tags = self.ec2_client.get_all_tags()
Chang Bo Guofc77e932013-09-16 17:38:26 -0700162 self.assertEqual(tags[0].name, 'key1')
163 self.assertEqual(tags[0].value, 'value1')
Burt Holzmanbb575e12013-07-14 00:23:30 -0500164
165 tags = self.ec2_client.get_all_tags(filters={'key': 'key1'})
Chang Bo Guofc77e932013-09-16 17:38:26 -0700166 self.assertEqual(tags[0].name, 'key1')
167 self.assertEqual(tags[0].value, 'value1')
Burt Holzmanbb575e12013-07-14 00:23:30 -0500168
169 tags = self.ec2_client.get_all_tags(filters={'value': 'value1'})
Chang Bo Guofc77e932013-09-16 17:38:26 -0700170 self.assertEqual(tags[0].name, 'key1')
171 self.assertEqual(tags[0].value, 'value1')
Burt Holzmanbb575e12013-07-14 00:23:30 -0500172
173 tags = self.ec2_client.get_all_tags(filters={'key': 'value2'})
Attila Fazekas849708e2013-09-25 17:33:56 +0200174 self.assertEqual(len(tags), 0, str(tags))
Burt Holzmanbb575e12013-07-14 00:23:30 -0500175
176 for instance in reservation.instances:
177 instance.remove_tag('key1', value='value1')
178
179 tags = self.ec2_client.get_all_tags()
Rushi Agrawald0bea622014-07-07 17:57:08 +0530180
181 # NOTE: Volume-attach and detach causes metadata (tags) to be created
182 # for the volume. So exclude them while asserting.
183 self.assertNotIn('key1', tags)
Burt Holzmanbb575e12013-07-14 00:23:30 -0500184
185 for instance in reservation.instances:
186 instance.stop()
187 LOG.info("state: %s", instance.state)
188 if instance.state != "stopped":
189 self.assertInstanceStateWait(instance, "stopped")
190
191 for instance in reservation.instances:
192 instance.terminate()
193 self.cancelResourceCleanUp(rcuk)
194
Attila Fazekasa23f5002012-10-23 19:32:45 +0200195 def test_run_terminate_instance(self):
Sean Dague64ef48d2013-01-03 17:54:36 -0500196 # EC2 run, terminate immediately
Attila Fazekasa23f5002012-10-23 19:32:45 +0200197 image_ami = self.ec2_client.get_image(self.images["ami"]
198 ["image_id"])
199 reservation = image_ami.run(kernel_id=self.images["aki"]["image_id"],
200 ramdisk_id=self.images["ari"]["image_id"],
201 instance_type=self.instance_type)
202
203 for instance in reservation.instances:
204 instance.terminate()
Attila Fazekas37f83042013-01-12 16:13:03 +0100205 try:
206 instance.update(validate=True)
207 except ValueError:
208 pass
Attila Fazekas234d3e82013-02-22 16:39:49 +0100209 except exception.EC2ResponseError as exc:
Attila Fazekas37f83042013-01-12 16:13:03 +0100210 if self.ec2_error_code.\
Andrey Pavlov5fbfdcd2014-05-21 14:32:34 +0400211 client.InvalidInstanceID.NotFound.match(exc) is None:
Attila Fazekas37f83042013-01-12 16:13:03 +0100212 pass
213 else:
214 raise
215 else:
216 self.assertNotEqual(instance.state, "running")
Attila Fazekasa23f5002012-10-23 19:32:45 +0200217
Sean Dague3b563352014-04-22 20:00:46 -0400218 def test_compute_with_volumes(self):
Sean Dague64ef48d2013-01-03 17:54:36 -0500219 # EC2 1. integration test (not strict)
Attila Fazekasa23f5002012-10-23 19:32:45 +0200220 image_ami = self.ec2_client.get_image(self.images["ami"]["image_id"])
Masayuki Igawa259c1132013-10-31 17:48:44 +0900221 sec_group_name = data_utils.rand_name("securitygroup-")
Attila Fazekasa23f5002012-10-23 19:32:45 +0200222 group_desc = sec_group_name + " security group description "
223 security_group = self.ec2_client.create_security_group(sec_group_name,
224 group_desc)
225 self.addResourceCleanUp(self.destroy_security_group_wait,
226 security_group)
Sean Dague14c68182013-04-14 15:34:30 -0400227 self.assertTrue(
228 self.ec2_client.authorize_security_group(
Chris Yeoh86732f92013-02-27 20:52:06 +1030229 sec_group_name,
230 ip_protocol="icmp",
231 cidr_ip="0.0.0.0/0",
232 from_port=-1,
233 to_port=-1))
Sean Dague14c68182013-04-14 15:34:30 -0400234 self.assertTrue(
235 self.ec2_client.authorize_security_group(
Chris Yeoh86732f92013-02-27 20:52:06 +1030236 sec_group_name,
237 ip_protocol="tcp",
238 cidr_ip="0.0.0.0/0",
239 from_port=22,
240 to_port=22))
Attila Fazekasa23f5002012-10-23 19:32:45 +0200241 reservation = image_ami.run(kernel_id=self.images["aki"]["image_id"],
242 ramdisk_id=self.images["ari"]["image_id"],
243 instance_type=self.instance_type,
244 key_name=self.keypair_name,
245 security_groups=(sec_group_name,))
Sean Dague3b563352014-04-22 20:00:46 -0400246
247 LOG.debug("Instance booted - state: %s",
248 reservation.instances[0].state)
249
Attila Fazekasa23f5002012-10-23 19:32:45 +0200250 self.addResourceCleanUp(self.destroy_reservation,
251 reservation)
252 volume = self.ec2_client.create_volume(1, self.zone)
Sean Dague3b563352014-04-22 20:00:46 -0400253 LOG.debug("Volume created - status: %s", volume.status)
254
Attila Fazekasa23f5002012-10-23 19:32:45 +0200255 self.addResourceCleanUp(self.destroy_volume_wait, volume)
256 instance = reservation.instances[0]
Attila Fazekasa23f5002012-10-23 19:32:45 +0200257 if instance.state != "running":
Attila Fazekas40aa3612013-01-19 22:16:38 +0100258 self.assertInstanceStateWait(instance, "running")
Sean Dague3b563352014-04-22 20:00:46 -0400259 LOG.debug("Instance now running - state: %s", instance.state)
Attila Fazekasa23f5002012-10-23 19:32:45 +0200260
261 address = self.ec2_client.allocate_address()
262 rcuk_a = self.addResourceCleanUp(address.delete)
Chris Yeoh86732f92013-02-27 20:52:06 +1030263 self.assertTrue(address.associate(instance.id))
Attila Fazekasa23f5002012-10-23 19:32:45 +0200264
265 rcuk_da = self.addResourceCleanUp(address.disassociate)
Attila Fazekas3e381f72013-08-01 16:52:23 +0200266 # TODO(afazekas): ping test. dependecy/permission ?
Attila Fazekasa23f5002012-10-23 19:32:45 +0200267
Attila Fazekas40aa3612013-01-19 22:16:38 +0100268 self.assertVolumeStatusWait(volume, "available")
Marc Solanasb15d8b62014-02-07 00:04:15 -0800269 # NOTE(afazekas): it may be reports available before it is available
Attila Fazekasa23f5002012-10-23 19:32:45 +0200270
Masayuki Igawa224a8272014-02-17 15:07:43 +0900271 ssh = remote_client.RemoteClient(address.public_ip,
272 CONF.compute.ssh_user,
273 pkey=self.keypair.material)
Masayuki Igawa259c1132013-10-31 17:48:44 +0900274 text = data_utils.rand_name("Pattern text for console output -")
Attila Fazekasa23f5002012-10-23 19:32:45 +0200275 resp = ssh.write_to_console(text)
276 self.assertFalse(resp)
277
278 def _output():
279 output = instance.get_console_output()
280 return output.output
281
Masayuki Igawa224a8272014-02-17 15:07:43 +0900282 wait.re_search_wait(_output, text)
Attila Fazekasa23f5002012-10-23 19:32:45 +0200283 part_lines = ssh.get_partitions().split('\n')
Attila Fazekasa23f5002012-10-23 19:32:45 +0200284 volume.attach(instance.id, "/dev/vdh")
285
Attila Fazekas40aa3612013-01-19 22:16:38 +0100286 def _volume_state():
Sean Dague3b563352014-04-22 20:00:46 -0400287 """Return volume state realizing that 'in-use' is overloaded."""
Attila Fazekas40aa3612013-01-19 22:16:38 +0100288 volume.update(validate=True)
Sean Dague3b563352014-04-22 20:00:46 -0400289 status = volume.status
290 attached = volume.attach_data.status
291 LOG.debug("Volume %s is in status: %s, attach_status: %s",
292 volume.id, status, attached)
293 # Nova reports 'in-use' on 'attaching' volumes because we
294 # have a single volume status, and EC2 has 2. Ensure that
295 # if we aren't attached yet we return something other than
296 # 'in-use'
297 if status == 'in-use' and attached != 'attached':
298 return 'attaching'
299 else:
300 return status
Attila Fazekas40aa3612013-01-19 22:16:38 +0100301
Masayuki Igawa224a8272014-02-17 15:07:43 +0900302 wait.re_search_wait(_volume_state, "in-use")
Attila Fazekasa23f5002012-10-23 19:32:45 +0200303
Attila Fazekas3e381f72013-08-01 16:52:23 +0200304 # NOTE(afazekas): Different Hypervisor backends names
Attila Fazekasa23f5002012-10-23 19:32:45 +0200305 # differently the devices,
306 # now we just test is the partition number increased/decrised
307
308 def _part_state():
309 current = ssh.get_partitions().split('\n')
Sean Dague3b563352014-04-22 20:00:46 -0400310 LOG.debug("Partition map for instance: %s", current)
Attila Fazekasa23f5002012-10-23 19:32:45 +0200311 if current > part_lines:
312 return 'INCREASE'
313 if current < part_lines:
314 return 'DECREASE'
315 return 'EQUAL'
316
Masayuki Igawa224a8272014-02-17 15:07:43 +0900317 wait.state_wait(_part_state, 'INCREASE')
Attila Fazekasa23f5002012-10-23 19:32:45 +0200318 part_lines = ssh.get_partitions().split('\n')
319
Attila Fazekas3e381f72013-08-01 16:52:23 +0200320 # TODO(afazekas): Resource compare to the flavor settings
Attila Fazekasa23f5002012-10-23 19:32:45 +0200321
Chris Yeohf2a5e822013-05-08 21:33:00 +0930322 volume.detach()
Attila Fazekasa23f5002012-10-23 19:32:45 +0200323
Chris Yeohf2a5e822013-05-08 21:33:00 +0930324 self.assertVolumeStatusWait(_volume_state, "available")
Masayuki Igawa224a8272014-02-17 15:07:43 +0900325 wait.re_search_wait(_volume_state, "available")
Attila Fazekasa23f5002012-10-23 19:32:45 +0200326
Masayuki Igawa224a8272014-02-17 15:07:43 +0900327 wait.state_wait(_part_state, 'DECREASE')
Attila Fazekasa23f5002012-10-23 19:32:45 +0200328
329 instance.stop()
330 address.disassociate()
331 self.assertAddressDissasociatedWait(address)
332 self.cancelResourceCleanUp(rcuk_da)
333 address.release()
334 self.assertAddressReleasedWait(address)
335 self.cancelResourceCleanUp(rcuk_a)
336
Sean Dague3b563352014-04-22 20:00:46 -0400337 LOG.debug("Instance %s state: %s", instance.id, instance.state)
Attila Fazekasa23f5002012-10-23 19:32:45 +0200338 if instance.state != "stopped":
Attila Fazekas40aa3612013-01-19 22:16:38 +0100339 self.assertInstanceStateWait(instance, "stopped")
Attila Fazekas3e381f72013-08-01 16:52:23 +0200340 # TODO(afazekas): move steps from teardown to the test case
Attila Fazekasa23f5002012-10-23 19:32:45 +0200341
342
Attila Fazekas3e381f72013-08-01 16:52:23 +0200343# TODO(afazekas): Snapshot/volume read/write test case