Statistics
| Branch: | Tag: | Revision:

root / api / images.py @ f533f224

History | View | Annotate | Download (9.7 kB)

1
#
2
# Copyright (c) 2010 Greek Research and Technology Network
3
#
4

    
5
from django.conf.urls.defaults import patterns
6
from django.http import HttpResponse
7
from django.template.loader import render_to_string
8
from django.utils import simplejson as json
9

    
10
from synnefo.api import util
11
from synnefo.api.common import method_not_allowed
12
from synnefo.api.faults import BadRequest
13
from synnefo.db.models import Image, ImageMetadata
14

    
15

    
16
urlpatterns = patterns('synnefo.api.images',
17
    (r'^(?:/|.json|.xml)?$', 'demux'),
18
    (r'^/detail(?:.json|.xml)?$', 'list_images', {'detail': True}),
19
    (r'^/(\d+)(?:.json|.xml)?$', 'image_demux'),
20
    (r'^/(\d+)/meta(?:.json|.xml)?$', 'metadata_demux'),
21
    (r'^/(\d+)/meta/(.+?)(?:.json|.xml)?$', 'metadata_item_demux'),
22
)
23

    
24
def demux(request):
25
    if request.method == 'GET':
26
        return list_images(request)
27
    elif request.method == 'POST':
28
        return create_image(request)
29
    else:
30
        return method_not_allowed(request)
31

    
32
def image_demux(request, image_id):
33
    if request.method == 'GET':
34
        return get_image_details(request, image_id)
35
    elif request.method == 'DELETE':
36
        return delete_image(request, image_id)
37
    else:
38
        return method_not_allowed(request)
39

    
40
def metadata_demux(request, image_id):
41
    if request.method == 'GET':
42
        return list_metadata(request, image_id)
43
    elif request.method == 'POST':
44
        return update_metadata(request, image_id)
45
    else:
46
        return method_not_allowed(request)
47

    
48
def metadata_item_demux(request, image_id, key):
49
    if request.method == 'GET':
50
        return get_metadata_item(request, image_id, key)
51
    elif request.method == 'PUT':
52
        return create_metadata_item(request, image_id, key)
53
    elif request.method == 'DELETE':
54
        return delete_metadata_item(request, image_id, key)
55
    else:
56
        return method_not_allowed(request)
57

    
58

    
59
def image_to_dict(image, detail=True):
60
    d = {'id': image.id, 'name': image.name}
61
    if detail:
62
        d['updated'] = util.isoformat(image.updated)
63
        d['created'] = util.isoformat(image.created)
64
        d['status'] = image.state
65
        d['progress'] = 100 if image.state == 'ACTIVE' else 0
66
        if image.sourcevm:
67
            d['serverRef'] = image.sourcevm.id
68

    
69
        metadata = {}
70
        for meta in ImageMetadata.objects.filter(image=image):
71
            metadata[meta.meta_key] = meta.meta_value
72

    
73
        if metadata:
74
            d['metadata'] = {'values': metadata}
75

    
76
    return d
77

    
78
def metadata_to_dict(image):
79
    image_meta = image.imagemetadata_set.all()
80
    return dict((meta.meta_key, meta.meta_value) for meta in image_meta)
81

    
82

    
83
@util.api_method('GET')
84
def list_images(request, detail=False):
85
    # Normal Response Codes: 200, 203
86
    # Error Response Codes: computeFault (400, 500),
87
    #                       serviceUnavailable (503),
88
    #                       unauthorized (401),
89
    #                       badRequest (400),
90
    #                       overLimit (413)
91

    
92
    since = util.isoparse(request.GET.get('changes-since'))
93

    
94
    if since:
95
        avail_images = Image.objects.filter(owner=request.user,
96
                                            updated__gte=since)
97
        if not avail_images:
98
            return HttpResponse(status=304)
99
    else:
100
        avail_images = Image.objects.filter(owner=request.user)
101

    
102
    images = [image_to_dict(image, detail) for image in avail_images]
103

    
104
    if request.serialization == 'xml':
105
        data = render_to_string('list_images.xml', {
106
            'images': images,
107
            'detail': detail})
108
    else:
109
        data = json.dumps({'images': {'values': images}})
110

    
111
    return HttpResponse(data, status=200)
112

    
113
@util.api_method('POST')
114
def create_image(request):
115
    # Normal Response Code: 202
116
    # Error Response Codes: computeFault (400, 500),
117
    #                       serviceUnavailable (503),
118
    #                       unauthorized (401),
119
    #                       badMediaType(415),
120
    #                       itemNotFound (404),
121
    #                       badRequest (400),
122
    #                       serverCapacityUnavailable (503),
123
    #                       buildInProgress (409),
124
    #                       resizeNotAllowed (403),
125
    #                       backupOrResizeInProgress (409),
126
    #                       overLimit (413)
127

    
128
    req = util.get_request_dict(request)
129

    
130
    try:
131
        d = req['image']
132
        server_id = d['serverRef']
133
        name = d['name']
134
    except (KeyError, ValueError):
135
        raise BadRequest('Malformed request.')
136

    
137
    owner = request.user
138
    vm = util.get_vm(server_id, owner)
139
    image = Image.objects.create(name=name, owner=owner, sourcevm=vm)
140

    
141
    imagedict = image_to_dict(image)
142
    if request.serialization == 'xml':
