Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / api / images.py @ 8a992938

History | View | Annotate | Download (11.7 kB)

1 6ef51e9f Giorgos Verigakis
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 cd2b0bf5 Christos Stavrakakis
#
3 adee02b8 Giorgos Verigakis
# Redistribution and use in source and binary forms, with or
4 adee02b8 Giorgos Verigakis
# without modification, are permitted provided that the following
5 adee02b8 Giorgos Verigakis
# conditions are met:
6 cd2b0bf5 Christos Stavrakakis
#
7 adee02b8 Giorgos Verigakis
#   1. Redistributions of source code must retain the above
8 adee02b8 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
9 adee02b8 Giorgos Verigakis
#      disclaimer.
10 cd2b0bf5 Christos Stavrakakis
#
11 adee02b8 Giorgos Verigakis
#   2. Redistributions in binary form must reproduce the above
12 adee02b8 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
13 adee02b8 Giorgos Verigakis
#      disclaimer in the documentation and/or other materials
14 adee02b8 Giorgos Verigakis
#      provided with the distribution.
15 cd2b0bf5 Christos Stavrakakis
#
16 adee02b8 Giorgos Verigakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 adee02b8 Giorgos Verigakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 adee02b8 Giorgos Verigakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 adee02b8 Giorgos Verigakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 adee02b8 Giorgos Verigakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 adee02b8 Giorgos Verigakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 adee02b8 Giorgos Verigakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 adee02b8 Giorgos Verigakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 adee02b8 Giorgos Verigakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 adee02b8 Giorgos Verigakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 adee02b8 Giorgos Verigakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 adee02b8 Giorgos Verigakis
# POSSIBILITY OF SUCH DAMAGE.
28 cd2b0bf5 Christos Stavrakakis
#
29 adee02b8 Giorgos Verigakis
# The views and conclusions contained in the software and
30 adee02b8 Giorgos Verigakis
# documentation are those of the authors and should not be
31 adee02b8 Giorgos Verigakis
# interpreted as representing official policies, either expressed
32 adee02b8 Giorgos Verigakis
# or implied, of GRNET S.A.
33 c36934a7 Giorgos Verigakis
34 2035039b Giorgos Verigakis
from logging import getLogger
35 14c94c48 Christos Stavrakakis
from itertools import ifilter
36 2035039b Giorgos Verigakis
37 b3fd98ae Christos Stavrakakis
from dateutil.parser import parse as date_parse
38 6ef51e9f Giorgos Verigakis
39 d8e50a39 Giorgos Verigakis
from django.conf.urls.defaults import patterns
40 c36934a7 Giorgos Verigakis
from django.http import HttpResponse
41 c36934a7 Giorgos Verigakis
from django.template.loader import render_to_string
42 29a59bc1 Giorgos Verigakis
from django.utils import simplejson as json
43 c36934a7 Giorgos Verigakis
44 b3fd98ae Christos Stavrakakis
from snf_django.lib import api
45 b3fd98ae Christos Stavrakakis
from snf_django.lib.api import faults, utils
46 b36f78fa Giorgos Verigakis
from synnefo.api import util
47 b3fd98ae Christos Stavrakakis
from synnefo.plankton.utils import image_backend
48 b36f78fa Giorgos Verigakis
49 c36934a7 Giorgos Verigakis
50 b3fd98ae Christos Stavrakakis
log = getLogger(__name__)
51 9e98ba3c Giorgos Verigakis
52 e440e835 Christos Stavrakakis
urlpatterns = patterns(
53 e440e835 Christos Stavrakakis
    'synnefo.api.images',
54 c36934a7 Giorgos Verigakis
    (r'^(?:/|.json|.xml)?$', 'demux'),
55 c36934a7 Giorgos Verigakis
    (r'^/detail(?:.json|.xml)?$', 'list_images', {'detail': True}),
56 6ef51e9f Giorgos Verigakis
    (r'^/([\w-]+)(?:.json|.xml)?$', 'image_demux'),
57 8a992938 Christos Stavrakakis
    (r'^/([\w-]+)/metadata(?:.json|.xml)?$', 'metadata_demux'),
58 8a992938 Christos Stavrakakis
    (r'^/([\w-]+)/metadata/(.+?)(?:.json|.xml)?$', 'metadata_item_demux')
59 c36934a7 Giorgos Verigakis
)
60 c36934a7 Giorgos Verigakis
61 e440e835 Christos Stavrakakis
62 c36934a7 Giorgos Verigakis
def demux(request):
63 c36934a7 Giorgos Verigakis
    if request.method == 'GET':
