Merge lp:~vishvananda/nova/fix-describe-images into lp:~hudson-openstack/nova/trunk
- fix-describe-images
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Devin Carlen |
Approved revision: | 934 |
Merged at revision: | 961 |
Proposed branch: | lp:~vishvananda/nova/fix-describe-images |
Merge into: | lp:~hudson-openstack/nova/trunk |
Diff against target: |
560 lines (+123/-122) 12 files modified
bin/nova-manage (+20/-20) nova/api/ec2/cloud.py (+38/-16) nova/api/openstack/servers.py (+1/-1) nova/image/fake.py (+3/-3) nova/image/glance.py (+4/-27) nova/image/local.py (+13/-3) nova/image/s3.py (+6/-36) nova/image/service.py (+27/-0) nova/tests/api/openstack/test_image_metadata.py (+0/-2) nova/tests/api/openstack/test_servers.py (+7/-9) nova/tests/image/test_glance.py (+4/-4) nova/virt/libvirt_conn.py (+0/-1) |
To merge this branch: | bzr merge lp:~vishvananda/nova/fix-describe-images |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Rick Harris (community) | Approve | ||
Brian Lamar (community) | Needs Information | ||
Devin Carlen (community) | Approve | ||
termie (community) | Needs Fixing | ||
Review via email: mp+55617@code.launchpad.net |
Commit message
Description of the change
Fixes issues with describe instances due to improperly set metadata.
* Removes image['
* Uses image['
* Defaults to 'ami' if container_format cannot be deduced. This allows
bare images to show up in describe instances and be launched even though they
are not officially in 'ami' format.
* Changes nova-manage register to set proper container format
* Fixes tests
* Fixes _do_get_
* Replaces 'owner_id' with 'project_id' since that is expected by glance code
* Moves the filtering scheme to base image service so all services filter the same way
Vish Ishaya (vishvananda) wrote : | # |
On Mar 30, 2011, at 1:41 PM, termie wrote:
> Review: Needs Fixing
> - _image_ec2_id's docstring needs punctuation.
Fixed.
> - image_register's docstring needs the closing quotes moved down a bit.
The docstrings in nova manage are displayed to the user, so they are all in this format. I'll go ahead and change this one, but it needs a whole-file cleanup.
>
> why did we change the argument order of image_register? is that method being tested anywhere? it seems like a possible compat issue so it'd be nice to know how far reaching it is
The old ordering made it impossible to register images with no kernel and ramdisk and a different format, because there isn't a way to pass "None" through nova-manage.
No other code is using this. It is user-facing. We don't have tests for nova-manage, and this is something that should be addressed, but I'm not sure that it is in the scope of this patch.
> --
> https:/
> You are the owner of lp:~vishvananda/nova/fix-describe-images.
Brian Lamar (blamar) wrote : | # |
I see the initialism 'AMI' being used in non-EC2-specific code (bin/nova-manage), is AMI being used here as an analogue for "some sort of machine image"? If so, is there any way to better indicate a generic machine image. Sometimes I look at the code and see abbreviations such as AMI/ARI/AKI and I assume we're talking about Amazon-specific images.
> (is_public == 'T')
Can this just be a boolean?
Vish Ishaya (vishvananda) wrote : | # |
> I see the initialism 'AMI' being used in non-EC2-specific code (bin/nova-
> manage), is AMI being used here as an analogue for "some sort of machine
> image"? If so, is there any way to better indicate a generic machine image.
> Sometimes I look at the code and see abbreviations such as AMI/ARI/AKI and I
> assume we're talking about Amazon-specific images.
AMI is supposed to only be used for images that have a separate kernel and ramdisk. Nova-manage sets the type to ami if you specify kernel and ramdisk. Otherwise it assumes a bare image.
To clients of the ec2 api, all images are displayed as ami's because there isn't really another image type shown there.
I hope that makes it clearer
>
> > (is_public == 'T')
nova-manage command line processing doesn't really support conversion to boolean, so this does the conversion to boolean from the text passed on the command line.
>
> Can this just be a boolean?
Rick Harris (rconradharris) wrote : | # |
Looks good, thanks Vish.
Devin Carlen (devcamcar) wrote : | # |
Looks like termie's concerns were addressed, so going to approve this.
OpenStack Infra (hudson-openstack) wrote : | # |
The attempt to merge lp:~vishvananda/nova/fix-describe-images into lp:nova failed. Below is the output from the failed tests.
AccountsTest
test_
test_
test_
test_
AdminAPITest
test_
test_
APITest
test_
Test
test_
test_
test_bad_token OK
test_
test_
test_no_user OK
test_
TestFunctional
test_
test_
TestLimiter
test_
LimiterTest
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
ActionExtensionTest
test_
test_
test_
ExtensionContro
test_
test_index OK
ExtensionManage
test_
ResourceExtensi
test_
test_
test_
ResponseExtensi
test_
test_
TestFaults
test_
test_
- 933. By Vish Ishaya
-
merged trunk
- 934. By Vish Ishaya
-
fix tests from moving access check into update and delete
Vish Ishaya (vishvananda) wrote : | # |
My bad, forgot to update tests on my last change. Should be working now.
On Apr 7, 2011, at 3:38 PM, OpenStack Hudson wrote:
> The proposal to merge lp:~vishvananda/nova/fix-describe-images into lp:nova has been updated.
>
> Status: Approved => Needs review
>
> For more details, see:
> https:/
> --
> https:/
> You are the owner of lp:~vishvananda/nova/fix-describe-images.
Preview Diff
1 | === modified file 'bin/nova-manage' |
2 | --- bin/nova-manage 2011-04-04 20:17:04 +0000 |
3 | +++ bin/nova-manage 2011-04-07 23:45:54 +0000 |
4 | @@ -894,20 +894,17 @@ |
5 | def __init__(self, *args, **kwargs): |
6 | self.image_service = utils.import_object(FLAGS.image_service) |
7 | |
8 | - def _register(self, image_type, disk_format, container_format, |
9 | + def _register(self, container_format, disk_format, |
10 | path, owner, name=None, is_public='T', |
11 | architecture='x86_64', kernel_id=None, ramdisk_id=None): |
12 | - meta = {'is_public': True, |
13 | + meta = {'is_public': (is_public == 'T'), |
14 | 'name': name, |
15 | + 'container_format': container_format, |
16 | 'disk_format': disk_format, |
17 | - 'container_format': container_format, |
18 | 'properties': {'image_state': 'available', |
19 | - 'owner_id': owner, |
20 | - 'type': image_type, |
21 | + 'project_id': owner, |
22 | 'architecture': architecture, |
23 | - 'image_location': 'local', |
24 | - 'is_public': (is_public == 'T')}} |
25 | - print image_type, meta |
26 | + 'image_location': 'local'}} |
27 | if kernel_id: |
28 | meta['properties']['kernel_id'] = int(kernel_id) |
29 | if ramdisk_id: |
30 | @@ -932,16 +929,18 @@ |
31 | ramdisk_id = self.ramdisk_register(ramdisk, owner, None, |
32 | is_public, architecture) |
33 | self.image_register(image, owner, name, is_public, |
34 | - architecture, kernel_id, ramdisk_id) |
35 | + architecture, 'ami', 'ami', |
36 | + kernel_id, ramdisk_id) |
37 | |
38 | def image_register(self, path, owner, name=None, is_public='T', |
39 | - architecture='x86_64', kernel_id=None, ramdisk_id=None, |
40 | - disk_format='ami', container_format='ami'): |
41 | + architecture='x86_64', container_format='bare', |
42 | + disk_format='raw', kernel_id=None, ramdisk_id=None): |
43 | """Uploads an image into the image_service |
44 | arguments: path owner [name] [is_public='T'] [architecture='x86_64'] |
45 | + [container_format='bare'] [disk_format='raw'] |
46 | [kernel_id=None] [ramdisk_id=None] |
47 | - [disk_format='ami'] [container_format='ami']""" |
48 | - return self._register('machine', disk_format, container_format, path, |
49 | + """ |
50 | + return self._register(container_format, disk_format, path, |
51 | owner, name, is_public, architecture, |
52 | kernel_id, ramdisk_id) |
53 | |
54 | @@ -950,7 +949,7 @@ |
55 | """Uploads a kernel into the image_service |
56 | arguments: path owner [name] [is_public='T'] [architecture='x86_64'] |
57 | """ |
58 | - return self._register('kernel', 'aki', 'aki', path, owner, name, |
59 | + return self._register('aki', 'aki', path, owner, name, |
60 | is_public, architecture) |
61 | |
62 | def ramdisk_register(self, path, owner, name=None, is_public='T', |
63 | @@ -958,7 +957,7 @@ |
64 | """Uploads a ramdisk into the image_service |
65 | arguments: path owner [name] [is_public='T'] [architecture='x86_64'] |
66 | """ |
67 | - return self._register('ramdisk', 'ari', 'ari', path, owner, name, |
68 | + return self._register('ari', 'ari', path, owner, name, |
69 | is_public, architecture) |
70 | |
71 | def _lookup(self, old_image_id): |
72 | @@ -975,16 +974,17 @@ |
73 | 'ramdisk': 'ari'} |
74 | container_format = mapping[old['type']] |
75 | disk_format = container_format |
76 | + if container_format == 'ami' and not old.get('kernelId'): |
77 | + container_format = 'bare' |
78 | + disk_format = 'raw' |
79 | new = {'disk_format': disk_format, |
80 | 'container_format': container_format, |
81 | - 'is_public': True, |
82 | + 'is_public': old['isPublic'], |
83 | 'name': old['imageId'], |
84 | 'properties': {'image_state': old['imageState'], |
85 | - 'owner_id': old['imageOwnerId'], |
86 | + 'project_id': old['imageOwnerId'], |
87 | 'architecture': old['architecture'], |
88 | - 'type': old['type'], |
89 | - 'image_location': old['imageLocation'], |
90 | - 'is_public': old['isPublic']}} |
91 | + 'image_location': old['imageLocation']}} |
92 | if old.get('kernelId'): |
93 | new['properties']['kernel_id'] = self._lookup(old['kernelId']) |
94 | if old.get('ramdiskId'): |
95 | |
96 | === modified file 'nova/api/ec2/cloud.py' |
97 | --- nova/api/ec2/cloud.py 2011-04-07 19:52:14 +0000 |
98 | +++ nova/api/ec2/cloud.py 2011-04-07 23:45:54 +0000 |
99 | @@ -154,7 +154,7 @@ |
100 | floating_ip = db.instance_get_floating_address(ctxt, |
101 | instance_ref['id']) |
102 | ec2_id = ec2utils.id_to_ec2_id(instance_ref['id']) |
103 | - image_ec2_id = self._image_ec2_id(instance_ref['image_id'], 'machine') |
104 | + image_ec2_id = self._image_ec2_id(instance_ref['image_id'], 'ami') |
105 | data = { |
106 | 'user-data': base64.b64decode(instance_ref['user_data']), |
107 | 'meta-data': { |
108 | @@ -184,7 +184,7 @@ |
109 | for image_type in ['kernel', 'ramdisk']: |
110 | if '%s_id' % image_type in instance_ref: |
111 | ec2_id = self._image_ec2_id(instance_ref['%s_id' % image_type], |
112 | - image_type) |
113 | + self._image_type(image_type)) |
114 | data['meta-data']['%s-id' % image_type] = ec2_id |
115 | |
116 | if False: # TODO(vish): store ancestor ids |
117 | @@ -875,13 +875,27 @@ |
118 | self.compute_api.update(context, instance_id=instance_id, **kwargs) |
119 | return True |
120 | |
121 | - _type_prefix_map = {'machine': 'ami', |
122 | - 'kernel': 'aki', |
123 | - 'ramdisk': 'ari'} |
124 | - |
125 | - def _image_ec2_id(self, image_id, image_type='machine'): |
126 | - prefix = self._type_prefix_map[image_type] |
127 | - template = prefix + '-%08x' |
128 | + @staticmethod |
129 | + def _image_type(image_type): |
130 | + """Converts to a three letter image type. |
131 | + |
132 | + aki, kernel => aki |
133 | + ari, ramdisk => ari |
134 | + anything else => ami |
135 | + |
136 | + """ |
137 | + if image_type == 'kernel': |
138 | + return 'aki' |
139 | + if image_type == 'ramdisk': |
140 | + return 'ari' |
141 | + if image_type not in ['aki', 'ari']: |
142 | + return 'ami' |
143 | + return image_type |
144 | + |
145 | + @staticmethod |
146 | + def _image_ec2_id(image_id, image_type='ami'): |
147 | + """Returns image ec2_id using id and three letter type.""" |
148 | + template = image_type + '-%08x' |
149 | return ec2utils.id_to_ec2_id(int(image_id), template=template) |
150 | |
151 | def _get_image(self, context, ec2_id): |
152 | @@ -894,27 +908,34 @@ |
153 | def _format_image(self, image): |
154 | """Convert from format defined by BaseImageService to S3 format.""" |
155 | i = {} |
156 | - image_type = image['properties'].get('type') |
157 | + image_type = self._image_type(image.get('container_format')) |
158 | ec2_id = self._image_ec2_id(image.get('id'), image_type) |
159 | name = image.get('name') |
160 | i['imageId'] = ec2_id |
161 | kernel_id = image['properties'].get('kernel_id') |
162 | if kernel_id: |
163 | - i['kernelId'] = self._image_ec2_id(kernel_id, 'kernel') |
164 | + i['kernelId'] = self._image_ec2_id(kernel_id, 'aki') |
165 | ramdisk_id = image['properties'].get('ramdisk_id') |
166 | if ramdisk_id: |
167 | - i['ramdiskId'] = self._image_ec2_id(ramdisk_id, 'ramdisk') |
168 | + i['ramdiskId'] = self._image_ec2_id(ramdisk_id, 'ari') |
169 | i['imageOwnerId'] = image['properties'].get('owner_id') |
170 | if name: |
171 | i['imageLocation'] = "%s (%s)" % (image['properties']. |
172 | get('image_location'), name) |
173 | else: |
174 | i['imageLocation'] = image['properties'].get('image_location') |
175 | - i['imageState'] = image['properties'].get('image_state') |
176 | + # NOTE(vish): fallback status if image_state isn't set |
177 | + state = image.get('status') |
178 | + if state == 'active': |
179 | + state = 'available' |
180 | + i['imageState'] = image['properties'].get('image_state', state) |
181 | i['displayName'] = name |
182 | i['description'] = image.get('description') |
183 | - i['imageType'] = image_type |
184 | - i['isPublic'] = str(image['properties'].get('is_public', '')) == 'True' |
185 | + display_mapping = {'aki': 'kernel', |
186 | + 'ari': 'ramdisk', |
187 | + 'ami': 'machine'} |
188 | + i['imageType'] = display_mapping.get(image_type) |
189 | + i['isPublic'] = image.get('is_public') == True |
190 | i['architecture'] = image['properties'].get('architecture') |
191 | return i |
192 | |
193 | @@ -946,8 +967,9 @@ |
194 | image_location = kwargs['name'] |
195 | metadata = {'properties': {'image_location': image_location}} |
196 | image = self.image_service.create(context, metadata) |
197 | + image_type = self._image_type(image.get('container_format')) |
198 | image_id = self._image_ec2_id(image['id'], |
199 | - image['properties']['type']) |
200 | + image_type) |
201 | msg = _("Registered image %(image_location)s with" |
202 | " id %(image_id)s") % locals() |
203 | LOG.audit(msg, context=context) |
204 | |
205 | === modified file 'nova/api/openstack/servers.py' |
206 | --- nova/api/openstack/servers.py 2011-04-07 23:04:43 +0000 |
207 | +++ nova/api/openstack/servers.py 2011-04-07 23:45:54 +0000 |
208 | @@ -565,7 +565,7 @@ |
209 | _("Cannot build from image %(image_id)s, status not active") % |
210 | locals()) |
211 | |
212 | - if image_meta['properties']['disk_format'] != 'ami': |
213 | + if image_meta.get('container_format') != 'ami': |
214 | return None, None |
215 | |
216 | try: |
217 | |
218 | === modified file 'nova/image/fake.py' |
219 | --- nova/image/fake.py 2011-03-30 02:11:12 +0000 |
220 | +++ nova/image/fake.py 2011-04-07 23:45:54 +0000 |
221 | @@ -44,10 +44,10 @@ |
222 | 'created_at': timestamp, |
223 | 'updated_at': timestamp, |
224 | 'status': 'active', |
225 | - 'type': 'machine', |
226 | + 'container_format': 'ami', |
227 | + 'disk_format': 'raw', |
228 | 'properties': {'kernel_id': FLAGS.null_kernel, |
229 | - 'ramdisk_id': FLAGS.null_kernel, |
230 | - 'disk_format': 'ami'} |
231 | + 'ramdisk_id': FLAGS.null_kernel} |
232 | } |
233 | self.create(None, image) |
234 | super(FakeImageService, self).__init__() |
235 | |
236 | === modified file 'nova/image/glance.py' |
237 | --- nova/image/glance.py 2011-03-29 16:06:52 +0000 |
238 | +++ nova/image/glance.py 2011-04-07 23:45:54 +0000 |
239 | @@ -151,6 +151,8 @@ |
240 | |
241 | :raises NotFound if the image does not exist. |
242 | """ |
243 | + # NOTE(vish): show is to check if image is available |
244 | + self.show(context, image_id) |
245 | try: |
246 | image_meta = self.client.update_image(image_id, image_meta, data) |
247 | except glance_exception.NotFound: |
248 | @@ -165,6 +167,8 @@ |
249 | |
250 | :raises NotFound if the image does not exist. |
251 | """ |
252 | + # NOTE(vish): show is to check if image is available |
253 | + self.show(context, image_id) |
254 | try: |
255 | result = self.client.delete_image(image_id) |
256 | except glance_exception.NotFound: |
257 | @@ -186,33 +190,6 @@ |
258 | image_meta = _convert_timestamps_to_datetimes(image_meta) |
259 | return image_meta |
260 | |
261 | - @staticmethod |
262 | - def _is_image_available(context, image_meta): |
263 | - """ |
264 | - Images are always available if they are public or if the user is an |
265 | - admin. |
266 | - |
267 | - Otherwise, we filter by project_id (if present) and then fall-back to |
268 | - images owned by user. |
269 | - """ |
270 | - # FIXME(sirp): We should be filtering by user_id on the Glance side |
271 | - # for security; however, we can't do that until we get authn/authz |
272 | - # sorted out. Until then, filtering in Nova. |
273 | - if image_meta['is_public'] or context.is_admin: |
274 | - return True |
275 | - |
276 | - properties = image_meta['properties'] |
277 | - |
278 | - if context.project_id and ('project_id' in properties): |
279 | - return str(properties['project_id']) == str(project_id) |
280 | - |
281 | - try: |
282 | - user_id = properties['user_id'] |
283 | - except KeyError: |
284 | - return False |
285 | - |
286 | - return str(user_id) == str(context.user_id) |
287 | - |
288 | |
289 | # utility functions |
290 | def _convert_timestamps_to_datetimes(image_meta): |
291 | |
292 | === modified file 'nova/image/local.py' |
293 | --- nova/image/local.py 2011-03-23 05:50:53 +0000 |
294 | +++ nova/image/local.py 2011-04-07 23:45:54 +0000 |
295 | @@ -84,7 +84,10 @@ |
296 | def show(self, context, image_id): |
297 | try: |
298 | with open(self._path_to(image_id)) as metadata_file: |
299 | - return json.load(metadata_file) |
300 | + image_meta = json.load(metadata_file) |
301 | + if not self._is_image_available(context, image_meta): |
302 | + raise exception.NotFound |
303 | + return image_meta |
304 | except (IOError, ValueError): |
305 | raise exception.NotFound |
306 | |
307 | @@ -119,10 +122,15 @@ |
308 | image_path = self._path_to(image_id, None) |
309 | if not os.path.exists(image_path): |
310 | os.mkdir(image_path) |
311 | - return self.update(context, image_id, metadata, data) |
312 | + return self._store(context, image_id, metadata, data) |
313 | |
314 | def update(self, context, image_id, metadata, data=None): |
315 | """Replace the contents of the given image with the new data.""" |
316 | + # NOTE(vish): show is to check if image is available |
317 | + self.show(context, image_id) |
318 | + return self._store(context, image_id, metadata, data) |
319 | + |
320 | + def _store(self, context, image_id, metadata, data=None): |
321 | metadata['id'] = image_id |
322 | try: |
323 | if data: |
324 | @@ -140,9 +148,11 @@ |
325 | |
326 | def delete(self, context, image_id): |
327 | """Delete the given image. |
328 | - Raises OSError if the image does not exist. |
329 | + Raises NotFound if the image does not exist. |
330 | |
331 | """ |
332 | + # NOTE(vish): show is to check if image is available |
333 | + self.show(context, image_id) |
334 | try: |
335 | shutil.rmtree(self._path_to(image_id, None)) |
336 | except (IOError, ValueError): |
337 | |
338 | === modified file 'nova/image/s3.py' |
339 | --- nova/image/s3.py 2011-03-30 00:23:09 +0000 |
340 | +++ nova/image/s3.py 2011-04-07 23:45:54 +0000 |
341 | @@ -46,6 +46,7 @@ |
342 | |
343 | |
344 | class S3ImageService(service.BaseImageService): |
345 | + """Wraps an existing image service to support s3 based register""" |
346 | def __init__(self, service=None, *args, **kwargs): |
347 | if service == None: |
348 | service = utils.import_object(FLAGS.image_service) |
349 | @@ -58,52 +59,23 @@ |
350 | return image |
351 | |
352 | def delete(self, context, image_id): |
353 | - # FIXME(vish): call to show is to check filter |
354 | - self.show(context, image_id) |
355 | self.service.delete(context, image_id) |
356 | |
357 | def update(self, context, image_id, metadata, data=None): |
358 | - # FIXME(vish): call to show is to check filter |
359 | - self.show(context, image_id) |
360 | image = self.service.update(context, image_id, metadata, data) |
361 | return image |
362 | |
363 | def index(self, context): |
364 | - images = self.service.index(context) |
365 | - # FIXME(vish): index doesn't filter so we do it manually |
366 | - return self._filter(context, images) |
367 | + return self.service.index(context) |
368 | |
369 | def detail(self, context): |
370 | - images = self.service.detail(context) |
371 | - # FIXME(vish): detail doesn't filter so we do it manually |
372 | - return self._filter(context, images) |
373 | - |
374 | - @classmethod |
375 | - def _is_visible(cls, context, image): |
376 | - return (context.is_admin |
377 | - or context.project_id == image['properties']['owner_id'] |
378 | - or image['properties']['is_public'] == 'True') |
379 | - |
380 | - @classmethod |
381 | - def _filter(cls, context, images): |
382 | - filtered = [] |
383 | - for image in images: |
384 | - if not cls._is_visible(context, image): |
385 | - continue |
386 | - filtered.append(image) |
387 | - return filtered |
388 | + return self.service.detail(context) |
389 | |
390 | def show(self, context, image_id): |
391 | - image = self.service.show(context, image_id) |
392 | - if not self._is_visible(context, image): |
393 | - raise exception.NotFound |
394 | - return image |
395 | + return self.service.show(context, image_id) |
396 | |
397 | def show_by_name(self, context, name): |
398 | - image = self.service.show_by_name(context, name) |
399 | - if not self._is_visible(context, image): |
400 | - raise exception.NotFound |
401 | - return image |
402 | + return self.service.show(context, name) |
403 | |
404 | @staticmethod |
405 | def _conn(context): |
406 | @@ -167,7 +139,7 @@ |
407 | arch = 'x86_64' |
408 | |
409 | properties = metadata['properties'] |
410 | - properties['owner_id'] = context.project_id |
411 | + properties['project_id'] = context.project_id |
412 | properties['architecture'] = arch |
413 | |
414 | if kernel_id: |
415 | @@ -176,8 +148,6 @@ |
416 | if ramdisk_id: |
417 | properties['ramdisk_id'] = ec2utils.ec2_id_to_id(ramdisk_id) |
418 | |
419 | - properties['is_public'] = False |
420 | - properties['type'] = image_type |
421 | metadata.update({'disk_format': image_format, |
422 | 'container_format': image_format, |
423 | 'status': 'queued', |
424 | |
425 | === modified file 'nova/image/service.py' |
426 | --- nova/image/service.py 2011-03-24 21:13:55 +0000 |
427 | +++ nova/image/service.py 2011-04-07 23:45:54 +0000 |
428 | @@ -136,6 +136,33 @@ |
429 | """ |
430 | raise NotImplementedError |
431 | |
432 | + @staticmethod |
433 | + def _is_image_available(context, image_meta): |
434 | + """ |
435 | + Images are always available if they are public or if the user is an |
436 | + admin. |
437 | + |
438 | + Otherwise, we filter by project_id (if present) and then fall-back to |
439 | + images owned by user. |
440 | + """ |
441 | + # FIXME(sirp): We should be filtering by user_id on the Glance side |
442 | + # for security; however, we can't do that until we get authn/authz |
443 | + # sorted out. Until then, filtering in Nova. |
444 | + if image_meta['is_public'] or context.is_admin: |
445 | + return True |
446 | + |
447 | + properties = image_meta['properties'] |
448 | + |
449 | + if context.project_id and ('project_id' in properties): |
450 | + return str(properties['project_id']) == str(context.project_id) |
451 | + |
452 | + try: |
453 | + user_id = properties['user_id'] |
454 | + except KeyError: |
455 | + return False |
456 | + |
457 | + return str(user_id) == str(context.user_id) |
458 | + |
459 | @classmethod |
460 | def _translate_to_base(cls, metadata): |
461 | """Return a metadata dictionary that is BaseImageService compliant. |
462 | |
463 | === modified file 'nova/tests/api/openstack/test_image_metadata.py' |
464 | --- nova/tests/api/openstack/test_image_metadata.py 2011-03-25 13:28:36 +0000 |
465 | +++ nova/tests/api/openstack/test_image_metadata.py 2011-04-07 23:45:54 +0000 |
466 | @@ -45,7 +45,6 @@ |
467 | 'is_public': True, |
468 | 'deleted_at': None, |
469 | 'properties': { |
470 | - 'type': 'ramdisk', |
471 | 'key1': 'value1', |
472 | 'key2': 'value2' |
473 | }, |
474 | @@ -62,7 +61,6 @@ |
475 | 'is_public': True, |
476 | 'deleted_at': None, |
477 | 'properties': { |
478 | - 'type': 'ramdisk', |
479 | 'key1': 'value1', |
480 | 'key2': 'value2' |
481 | }, |
482 | |
483 | === modified file 'nova/tests/api/openstack/test_servers.py' |
484 | --- nova/tests/api/openstack/test_servers.py 2011-04-07 23:04:43 +0000 |
485 | +++ nova/tests/api/openstack/test_servers.py 2011-04-07 23:45:54 +0000 |
486 | @@ -1643,29 +1643,27 @@ |
487 | |
488 | def test_not_ami(self): |
489 | """Anything other than ami should return no kernel and no ramdisk""" |
490 | - image_meta = {'id': 1, 'status': 'active', |
491 | - 'properties': {'disk_format': 'vhd'}} |
492 | + image_meta = {'id': 1, 'status': 'active', 'container_format': 'vhd'} |
493 | kernel_id, ramdisk_id = self._get_k_r(image_meta) |
494 | self.assertEqual(kernel_id, None) |
495 | self.assertEqual(ramdisk_id, None) |
496 | |
497 | def test_ami_no_kernel(self): |
498 | """If an ami is missing a kernel it should raise NotFound""" |
499 | - image_meta = {'id': 1, 'status': 'active', |
500 | - 'properties': {'disk_format': 'ami', 'ramdisk_id': 1}} |
501 | + image_meta = {'id': 1, 'status': 'active', 'container_format': 'ami', |
502 | + 'properties': {'ramdisk_id': 1}} |
503 | self.assertRaises(exception.NotFound, self._get_k_r, image_meta) |
504 | |
505 | def test_ami_no_ramdisk(self): |
506 | """If an ami is missing a ramdisk it should raise NotFound""" |
507 | - image_meta = {'id': 1, 'status': 'active', |
508 | - 'properties': {'disk_format': 'ami', 'kernel_id': 1}} |
509 | + image_meta = {'id': 1, 'status': 'active', 'container_format': 'ami', |
510 | + 'properties': {'kernel_id': 1}} |
511 | self.assertRaises(exception.NotFound, self._get_k_r, image_meta) |
512 | |
513 | def test_ami_kernel_ramdisk_present(self): |
514 | """Return IDs if both kernel and ramdisk are present""" |
515 | - image_meta = {'id': 1, 'status': 'active', |
516 | - 'properties': {'disk_format': 'ami', 'kernel_id': 1, |
517 | - 'ramdisk_id': 2}} |
518 | + image_meta = {'id': 1, 'status': 'active', 'container_format': 'ami', |
519 | + 'properties': {'kernel_id': 1, 'ramdisk_id': 2}} |
520 | kernel_id, ramdisk_id = self._get_k_r(image_meta) |
521 | self.assertEqual(kernel_id, 1) |
522 | self.assertEqual(ramdisk_id, 2) |
523 | |
524 | === modified file 'nova/tests/image/test_glance.py' |
525 | --- nova/tests/image/test_glance.py 2011-03-28 17:47:18 +0000 |
526 | +++ nova/tests/image/test_glance.py 2011-04-07 23:45:54 +0000 |
527 | @@ -209,17 +209,17 @@ |
528 | self.assertDateTimesEmpty(image_meta) |
529 | |
530 | def test_update_handles_datetimes(self): |
531 | + self.client.images = {'image1': self._make_datetime_fixture()} |
532 | self.client.update_response = self._make_datetime_fixture() |
533 | - dummy_id = 'dummy_id' |
534 | dummy_meta = {} |
535 | - image_meta = self.service.update(self.context, 'dummy_id', dummy_meta) |
536 | + image_meta = self.service.update(self.context, 'image1', dummy_meta) |
537 | self.assertDateTimesFilled(image_meta) |
538 | |
539 | def test_update_handles_none_datetimes(self): |
540 | + self.client.images = {'image1': self._make_datetime_fixture()} |
541 | self.client.update_response = self._make_none_datetime_fixture() |
542 | - dummy_id = 'dummy_id' |
543 | dummy_meta = {} |
544 | - image_meta = self.service.update(self.context, 'dummy_id', dummy_meta) |
545 | + image_meta = self.service.update(self.context, 'image1', dummy_meta) |
546 | self.assertDateTimesEmpty(image_meta) |
547 | |
548 | def _make_datetime_fixture(self): |
549 | |
550 | === modified file 'nova/virt/libvirt_conn.py' |
551 | --- nova/virt/libvirt_conn.py 2011-04-07 21:48:29 +0000 |
552 | +++ nova/virt/libvirt_conn.py 2011-04-07 23:45:54 +0000 |
553 | @@ -424,7 +424,6 @@ |
554 | 'container_format': base['container_format'], |
555 | 'is_public': False, |
556 | 'properties': {'architecture': base['architecture'], |
557 | - 'type': base['type'], |
558 | 'name': '%s.%s' % (base['name'], image_id), |
559 | 'kernel_id': instance['kernel_id'], |
560 | 'image_location': 'snapshot', |
- _image_ec2_id's docstring needs punctuation.
- image_register's docstring needs the closing quotes moved down a bit.
why did we change the argument order of image_register? is that method being tested anywhere? it seems like a possible compat issue so it'd be nice to know how far reaching it is