143
        data = render_to_string('image.xml', {'image': imagedict})
144
    else:
145
        data = json.dumps({'image': imagedict})
146

    
147
    return HttpResponse(data, status=202)
148

    
149
@util.api_method('GET')
150
def get_image_details(request, image_id):
151
    # Normal Response Codes: 200, 203
152
    # Error Response Codes: computeFault (400, 500),
153
    #                       serviceUnavailable (503),
154
    #                       unauthorized (401),
155
    #                       badRequest (400),
156
    #                       itemNotFound (404),
157
    #                       overLimit (413)
158

    
159
    image = util.get_image(image_id, request.user)
160
    imagedict = image_to_dict(image)
161

    
162
    if request.serialization == 'xml':
163
        data = render_to_string('image.xml', {'image': imagedict})
164
    else:
165
        data = json.dumps({'image': imagedict})
166

    
167
    return HttpResponse(data, status=200)
168

    
169
@util.api_method('DELETE')
170
def delete_image(request, image_id):
171
    # Normal Response Code: 204
172
    # Error Response Codes: computeFault (400, 500),
173
    #                       serviceUnavailable (503),
174
    #                       unauthorized (401),
175
    #                       itemNotFound (404),
176
    #                       overLimit (413)
177

    
178
    image = util.get_image(image_id, request.user)
179
    image.delete()
180
    return HttpResponse(status=204)
181

    
182
@util.api_method('GET')
183
def list_metadata(request, image_id):
184
    # Normal Response Codes: 200, 203
185
    # Error Response Codes: computeFault (400, 500),
186
    #                       serviceUnavailable (503),
187
    #                       unauthorized (401),
188
    #                       badRequest (400),
189
    #                       overLimit (413)
190

    
191
    image = util.get_image(image_id, request.user)
192
    metadata = metadata_to_dict(image)
193
    return util.render_metadata(request, metadata, use_values=True, status=200)
194

    
195
@util.api_method('POST')
196
def update_metadata(request, image_id):
197
    # Normal Response Code: 201
198
    # Error Response Codes: computeFault (400, 500),
199
    #                       serviceUnavailable (503),
200
    #                       unauthorized (401),
201
    #                       badRequest (400),
202
    #                       buildInProgress (409),
203
    #                       badMediaType(415),
204
    #                       overLimit (413)
205

    
206
    image = util.get_image(image_id, request.user)
207
    req = util.get_request_dict(request)
208
    try:
209
        metadata = req['metadata']
210
        assert isinstance(metadata, dict)
211
    except (KeyError, AssertionError):
212
        raise BadRequest('Malformed request.')
213

    
214
    updated = {}
215

    
216
    for key, val in metadata.items():
217
        try:
218
            meta = ImageMetadata.objects.get(meta_key=key, image=image)
219
            meta.meta_value = val
220
            meta.save()
221
            updated[key] = val
222
        except ImageMetadata.DoesNotExist:
223
            pass    # Ignore non-existent metadata
224
    
225
    if updated:
226
        image.save()
227
    
228
    return util.render_metadata(request, updated, status=201)
229

    
230
@util.api_method('GET')
231
def get_metadata_item(request, image_id, key):
232
    # Normal Response Codes: 200, 203
233
    # Error Response Codes: computeFault (400, 500),
234
    #                       serviceUnavailable (503),
235
    #                       unauthorized (401),
236
    #                       itemNotFound (404),
237
    #                       badRequest (400),
238
    #                       overLimit (413)
239

    
240
    image = util.get_image(image_id, request.user)
241
    meta = util.get_image_meta(image, key)
242
    return util.render_meta(request, meta, status=200)
243

    
244
@util.api_method('PUT')
245
def create_metadata_item(request, image_id, key):
246
    # Normal Response Code: 201
247
    # Error Response Codes: computeFault (400, 500),
248
    #                       serviceUnavailable (503),
249
    #                       unauthorized (401),
250
    #                       itemNotFound (404),
251
    #                       badRequest (400),
252
    #                       buildInProgress (409),
253
    #                       badMediaType(415),
254
    #                       overLimit (413)
255

    
256
    image = util.get_image(image_id, request.user)
257
    req = util.get_request_dict(request)
258
    try:
259
        metadict = req['meta']
260
        assert isinstance(metadict, dict)
261
        assert len(metadict) == 1
262
        assert key in metadict
263
    except (KeyError, AssertionError):
264
        raise BadRequest('Malformed request.')
265
    
266
    meta, created = ImageMetadata.objects.get_or_create(
267
        meta_key=key,
268
        image=image)
269
    
270
    meta.meta_value = metadict[key]
271
    meta.save()
272
    image.save()
273
    return util.render_meta(request, meta, status=201)
274

    
275
@util.api_method('DELETE')
276
def delete_metadata_item(request, image_id, key):
277
    # Normal Response Code: 204
278
    # Error Response Codes: computeFault (400, 500),
279
    #                       serviceUnavailable (503),
280
    #                       unauthorized (401),
281
    #                       itemNotFound (404),
282
    #                       badRequest (400),
283
    #                       buildInProgress (409),
284
    #                       badMediaType(415),
285
    #                       overLimit (413),
286

    
287
    image = util.get_image(image_id, request.user)
288
    meta = util.get_image_meta(image, key)
289
    meta.delete()
290
    image.save()
291
    return HttpResponse(status=204)