64 c36934a7 Giorgos Verigakis
        return list_images(request)
65 c36934a7 Giorgos Verigakis
    elif request.method == 'POST':
66 c36934a7 Giorgos Verigakis
        return create_image(request)
67 c36934a7 Giorgos Verigakis
    else:
68 b3fd98ae Christos Stavrakakis
        return api.method_not_allowed(request)
69 c36934a7 Giorgos Verigakis
70 e440e835 Christos Stavrakakis
71 c36934a7 Giorgos Verigakis
def image_demux(request, image_id):
72 c36934a7 Giorgos Verigakis
    if request.method == 'GET':
73 c36934a7 Giorgos Verigakis
        return get_image_details(request, image_id)
74 c36934a7 Giorgos Verigakis
    elif request.method == 'DELETE':
75 c36934a7 Giorgos Verigakis
        return delete_image(request, image_id)
76 c36934a7 Giorgos Verigakis
    else:
77 b3fd98ae Christos Stavrakakis
        return api.method_not_allowed(request)
78 c36934a7 Giorgos Verigakis
79 e440e835 Christos Stavrakakis
80 432fc8c3 Giorgos Verigakis
def metadata_demux(request, image_id):
81 432fc8c3 Giorgos Verigakis
    if request.method == 'GET':
82 432fc8c3 Giorgos Verigakis
        return list_metadata(request, image_id)
83 432fc8c3 Giorgos Verigakis
    elif request.method == 'POST':
84 432fc8c3 Giorgos Verigakis
        return update_metadata(request, image_id)
85 432fc8c3 Giorgos Verigakis
    else:
86 b3fd98ae Christos Stavrakakis
        return api.method_not_allowed(request)
87 432fc8c3 Giorgos Verigakis
88 e440e835 Christos Stavrakakis
89 432fc8c3 Giorgos Verigakis
def metadata_item_demux(request, image_id, key):
90 432fc8c3 Giorgos Verigakis
    if request.method == 'GET':
91 432fc8c3 Giorgos Verigakis
        return get_metadata_item(request, image_id, key)
92 432fc8c3 Giorgos Verigakis
    elif request.method == 'PUT':
93 432fc8c3 Giorgos Verigakis
        return create_metadata_item(request, image_id, key)
94 432fc8c3 Giorgos Verigakis
    elif request.method == 'DELETE':
95 432fc8c3 Giorgos Verigakis
        return delete_metadata_item(request, image_id, key)
96 432fc8c3 Giorgos Verigakis
    else:
97 b3fd98ae Christos Stavrakakis
        return api.method_not_allowed(request)
98 432fc8c3 Giorgos Verigakis
99 c36934a7 Giorgos Verigakis
100 c36934a7 Giorgos Verigakis
def image_to_dict(image, detail=True):
101 6ef51e9f Giorgos Verigakis
    d = dict(id=image['id'], name=image['name'])
102 c36934a7 Giorgos Verigakis
    if detail:
103 b3fd98ae Christos Stavrakakis
        d['updated'] = utils.isoformat(date_parse(image['updated_at']))
104 b3fd98ae Christos Stavrakakis
        d['created'] = utils.isoformat(date_parse(image['created_at']))
105 6ef51e9f Giorgos Verigakis
        d['status'] = 'DELETED' if image['deleted_at'] else 'ACTIVE'
106 6ef51e9f Giorgos Verigakis
        d['progress'] = 100 if image['status'] == 'available' else 0
107 6ef51e9f Giorgos Verigakis
        if image['properties']:
108 6ef51e9f Giorgos Verigakis
            d['metadata'] = {'values': image['properties']}
109 c36934a7 Giorgos Verigakis
    return d
110 c36934a7 Giorgos Verigakis
111 c36934a7 Giorgos Verigakis
112 b3fd98ae Christos Stavrakakis
@api.api_method("GET", user_required=True, logger=log)
113 c36934a7 Giorgos Verigakis
def list_images(request, detail=False):
114 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 200, 203
115 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
116 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
117 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
118 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
119 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
120 cd2b0bf5 Christos Stavrakakis
121 0c37a721 Christos Stavrakakis
    log.debug('list_images detail=%s', detail)
122 cda71050 Christos Stavrakakis
    since = utils.isoparse(request.GET.get('changes-since'))
123 b3a77863 Christos Stavrakakis
    with image_backend(request.user_uniq) as backend:
124 14c94c48 Christos Stavrakakis
        images = backend.list_images()
125 b3a77863 Christos Stavrakakis
        if since:
126 14c94c48 Christos Stavrakakis
            updated_since = lambda img: date_parse(img["updated_at"]) >= since
127 14c94c48 Christos Stavrakakis
            images = ifilter(updated_since, images)
128 b3a77863 Christos Stavrakakis
            if not images:
129 b3a77863 Christos Stavrakakis
                return HttpResponse(status=304)
130 cd2b0bf5 Christos Stavrakakis
131 cd2b0bf5 Christos Stavrakakis
    images = sorted(images, key=lambda x: x['id'])
132 6ef51e9f Giorgos Verigakis
    reply = [image_to_dict(image, detail) for image in images]
133 cd2b0bf5 Christos Stavrakakis
134 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
135 6ef51e9f Giorgos Verigakis
        data = render_to_string('list_images.xml',
136 6ef51e9f Giorgos Verigakis
                                dict(images=reply, detail=detail))
137 c36934a7 Giorgos Verigakis
    else:
138 6ef51e9f Giorgos Verigakis
        data = json.dumps(dict(images={'values': reply}))
139 cd2b0bf5 Christos Stavrakakis
140 d8e50a39 Giorgos Verigakis
    return HttpResponse(data, status=200)
141 c36934a7 Giorgos Verigakis
142 6ef51e9f Giorgos Verigakis
143 b3fd98ae Christos Stavrakakis
@api.api_method('POST', user_required=True, logger=log)
144 c36934a7 Giorgos Verigakis
def create_image(request):
145 c36934a7 Giorgos Verigakis
    # Normal Response Code: 202
146 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
147 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
148 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
149 c36934a7 Giorgos Verigakis
    #                       badMediaType(415),
150 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
151 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
152 c36934a7 Giorgos Verigakis
    #                       serverCapacityUnavailable (503),
153 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
154 c36934a7 Giorgos Verigakis
    #                       resizeNotAllowed (403),
155 c36934a7 Giorgos Verigakis
    #                       backupOrResizeInProgress (409),
156 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
157 cd2b0bf5 Christos Stavrakakis
158 bd40abfa Christos Stavrakakis
    raise faults.NotImplemented('Not supported.')
159 aa197ee4 Vangelis Koukis
160 aa197ee4 Vangelis Koukis
161 b3fd98ae Christos Stavrakakis
@api.api_method('GET', user_required=True, logger=log)
162 c36934a7 Giorgos Verigakis
def get_image_details(request, image_id):
163 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 200, 203
164 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
165 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
166 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
167 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
168 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
169 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
170 cd2b0bf5 Christos Stavrakakis
171 0c37a721 Christos Stavrakakis
    log.debug('get_image_details %s', image_id)
172 cda71050 Christos Stavrakakis
    with image_backend(request.user_uniq) as backend:
173 cda71050 Christos Stavrakakis
        image = backend.get_image(image_id)
174 6ef51e9f Giorgos Verigakis
    reply = image_to_dict(image)
175 cd2b0bf5 Christos Stavrakakis
176 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
177 6ef51e9f Giorgos Verigakis
        data = render_to_string('image.xml', dict(image=reply))
178 c36934a7 Giorgos Verigakis
    else:
179 6ef51e9f Giorgos Verigakis
        data = json.dumps(dict(image=reply))
180 cd2b0bf5 Christos Stavrakakis
181 c36934a7 Giorgos Verigakis
    return HttpResponse(data, status=200)
182 c36934a7 Giorgos Verigakis
183 6ef51e9f Giorgos Verigakis
184 b3fd98ae Christos Stavrakakis
@api.api_method('DELETE', user_required=True, logger=log)
185 c36934a7 Giorgos Verigakis
def delete_image(request, image_id):
186 c36934a7 Giorgos Verigakis
    # Normal Response Code: 204
187 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
188 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
189 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
190 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
191 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
192 cd2b0bf5 Christos Stavrakakis
193 bf5c82dc Christos Stavrakakis
    log.info('delete_image %s', image_id)
194 b3a77863 Christos Stavrakakis
    with image_backend(request.user_uniq) as backend:
195 f13aab5d Christos Stavrakakis
        backend.unregister(image_id)
196 4b3b8688 Giorgos Verigakis
    log.info('User %s deleted image %s', request.user_uniq, image_id)
197 c36934a7 Giorgos Verigakis
    return HttpResponse(status=204)
198 432fc8c3 Giorgos Verigakis
199 6ef51e9f Giorgos Verigakis
200 b3fd98ae Christos Stavrakakis
@api.api_method('GET', user_required=True, logger=log)
201 432fc8c3 Giorgos Verigakis
def list_metadata(request, image_id):
202 432fc8c3 Giorgos Verigakis
    # Normal Response Codes: 200, 203
