Revision 29490fca

b/snf-cyclades-app/synnefo/plankton/views.py
73 73

  
74 74
def _create_image_response(image):
75 75
    response = HttpResponse()
76
    
76

  
77 77
    for key in DETAIL_FIELDS:
78 78
        if key == 'properties':
79 79
            for k, v in image.get('properties', {}).items():
......
82 82
        else:
83 83
            name = 'x-image-meta-' + key.replace('_', '-')
84 84
            response[name] = image.get(key, '')
85
    
85

  
86 86
    return response
87 87

  
88 88

  
89 89
def _get_image_headers(request):
90 90
    def normalize(s):
91 91
        return ''.join('_' if c in punctuation else c.lower() for c in s)
92
    
92

  
93 93
    META_PREFIX = 'HTTP_X_IMAGE_META_'
94 94
    META_PREFIX_LEN = len(META_PREFIX)
95 95
    META_PROPERTY_PREFIX = 'HTTP_X_IMAGE_META_PROPERTY_'
96 96
    META_PROPERTY_PREFIX_LEN = len(META_PROPERTY_PREFIX)
97
    
97

  
98 98
    headers = {'properties': {}}
99
    
99

  
100 100
    for key, val in request.META.items():
101 101
        if key.startswith(META_PROPERTY_PREFIX):
102 102
            name = normalize(key[META_PROPERTY_PREFIX_LEN:])
......
104 104
        elif key.startswith(META_PREFIX):
105 105
            name = normalize(key[META_PREFIX_LEN:])
106 106
            headers[unquote(name)] = unquote(val)
107
    
107

  
108 108
    is_public = headers.get('is_public', None)
109 109
    if is_public is not None:
110 110
        headers['is_public'] = True if is_public.lower() == 'true' else False
111
    
111

  
112 112
    if not headers['properties']:
113 113
        del headers['properties']
114
    
114

  
115 115
    return headers
116 116

  
117 117

  
118 118
@plankton_method('POST')
119 119
def add_image(request):
120 120
    """Add a new virtual machine image
121
    
121

  
122 122
    Described in:
123 123
    3.6. Adding a New Virtual Machine Image
124
    
124

  
125 125
    Implementation notes:
126 126
      * The implementation is very inefficient as it loads the whole image
127 127
        in memory.
128
    
128

  
129 129
    Limitations:
130 130
      * x-image-meta-id is not supported. Will always return 409 Conflict.
131
    
131

  
132 132
    Extensions:
133 133
      * An x-image-meta-location header can be passed with a link to file,
134 134
        instead of uploading the data.
135 135
    """
136
    
136

  
137 137
    params = _get_image_headers(request)
138 138
    log.debug('add_image %s', params)
139
    
139

  
140 140
    assert 'name' in params
141 141
    assert set(params.keys()).issubset(set(ADD_FIELDS))
142
    
142

  
143 143
    name = params.pop('name')
144 144
    location = params.pop('location', None)
145
    
145

  
146 146
    if location:
147 147
        image = request.backend.register(name, location, params)
148 148
    else:
149 149
        #f = StringIO(request.raw_post_data)
150 150
        #image = request.backend.put(name, f, params)
151 151
        return HttpResponse(status=501)     # Not Implemented
152
    
152

  
153 153
    if not image:
154 154
        return HttpResponse('Registration failed', status=500)
155
    
155

  
156 156
    return _create_image_response(image)
157 157

  
158 158

  
159 159
@plankton_method('PUT')
160 160
def add_image_member(request, image_id, member):
161 161
    """Add a member to an image
162
    
162

  
163 163
    Described in:
164 164
    3.9. Adding a Member to an Image
165
    
165

  
166 166
    Limitations:
167 167
      * Passing a body to enable `can_share` is not supported.
168 168
    """
169
    
169

  
170 170
    log.debug('add_image_member %s %s', image_id, member)
171 171
    request.backend.add_user(image_id, member)
172 172
    return HttpResponse(status=204)
