1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
3
# Copyright 2011 Justin Santa Barbara
4
# Copyright 2012 OpenStack LLC
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
11
# http://www.apache.org/licenses/LICENSE-2.0
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
19
"""Implementation of a fake image service"""
24
from nova import exception
25
from nova import flags
26
import nova.image.glance
27
from nova.openstack.common import log as logging
28
from nova import utils
31
LOG = logging.getLogger(__name__)
37
class _FakeImageService(object):
38
"""Mock (fake) image service for unit testing."""
42
# NOTE(justinsb): The OpenStack API can't upload an image?
43
# So, make sure we've got one..
44
timestamp = datetime.datetime(2011, 01, 01, 01, 02, 03)
46
image1 = {'id': '155d900f-4e14-4e4c-a73d-069cbf4541e6',
47
'name': 'fakeimage123456',
48
'created_at': timestamp,
49
'updated_at': timestamp,
54
'container_format': 'raw',
56
'properties': {'kernel_id': FLAGS.null_kernel,
57
'ramdisk_id': FLAGS.null_kernel,
58
'architecture': 'x86_64'}}
60
image2 = {'id': 'a2459075-d96c-40d5-893e-577ff92e721c',
61
'name': 'fakeimage123456',
62
'created_at': timestamp,
63
'updated_at': timestamp,
68
'container_format': 'ami',
70
'properties': {'kernel_id': FLAGS.null_kernel,
71
'ramdisk_id': FLAGS.null_kernel}}
73
image3 = {'id': '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6',
74
'name': 'fakeimage123456',
75
'created_at': timestamp,
76
'updated_at': timestamp,
81
'container_format': None,
83
'properties': {'kernel_id': FLAGS.null_kernel,
84
'ramdisk_id': FLAGS.null_kernel}}
86
image4 = {'id': 'cedef40a-ed67-4d10-800e-17455edce175',
87
'name': 'fakeimage123456',
88
'created_at': timestamp,
89
'updated_at': timestamp,
94
'container_format': 'ami',
96
'properties': {'kernel_id': FLAGS.null_kernel,
97
'ramdisk_id': FLAGS.null_kernel}}
99
image5 = {'id': 'c905cedb-7281-47e4-8a62-f26bc5fc4c77',
100
'name': 'fakeimage123456',
101
'created_at': timestamp,
102
'updated_at': timestamp,
107
'container_format': 'ami',
108
'disk_format': 'ami',
109
'properties': {'kernel_id':
110
'155d900f-4e14-4e4c-a73d-069cbf4541e6',
113
image6 = {'id': 'a440c04b-79fa-479c-bed1-0b816eaec379',
114
'name': 'fakeimage6',
115
'created_at': timestamp,
116
'updated_at': timestamp,
121
'container_format': 'ova',
122
'disk_format': 'vhd',
123
'properties': {'kernel_id': FLAGS.null_kernel,
124
'ramdisk_id': FLAGS.null_kernel,
125
'architecture': 'x86_64',
126
'auto_disk_config': 'False'}}
128
image7 = {'id': '70a599e0-31e7-49b7-b260-868f441e862b',
129
'name': 'fakeimage7',
130
'created_at': timestamp,
131
'updated_at': timestamp,
136
'container_format': 'ova',
137
'disk_format': 'vhd',
138
'properties': {'kernel_id': FLAGS.null_kernel,
139
'ramdisk_id': FLAGS.null_kernel,
140
'architecture': 'x86_64',
141
'auto_disk_config': 'True'}}
143
self.create(None, image1)
144
self.create(None, image2)
145
self.create(None, image3)
146
self.create(None, image4)
147
self.create(None, image5)
148
self.create(None, image6)
149
self.create(None, image7)
151
super(_FakeImageService, self).__init__()
153
#TODO(bcwaldon): implement optional kwargs such as limit, sort_dir
154
def detail(self, context, **kwargs):
155
"""Return list of detailed image information."""
156
return copy.deepcopy(self.images.values())
158
def download(self, context, image_id, data):
159
self.show(context, image_id)
160
data.write(self._imagedata.get(image_id, ''))
162
def show(self, context, image_id):
163
"""Get data about specified image.
165
Returns a dict containing image data for the given opaque image id.
168
image = self.images.get(str(image_id))
170
return copy.deepcopy(image)
171
LOG.warn('Unable to find image id %s. Have images: %s',
172
image_id, self.images)
173
raise exception.ImageNotFound(image_id=image_id)
175
def create(self, context, metadata, data=None):
176
"""Store the image data and return the new image id.
178
:raises: Duplicate if the image already exist.
181
image_id = str(metadata.get('id', utils.gen_uuid()))
182
metadata['id'] = image_id
183
if image_id in self.images:
184
raise exception.Duplicate()
185
self.images[image_id] = copy.deepcopy(metadata)
187
self._imagedata[image_id] = data.read()
188
return self.images[image_id]
190
def update(self, context, image_id, metadata, data=None,
192
"""Replace the contents of the given image with the new data.
194
:raises: ImageNotFound if the image does not exist.
197
if not self.images.get(image_id):
198
raise exception.ImageNotFound(image_id=image_id)
200
purge = headers['x-glance-registry-purge-props']
204
self.images[image_id] = copy.deepcopy(metadata)
206
image = self.images[image_id]
208
image['properties'].update(metadata.pop('properties'))
211
image.update(metadata)
212
return self.images[image_id]
214
def delete(self, context, image_id):
215
"""Delete the given image.
217
:raises: ImageNotFound if the image does not exist.
220
removed = self.images.pop(image_id, None)
222
raise exception.ImageNotFound(image_id=image_id)
224
def delete_all(self):
225
"""Clears out all images."""
228
_fakeImageService = _FakeImageService()
231
def FakeImageService():
232
return _fakeImageService
235
def FakeImageService_reset():
236
global _fakeImageService
237
_fakeImageService = _FakeImageService()
240
def stub_out_image_service(stubs):
241
def fake_get_remote_image_service(context, image_href):
242
return (FakeImageService(), image_href)
243
stubs.Set(nova.image.glance, 'get_remote_image_service',
244
lambda x, y: (FakeImageService(), y))
245
stubs.Set(nova.image.glance, 'get_default_image_service',
246
lambda: FakeImageService())