203 432fc8c3 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
204 432fc8c3 Giorgos Verigakis
    #                       serviceUnavailable (503),
205 432fc8c3 Giorgos Verigakis
    #                       unauthorized (401),
206 432fc8c3 Giorgos Verigakis
    #                       badRequest (400),
207 432fc8c3 Giorgos Verigakis
    #                       overLimit (413)
208 cd2b0bf5 Christos Stavrakakis
209 0c37a721 Christos Stavrakakis
    log.debug('list_image_metadata %s', image_id)
210 cda71050 Christos Stavrakakis
    with image_backend(request.user_uniq) as backend:
211 cda71050 Christos Stavrakakis
        image = backend.get_image(image_id)
212 6ef51e9f Giorgos Verigakis
    metadata = image['properties']
213 b36f78fa Giorgos Verigakis
    return util.render_metadata(request, metadata, use_values=True, status=200)
214 432fc8c3 Giorgos Verigakis
215 6ef51e9f Giorgos Verigakis
216 b3fd98ae Christos Stavrakakis
@api.api_method('POST', user_required=True, logger=log)
217 432fc8c3 Giorgos Verigakis
def update_metadata(request, image_id):
218 432fc8c3 Giorgos Verigakis
    # Normal Response Code: 201
219 432fc8c3 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
220 432fc8c3 Giorgos Verigakis
    #                       serviceUnavailable (503),
221 432fc8c3 Giorgos Verigakis
    #                       unauthorized (401),
222 432fc8c3 Giorgos Verigakis
    #                       badRequest (400),
223 432fc8c3 Giorgos Verigakis
    #                       buildInProgress (409),
224 432fc8c3 Giorgos Verigakis
    #                       badMediaType(415),
225 432fc8c3 Giorgos Verigakis
    #                       overLimit (413)
226 cd2b0bf5 Christos Stavrakakis
227 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
228 bf5c82dc Christos Stavrakakis
    log.info('update_image_metadata %s %s', image_id, req)
229 cda71050 Christos Stavrakakis
    with image_backend(request.user_uniq) as backend:
230 cda71050 Christos Stavrakakis
        image = backend.get_image(image_id)
231 cda71050 Christos Stavrakakis
        try:
232 cda71050 Christos Stavrakakis
            metadata = req['metadata']
233 cda71050 Christos Stavrakakis
            assert isinstance(metadata, dict)
234 cda71050 Christos Stavrakakis
        except (KeyError, AssertionError):
235 cda71050 Christos Stavrakakis
            raise faults.BadRequest('Malformed request.')
236 cd2b0bf5 Christos Stavrakakis
237 cda71050 Christos Stavrakakis
        properties = image['properties']
238 cda71050 Christos Stavrakakis
        properties.update(metadata)
239 cd2b0bf5 Christos Stavrakakis
240 cda71050 Christos Stavrakakis
        backend.update_metadata(image_id, dict(properties=properties))
241 cd2b0bf5 Christos Stavrakakis
242 6ef51e9f Giorgos Verigakis
    return util.render_metadata(request, properties, status=201)
243 432fc8c3 Giorgos Verigakis
244 6ef51e9f Giorgos Verigakis
245 b3fd98ae Christos Stavrakakis
@api.api_method('GET', user_required=True, logger=log)
246 432fc8c3 Giorgos Verigakis
def get_metadata_item(request, image_id, key):
247 432fc8c3 Giorgos Verigakis
    # Normal Response Codes: 200, 203
248 432fc8c3 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
249 432fc8c3 Giorgos Verigakis
    #                       serviceUnavailable (503),
250 432fc8c3 Giorgos Verigakis
    #                       unauthorized (401),
251 432fc8c3 Giorgos Verigakis
    #                       itemNotFound (404),
252 432fc8c3 Giorgos Verigakis
    #                       badRequest (400),
253 432fc8c3 Giorgos Verigakis
    #                       overLimit (413)
254 cd2b0bf5 Christos Stavrakakis
255 0c37a721 Christos Stavrakakis
    log.debug('get_image_metadata_item %s %s', image_id, key)
256 cda71050 Christos Stavrakakis
    with image_backend(request.user_uniq) as backend:
257 cda71050 Christos Stavrakakis
        image = backend.get_image(image_id)
258 6ef51e9f Giorgos Verigakis
    val = image['properties'].get(key)
259 6ef51e9f Giorgos Verigakis
    if val is None:
260 bd40abfa Christos Stavrakakis
        raise faults.ItemNotFound('Metadata key not found.')
261 6ef51e9f Giorgos Verigakis
    return util.render_meta(request, {key: val}, status=200)
262 6ef51e9f Giorgos Verigakis
263 432fc8c3 Giorgos Verigakis
264 b3fd98ae Christos Stavrakakis
@api.api_method('PUT', user_required=True, logger=log)
265 432fc8c3 Giorgos Verigakis
def create_metadata_item(request, image_id, key):
266 432fc8c3 Giorgos Verigakis
    # Normal Response Code: 201
267 432fc8c3 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
268 432fc8c3 Giorgos Verigakis
    #                       serviceUnavailable (503),
269 432fc8c3 Giorgos Verigakis
    #                       unauthorized (401),
270 432fc8c3 Giorgos Verigakis
    #                       itemNotFound (404),
271 432fc8c3 Giorgos Verigakis
    #                       badRequest (400),
272 432fc8c3 Giorgos Verigakis
    #                       buildInProgress (409),
273 432fc8c3 Giorgos Verigakis
    #                       badMediaType(415),
274 432fc8c3 Giorgos Verigakis
    #                       overLimit (413)
275 cd2b0bf5 Christos Stavrakakis
276 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
277 bf5c82dc Christos Stavrakakis
    log.info('create_image_metadata_item %s %s %s', image_id, key, req)
278 432fc8c3 Giorgos Verigakis
    try:
279 432fc8c3 Giorgos Verigakis
        metadict = req['meta']
280 432fc8c3 Giorgos Verigakis
        assert isinstance(metadict, dict)
281 432fc8c3 Giorgos Verigakis
        assert len(metadict) == 1
282 432fc8c3 Giorgos Verigakis
        assert key in metadict
283 432fc8c3 Giorgos Verigakis
    except (KeyError, AssertionError):
284 bd40abfa Christos Stavrakakis
        raise faults.BadRequest('Malformed request.')
285 6ef51e9f Giorgos Verigakis
286 6ef51e9f Giorgos Verigakis
    val = metadict[key]
287 b3a77863 Christos Stavrakakis
    with image_backend(request.user_uniq) as backend:
288 cda71050 Christos Stavrakakis
        image = backend.get_image(image_id)
289 cda71050 Christos Stavrakakis
        properties = image['properties']
290 cda71050 Christos Stavrakakis
        properties[key] = val
291 cda71050 Christos Stavrakakis
292 cda71050 Christos Stavrakakis
        backend.update_metadata(image_id, dict(properties=properties))
293 cd2b0bf5 Christos Stavrakakis
294 6ef51e9f Giorgos Verigakis
    return util.render_meta(request, {key: val}, status=201)
295 6ef51e9f Giorgos Verigakis
296 432fc8c3 Giorgos Verigakis
297 b3fd98ae Christos Stavrakakis
@api.api_method('DELETE', user_required=True, logger=log)
298 432fc8c3 Giorgos Verigakis
def delete_metadata_item(request, image_id, key):
299 432fc8c3 Giorgos Verigakis
    # Normal Response Code: 204
300 432fc8c3 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
301 432fc8c3 Giorgos Verigakis
    #                       serviceUnavailable (503),
302 432fc8c3 Giorgos Verigakis
    #                       unauthorized (401),
303 432fc8c3 Giorgos Verigakis
    #                       itemNotFound (404),
304 432fc8c3 Giorgos Verigakis
    #                       badRequest (400),
305 432fc8c3 Giorgos Verigakis
    #                       buildInProgress (409),
306 432fc8c3 Giorgos Verigakis
    #                       badMediaType(415),
307 432fc8c3 Giorgos Verigakis
    #                       overLimit (413),
308 cd2b0bf5 Christos Stavrakakis
309 bf5c82dc Christos Stavrakakis
    log.info('delete_image_metadata_item %s %s', image_id, key)
310 b3a77863 Christos Stavrakakis
    with image_backend(request.user_uniq) as backend:
311 cda71050 Christos Stavrakakis
        image = backend.get_image(image_id)
312 cda71050 Christos Stavrakakis
        properties = image['properties']
313 cda71050 Christos Stavrakakis
        properties.pop(key, None)
314 cda71050 Christos Stavrakakis
315 cda71050 Christos Stavrakakis
        backend.update_metadata(image_id, dict(properties=properties))
316 cd2b0bf5 Christos Stavrakakis
317 432fc8c3 Giorgos Verigakis
    return HttpResponse(status=204)