......
175 175
@plankton_method('GET')
176 176
def get_image(request, image_id):
177 177
    """Retrieve a virtual machine image
178
    
178

  
179 179
    Described in:
180 180
    3.5. Retrieving a Virtual Machine Image
181
    
181

  
182 182
    Implementation notes:
183 183
      * The implementation is very inefficient as it loads the whole image
184 184
        in memory.
185 185
    """
186
    
186

  
187 187
    #image = request.backend.get_image(image_id)
188 188
    #if not image:
189 189
    #    return HttpResponseNotFound()
......
201 201
@plankton_method('HEAD')
202 202
def get_image_meta(request, image_id):
203 203
    """Return detailed metadata on a specific image
204
    
204

  
205 205
    Described in:
206 206
    3.4. Requesting Detailed Metadata on a Specific Image
207 207
    """
......
219 219
    Described in:
220 220
    3.7. Requesting Image Memberships
221 221
    """
222
    
222

  
223 223
    members = [{'member_id': user, 'can_share': False}
224 224
                for user in request.backend.list_users(image_id)]
225 225
    data = json.dumps({'members': members}, indent=settings.DEBUG)
......
229 229
@plankton_method('GET')
230 230
def list_public_images(request, detail=False):
231 231
    """Return a list of public VM images.
232
    
232

  
233 233
    Described in:
234 234
    3.1. Requesting a List of Public VM Images
235 235
    3.2. Requesting Detailed Metadata on Public VM Images
236 236
    3.3. Filtering Images Returned via GET /images andGET /images/detail
237
    
237

  
238 238
    Extensions:
239 239
      * Image ID is returned in both compact and detail listings
240 240
    """
......
259 259
    assert params['sort_dir'] in SORT_DIR_OPTIONS
260 260

  
261 261
    images = request.backend.list_public(filters, params)
262
    
262

  
263 263
    # Remove keys that should not be returned
264 264
    fields = DETAIL_FIELDS if detail else LIST_FIELDS
265 265
    for image in images:
......
274 274
@plankton_method('GET')
275 275
def list_shared_images(request, member):
276 276
    """Request shared images
277
    
277

  
278 278
    Described in:
279 279
    3.8. Requesting Shared Images
280
    
280

  
281 281
    Implementation notes:
282 282
      * It is not clear what this method should do. We return the IDs of
283 283
        the users's images that are accessible by `member`.
284 284
    """
285
    
285

  
286 286
    log.debug('list_shared_images %s', member)
287
    
287

  
288 288
    images = []
289 289
    for image_id in request.backend.iter_shared(member):
290 290
        images.append({'image_id': image_id, 'can_share': False})
291
    
291

  
292 292
    data = json.dumps({'shared_images': images}, indent=settings.DEBUG)
293 293
    return HttpResponse(data)
294 294

  
......
309 309
@plankton_method('PUT')
310 310
def update_image(request, image_id):
311 311
    """Update an image
312
    
312

  
313 313
    Described in:
314 314
    3.6.2. Updating an Image
315
    
315

  
316 316
    Implementation notes:
317 317
      * It is not clear which metadata are allowed to be updated. We support:
318 318
        name, disk_format, container_format, is_public, owner, properties
319 319
        and status.
320 320
    """
321
    
321

  
322 322
    meta = _get_image_headers(request)
323 323
    log.debug('update_image %s', meta)
324
    
324

  
325 325
    assert set(meta.keys()).issubset(set(UPDATE_FIELDS))
326
    
326

  
327 327
    image = request.backend.update(image_id, meta)
328 328
    return _create_image_response(image)
329 329

  
......
331 331
@plankton_method('PUT')
332 332
def update_image_members(request, image_id):
333 333
    """Replace a membership list for an image
334
    
334

  
335 335
    Described in:
336 336
    3.11. Replacing a Membership List for an Image
337
    
337

  
338 338
    Limitations:
339 339
      * can_share value is ignored
340 340
    """
341
    
341

  
342 342
    log.debug('update_image_members %s', image_id)
343 343
    members = []
344 344
    try:
......
347 347
            members.append(member['member_id'])
348 348
    except (ValueError, KeyError, TypeError):
349 349
        return HttpResponse(status=400)
350
    
350

  
351 351
    request.backend.replace_users(image_id, members)
352 352
    return HttpResponse(status=204)

Also available in: Unified diff