blob: def775062f39fc985ce8b6c7c57adeba91f24a4e [file] [log] [blame]
ZhiQiang Fan39f97222013-09-20 04:49:44 +08001# Copyright 2012 OpenStack Foundation
Jay Pipes50677282012-01-06 15:39:20 -05002# 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
Matthew Treinishb0c65f22015-04-23 09:09:41 -040016from six import moves
Matthew Treinish01472ff2015-02-20 17:26:52 -050017
Sean Dague1937d092013-05-17 16:36:38 -040018from tempest.api.image import base
Ken'ichi Ohmichi01151e82016-06-10 11:19:52 -070019from tempest.common import image as common_image
Fei Long Wangd39431f2015-05-14 11:30:48 +120020from tempest.common.utils import data_utils
Yaroslav Lobankov2fea4052016-04-19 15:05:57 +030021from tempest.common import waiters
Matthew Treinishbc0e03e2014-01-30 16:51:06 +000022from tempest import config
Takashi NATSUMEb7d85912015-11-10 13:24:48 +090023from tempest import exceptions
ivan-zhud1bbe5d2013-12-29 18:32:46 +080024from tempest import test
Jay Pipes50677282012-01-06 15:39:20 -050025
Matthew Treinishbc0e03e2014-01-30 16:51:06 +000026CONF = config.CONF
27
Jay Pipes50677282012-01-06 15:39:20 -050028
Takashi NATSUMEb7d85912015-11-10 13:24:48 +090029def get_container_and_disk_format():
30 a_formats = ['ami', 'ari', 'aki']
31
32 container_format = CONF.image.container_formats[0]
33 disk_format = CONF.image.disk_formats[0]
34
35 if container_format in a_formats and container_format != disk_format:
36 msg = ("The container format and the disk format don't match. "
zhuflc35b36e2016-05-12 10:16:07 +080037 "Container format: %(container)s, Disk format: %(disk)s." %
Takashi NATSUMEb7d85912015-11-10 13:24:48 +090038 {'container': container_format, 'disk': disk_format})
39 raise exceptions.InvalidConfiguration(message=msg)
40
41 return container_format, disk_format
42
43
Matthew Treinishce3ef922013-03-11 14:02:46 -040044class CreateRegisterImagesTest(base.BaseV1ImageTest):
45 """Here we test the registration and creation of images."""
Jay Pipes50677282012-01-06 15:39:20 -050046
Chris Hoge7579c1a2015-02-26 14:12:15 -080047 @test.idempotent_id('3027f8e6-3492-4a11-8575-c3293017af4d')
Jay Pipes50677282012-01-06 15:39:20 -050048 def test_register_then_upload(self):
Sean Dague46c4a2b2013-01-03 17:54:17 -050049 # Register, then upload an image
Matthew Treinish72ea4422013-02-07 14:42:49 -050050 properties = {'prop1': 'val1'}
Takashi NATSUMEb7d85912015-11-10 13:24:48 +090051 container_format, disk_format = get_container_and_disk_format()
David Kranz34f18782015-01-06 13:43:55 -050052 body = self.create_image(name='New Name',
Takashi NATSUMEb7d85912015-11-10 13:24:48 +090053 container_format=container_format,
54 disk_format=disk_format,
David Kranz34f18782015-01-06 13:43:55 -050055 is_public=False,
56 properties=properties)
Attila Fazekase191cb12013-07-29 06:41:52 +020057 self.assertIn('id', body)
Matthew Treinish72ea4422013-02-07 14:42:49 -050058 image_id = body.get('id')
Matthew Treinish72ea4422013-02-07 14:42:49 -050059 self.assertEqual('New Name', body.get('name'))
Aaron Rosenc7720622014-05-20 10:38:10 -070060 self.assertFalse(body.get('is_public'))
Matthew Treinish72ea4422013-02-07 14:42:49 -050061 self.assertEqual('queued', body.get('status'))
Matthew Treinish72ea4422013-02-07 14:42:49 -050062 for key, val in properties.items():
63 self.assertEqual(val, body.get('properties')[key])
Jay Pipes50677282012-01-06 15:39:20 -050064
65 # Now try uploading an image file
Matthew Treinishb0c65f22015-04-23 09:09:41 -040066 image_file = moves.cStringIO(data_utils.random_bytes())
John Warren66207252015-07-31 15:51:02 -040067 body = self.client.update_image(image_id, data=image_file)['image']
Attila Fazekase191cb12013-07-29 06:41:52 +020068 self.assertIn('size', body)
Matthew Treinish72ea4422013-02-07 14:42:49 -050069 self.assertEqual(1024, body.get('size'))
Jay Pipes50677282012-01-06 15:39:20 -050070
Chris Hoge7579c1a2015-02-26 14:12:15 -080071 @test.idempotent_id('69da74d9-68a9-404b-9664-ff7164ccb0f5')
Jay Pipes50677282012-01-06 15:39:20 -050072 def test_register_remote_image(self):
Sean Dague46c4a2b2013-01-03 17:54:17 -050073 # Register a new remote image
Takashi NATSUMEb7d85912015-11-10 13:24:48 +090074 container_format, disk_format = get_container_and_disk_format()
David Kranz34f18782015-01-06 13:43:55 -050075 body = self.create_image(name='New Remote Image',
Takashi NATSUMEb7d85912015-11-10 13:24:48 +090076 container_format=container_format,
77 disk_format=disk_format, is_public=False,
David Kranz34f18782015-01-06 13:43:55 -050078 location=CONF.image.http_image,
79 properties={'key1': 'value1',
80 'key2': 'value2'})
Attila Fazekase191cb12013-07-29 06:41:52 +020081 self.assertIn('id', body)
Matthew Treinish72ea4422013-02-07 14:42:49 -050082 self.assertEqual('New Remote Image', body.get('name'))
Aaron Rosenc7720622014-05-20 10:38:10 -070083 self.assertFalse(body.get('is_public'))
Matthew Treinish72ea4422013-02-07 14:42:49 -050084 self.assertEqual('active', body.get('status'))
afazekas4a96bf82013-03-25 16:07:38 +010085 properties = body.get('properties')
86 self.assertEqual(properties['key1'], 'value1')
87 self.assertEqual(properties['key2'], 'value2')
Jay Pipes50677282012-01-06 15:39:20 -050088
Chris Hoge7579c1a2015-02-26 14:12:15 -080089 @test.idempotent_id('6d0e13a7-515b-460c-b91f-9f4793f09816')
Attila Fazekase72b7cd2013-03-26 18:34:21 +010090 def test_register_http_image(self):
Takashi NATSUMEb7d85912015-11-10 13:24:48 +090091 container_format, disk_format = get_container_and_disk_format()
David Kranz34f18782015-01-06 13:43:55 -050092 body = self.create_image(name='New Http Image',
Takashi NATSUMEb7d85912015-11-10 13:24:48 +090093 container_format=container_format,
94 disk_format=disk_format, is_public=False,
David Kranz34f18782015-01-06 13:43:55 -050095 copy_from=CONF.image.http_image)
Attila Fazekase191cb12013-07-29 06:41:52 +020096 self.assertIn('id', body)
Attila Fazekase72b7cd2013-03-26 18:34:21 +010097 image_id = body.get('id')
Attila Fazekase72b7cd2013-03-26 18:34:21 +010098 self.assertEqual('New Http Image', body.get('name'))
Aaron Rosenc7720622014-05-20 10:38:10 -070099 self.assertFalse(body.get('is_public'))
Yaroslav Lobankov2fea4052016-04-19 15:05:57 +0300100 waiters.wait_for_image_status(self.client, image_id, 'active')
Ken'ichi Ohmichi5d410762015-05-22 01:10:03 +0000101 self.client.show_image(image_id)
Attila Fazekase72b7cd2013-03-26 18:34:21 +0100102
Chris Hoge7579c1a2015-02-26 14:12:15 -0800103 @test.idempotent_id('05b19d55-140c-40d0-b36b-fafd774d421b')
hi2suresh75a20302013-04-09 09:17:06 +0000104 def test_register_image_with_min_ram(self):
105 # Register an image with min ram
Takashi NATSUMEb7d85912015-11-10 13:24:48 +0900106 container_format, disk_format = get_container_and_disk_format()
hi2suresh75a20302013-04-09 09:17:06 +0000107 properties = {'prop1': 'val1'}
David Kranz34f18782015-01-06 13:43:55 -0500108 body = self.create_image(name='New_image_with_min_ram',
Takashi NATSUMEb7d85912015-11-10 13:24:48 +0900109 container_format=container_format,
110 disk_format=disk_format,
David Kranz34f18782015-01-06 13:43:55 -0500111 is_public=False,
112 min_ram=40,
113 properties=properties)
Attila Fazekase191cb12013-07-29 06:41:52 +0200114 self.assertIn('id', body)
hi2suresh75a20302013-04-09 09:17:06 +0000115 self.assertEqual('New_image_with_min_ram', body.get('name'))
Aaron Rosenc7720622014-05-20 10:38:10 -0700116 self.assertFalse(body.get('is_public'))
hi2suresh75a20302013-04-09 09:17:06 +0000117 self.assertEqual('queued', body.get('status'))
118 self.assertEqual(40, body.get('min_ram'))
119 for key, val in properties.items():
120 self.assertEqual(val, body.get('properties')[key])
David Kranz9c3b3b62014-06-19 16:05:53 -0400121 self.client.delete_image(body['id'])
hi2suresh75a20302013-04-09 09:17:06 +0000122
Jay Pipes50677282012-01-06 15:39:20 -0500123
Matthew Treinishce3ef922013-03-11 14:02:46 -0400124class ListImagesTest(base.BaseV1ImageTest):
Ken'ichi Ohmichi9e3dac02015-11-19 07:01:07 +0000125 """Here we test the listing of image information"""
Jay Pipes50677282012-01-06 15:39:20 -0500126
127 @classmethod
Takashi NATSUMEb7d85912015-11-10 13:24:48 +0900128 def skip_checks(cls):
129 super(ListImagesTest, cls).skip_checks()
130 if (len(CONF.image.container_formats) < 2
131 or len(CONF.image.disk_formats) < 2):
132 skip_msg = ("%s skipped as multiple container formats "
133 "or disk formats are not available." % cls.__name__)
134 raise cls.skipException(skip_msg)
135
136 @classmethod
Andrea Frittoli69a6b632014-09-15 13:14:53 +0100137 def resource_setup(cls):
138 super(ListImagesTest, cls).resource_setup()
Jay Pipes50677282012-01-06 15:39:20 -0500139 # We add a few images here to test the listing functionality of
140 # the images API
Takashi NATSUMEb7d85912015-11-10 13:24:48 +0900141 a_formats = ['ami', 'ari', 'aki']
142
143 (cls.container_format,
144 cls.container_format_alt) = CONF.image.container_formats[:2]
145 cls.disk_format, cls.disk_format_alt = CONF.image.disk_formats[:2]
146 if cls.container_format in a_formats:
147 cls.disk_format = cls.container_format
148 if cls.container_format_alt in a_formats:
149 cls.disk_format_alt = cls.container_format_alt
150
151 img1 = cls._create_remote_image('one', cls.container_format,
152 cls.disk_format)
153 img2 = cls._create_remote_image('two', cls.container_format_alt,
154 cls.disk_format_alt)
155 img3 = cls._create_remote_image('dup', cls.container_format,
156 cls.disk_format)
157 img4 = cls._create_remote_image('dup', cls.container_format,
158 cls.disk_format)
159 img5 = cls._create_standard_image('1', cls.container_format_alt,
160 cls.disk_format_alt, 42)
161 img6 = cls._create_standard_image('2', cls.container_format_alt,
162 cls.disk_format_alt, 142)
163 img7 = cls._create_standard_image('33', cls.container_format,
164 cls.disk_format, 142)
165 img8 = cls._create_standard_image('33', cls.container_format,
166 cls.disk_format, 142)
Attila Fazekas11795b52013-02-24 15:49:08 +0100167 cls.created_set = set(cls.created_images)
Takashi NATSUMEb7d85912015-11-10 13:24:48 +0900168 # same container format
169 cls.same_container_format_set = set((img1, img3, img4, img7, img8))
170 # same disk format
171 cls.same_disk_format_set = set((img2, img5, img6))
172
Attila Fazekas11795b52013-02-24 15:49:08 +0100173 # 1x with size 42
174 cls.size42_set = set((img5,))
175 # 3x with size 142
ivan-zhud1bbe5d2013-12-29 18:32:46 +0800176 cls.size142_set = set((img6, img7, img8,))
Attila Fazekas11795b52013-02-24 15:49:08 +0100177 # dup named
178 cls.dup_set = set((img3, img4))
Jay Pipes50677282012-01-06 15:39:20 -0500179
180 @classmethod
Attila Fazekas11795b52013-02-24 15:49:08 +0100181 def _create_remote_image(cls, name, container_format, disk_format):
Ken'ichi Ohmichi9e3dac02015-11-19 07:01:07 +0000182 """Create a new remote image and return newly-registered image-id"""
183
Attila Fazekas11795b52013-02-24 15:49:08 +0100184 name = 'New Remote Image %s' % name
Matthew Treinishe81ae692014-06-19 17:41:31 -0400185 location = CONF.image.http_image
David Kranz34f18782015-01-06 13:43:55 -0500186 image = cls.create_image(name=name,
187 container_format=container_format,
188 disk_format=disk_format,
189 is_public=False,
190 location=location)
Attila Fazekas11795b52013-02-24 15:49:08 +0100191 image_id = image['id']
Jay Pipes50677282012-01-06 15:39:20 -0500192 return image_id
193
194 @classmethod
Attila Fazekas11795b52013-02-24 15:49:08 +0100195 def _create_standard_image(cls, name, container_format,
196 disk_format, size):
Ken'ichi Ohmichi9e3dac02015-11-19 07:01:07 +0000197 """Create a new standard image and return newly-registered image-id
198
199 Note that the size of the new image is a random number between
Jay Pipes50677282012-01-06 15:39:20 -0500200 1024 and 4096
201 """
Matthew Treinishb0c65f22015-04-23 09:09:41 -0400202 image_file = moves.cStringIO(data_utils.random_bytes(size))
Attila Fazekas11795b52013-02-24 15:49:08 +0100203 name = 'New Standard Image %s' % name
David Kranz34f18782015-01-06 13:43:55 -0500204 image = cls.create_image(name=name,
205 container_format=container_format,
206 disk_format=disk_format,
207 is_public=False, data=image_file)
Attila Fazekas11795b52013-02-24 15:49:08 +0100208 image_id = image['id']
Jay Pipes50677282012-01-06 15:39:20 -0500209 return image_id
210
Chris Hoge7579c1a2015-02-26 14:12:15 -0800211 @test.idempotent_id('246178ab-3b33-4212-9a4b-a7fe8261794d')
Jay Pipes50677282012-01-06 15:39:20 -0500212 def test_index_no_params(self):
Sean Dague46c4a2b2013-01-03 17:54:17 -0500213 # Simple test to see all fixture images returned
John Warren66207252015-07-31 15:51:02 -0400214 images_list = self.client.list_images()['images']
Matthew Treinish72ea4422013-02-07 14:42:49 -0500215 image_list = map(lambda x: x['id'], images_list)
Attila Fazekas11795b52013-02-24 15:49:08 +0100216 for image_id in self.created_images:
Attila Fazekase191cb12013-07-29 06:41:52 +0200217 self.assertIn(image_id, image_list)
Attila Fazekas11795b52013-02-24 15:49:08 +0100218
Chris Hoge7579c1a2015-02-26 14:12:15 -0800219 @test.idempotent_id('f1755589-63d6-4468-b098-589820eb4031')
Attila Fazekas11795b52013-02-24 15:49:08 +0100220 def test_index_disk_format(self):
Takashi NATSUMEb7d85912015-11-10 13:24:48 +0900221 images_list = self.client.list_images(
222 disk_format=self.disk_format_alt)['images']
Attila Fazekas11795b52013-02-24 15:49:08 +0100223 for image in images_list:
Takashi NATSUMEb7d85912015-11-10 13:24:48 +0900224 self.assertEqual(image['disk_format'], self.disk_format_alt)
Attila Fazekas11795b52013-02-24 15:49:08 +0100225 result_set = set(map(lambda x: x['id'], images_list))
Takashi NATSUMEb7d85912015-11-10 13:24:48 +0900226 self.assertTrue(self.same_disk_format_set <= result_set)
227 self.assertFalse(self.created_set - self.same_disk_format_set
228 <= result_set)
Attila Fazekas11795b52013-02-24 15:49:08 +0100229
Chris Hoge7579c1a2015-02-26 14:12:15 -0800230 @test.idempotent_id('2143655d-96d9-4bec-9188-8674206b4b3b')
Attila Fazekas11795b52013-02-24 15:49:08 +0100231 def test_index_container_format(self):
Takashi NATSUMEb7d85912015-11-10 13:24:48 +0900232 images_list = self.client.list_images(
233 container_format=self.container_format)['images']
Attila Fazekas11795b52013-02-24 15:49:08 +0100234 for image in images_list:
Takashi NATSUMEb7d85912015-11-10 13:24:48 +0900235 self.assertEqual(image['container_format'], self.container_format)
Attila Fazekas11795b52013-02-24 15:49:08 +0100236 result_set = set(map(lambda x: x['id'], images_list))
Takashi NATSUMEb7d85912015-11-10 13:24:48 +0900237 self.assertTrue(self.same_container_format_set <= result_set)
238 self.assertFalse(self.created_set - self.same_container_format_set
239 <= result_set)
Attila Fazekas11795b52013-02-24 15:49:08 +0100240
Chris Hoge7579c1a2015-02-26 14:12:15 -0800241 @test.idempotent_id('feb32ac6-22bb-4a16-afd8-9454bb714b14')
Attila Fazekas11795b52013-02-24 15:49:08 +0100242 def test_index_max_size(self):
John Warren66207252015-07-31 15:51:02 -0400243 images_list = self.client.list_images(size_max=42)['images']
Attila Fazekas11795b52013-02-24 15:49:08 +0100244 for image in images_list:
245 self.assertTrue(image['size'] <= 42)
246 result_set = set(map(lambda x: x['id'], images_list))
247 self.assertTrue(self.size42_set <= result_set)
248 self.assertFalse(self.created_set - self.size42_set <= result_set)
249
Chris Hoge7579c1a2015-02-26 14:12:15 -0800250 @test.idempotent_id('6ffc16d0-4cbf-4401-95c8-4ac63eac34d8')
Attila Fazekas11795b52013-02-24 15:49:08 +0100251 def test_index_min_size(self):
John Warren66207252015-07-31 15:51:02 -0400252 images_list = self.client.list_images(size_min=142)['images']
Attila Fazekas11795b52013-02-24 15:49:08 +0100253 for image in images_list:
254 self.assertTrue(image['size'] >= 142)
255 result_set = set(map(lambda x: x['id'], images_list))
256 self.assertTrue(self.size142_set <= result_set)
257 self.assertFalse(self.size42_set <= result_set)
258
Chris Hoge7579c1a2015-02-26 14:12:15 -0800259 @test.idempotent_id('e5dc26d9-9aa2-48dd-bda5-748e1445da98')
Attila Fazekas11795b52013-02-24 15:49:08 +0100260 def test_index_status_active_detail(self):
Ken'ichi Ohmichibcad2a22015-05-22 09:37:06 +0000261 images_list = self.client.list_images(detail=True,
262 status='active',
263 sort_key='size',
John Warren66207252015-07-31 15:51:02 -0400264 sort_dir='desc')['images']
Attila Fazekas11795b52013-02-24 15:49:08 +0100265 top_size = images_list[0]['size'] # We have non-zero sized images
266 for image in images_list:
267 size = image['size']
268 self.assertTrue(size <= top_size)
269 top_size = size
270 self.assertEqual(image['status'], 'active')
271
Chris Hoge7579c1a2015-02-26 14:12:15 -0800272 @test.idempotent_id('097af10a-bae8-4342-bff4-edf89969ed2a')
Attila Fazekas11795b52013-02-24 15:49:08 +0100273 def test_index_name(self):
Ken'ichi Ohmichibcad2a22015-05-22 09:37:06 +0000274 images_list = self.client.list_images(
275 detail=True,
John Warren66207252015-07-31 15:51:02 -0400276 name='New Remote Image dup')['images']
Attila Fazekas11795b52013-02-24 15:49:08 +0100277 result_set = set(map(lambda x: x['id'], images_list))
278 for image in images_list:
279 self.assertEqual(image['name'], 'New Remote Image dup')
280 self.assertTrue(self.dup_set <= result_set)
281 self.assertFalse(self.created_set - self.dup_set <= result_set)
ivan-zhud1bbe5d2013-12-29 18:32:46 +0800282
283
ivan-zhud1bbe5d2013-12-29 18:32:46 +0800284class UpdateImageMetaTest(base.BaseV1ImageTest):
285 @classmethod
Andrea Frittoli69a6b632014-09-15 13:14:53 +0100286 def resource_setup(cls):
287 super(UpdateImageMetaTest, cls).resource_setup()
Takashi NATSUMEb7d85912015-11-10 13:24:48 +0900288 container_format, disk_format = get_container_and_disk_format()
289 cls.image_id = cls._create_standard_image('1', container_format,
290 disk_format, 42)
ivan-zhud1bbe5d2013-12-29 18:32:46 +0800291
292 @classmethod
293 def _create_standard_image(cls, name, container_format,
294 disk_format, size):
Ken'ichi Ohmichi9e3dac02015-11-19 07:01:07 +0000295 """Create a new standard image and return newly-registered image-id"""
296
Matthew Treinishb0c65f22015-04-23 09:09:41 -0400297 image_file = moves.cStringIO(data_utils.random_bytes(size))
ivan-zhud1bbe5d2013-12-29 18:32:46 +0800298 name = 'New Standard Image %s' % name
David Kranz34f18782015-01-06 13:43:55 -0500299 image = cls.create_image(name=name,
300 container_format=container_format,
301 disk_format=disk_format,
302 is_public=False, data=image_file,
303 properties={'key1': 'value1'})
ivan-zhud1bbe5d2013-12-29 18:32:46 +0800304 image_id = image['id']
305 return image_id
306
Chris Hoge7579c1a2015-02-26 14:12:15 -0800307 @test.idempotent_id('01752c1c-0275-4de3-9e5b-876e44541928')
ivan-zhud1bbe5d2013-12-29 18:32:46 +0800308 def test_list_image_metadata(self):
309 # All metadata key/value pairs for an image should be returned
Ken'ichi Ohmichi01151e82016-06-10 11:19:52 -0700310 resp = self.client.check_image(self.image_id)
311 resp_metadata = common_image.get_image_meta_from_headers(resp)
ivan-zhud1bbe5d2013-12-29 18:32:46 +0800312 expected = {'key1': 'value1'}
313 self.assertEqual(expected, resp_metadata['properties'])
314
Chris Hoge7579c1a2015-02-26 14:12:15 -0800315 @test.idempotent_id('d6d7649c-08ce-440d-9ea7-e3dda552f33c')
ivan-zhud1bbe5d2013-12-29 18:32:46 +0800316 def test_update_image_metadata(self):
317 # The metadata for the image should match the updated values
318 req_metadata = {'key1': 'alt1', 'key2': 'value2'}
Ken'ichi Ohmichi01151e82016-06-10 11:19:52 -0700319 resp = self.client.check_image(self.image_id)
320 metadata = common_image.get_image_meta_from_headers(resp)
ivan-zhud1bbe5d2013-12-29 18:32:46 +0800321 self.assertEqual(metadata['properties'], {'key1': 'value1'})
322 metadata['properties'].update(req_metadata)
Ken'ichi Ohmichi02bcdf32016-06-17 16:41:26 -0700323 headers = common_image.image_meta_to_headers(
324 properties=metadata['properties'])
325 metadata = self.client.update_image(self.image_id,
326 headers=headers)['image']
ivan-zhud1bbe5d2013-12-29 18:32:46 +0800327
Ken'ichi Ohmichi01151e82016-06-10 11:19:52 -0700328 resp = self.client.check_image(self.image_id)
329 resp_metadata = common_image.get_image_meta_from_headers(resp)
ivan-zhud1bbe5d2013-12-29 18:32:46 +0800330 expected = {'key1': 'alt1', 'key2': 'value2'}
331 self.assertEqual(expected, resp_metadata['properties'])