Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (11.9 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 6b256427 Christos Stavrakakis
from django.conf.urls 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 c0720b78 Kostas Papadimitriou
        return api.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 c0720b78 Kostas Papadimitriou
        return api.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 c0720b78 Kostas Papadimitriou
        return api.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 c0720b78 Kostas Papadimitriou
        return api.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 936e0be3 Christos Stavrakakis
        d['user_id'] = image['owner']
108 936e0be3 Christos Stavrakakis
        d['tenant_id'] = image['owner']
109 27e57c27 Christos Stavrakakis
        d['links'] = util.image_to_links(image["id"])
110 936e0be3 Christos Stavrakakis
        if image["properties"]:
111 5029ff36 Christos Stavrakakis
            d['metadata'] = image['properties']
112 936e0be3 Christos Stavrakakis
        else:
113 936e0be3 Christos Stavrakakis
            d['metadata'] = {}
114 c36934a7 Giorgos Verigakis
    return d
115 c36934a7 Giorgos Verigakis
116 c36934a7 Giorgos Verigakis
117 b3fd98ae Christos Stavrakakis
@api.api_method("GET", user_required=True, logger=log)
118 c36934a7 Giorgos Verigakis
def list_images(request, detail=False):
119 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 200, 203
120 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
121 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
122 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
123 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
124 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
125 cd2b0bf5 Christos Stavrakakis
126 0c37a721 Christos Stavrakakis
    log.debug('list_images detail=%s', detail)
127 cda71050 Christos Stavrakakis
    since = utils.isoparse(request.GET.get('changes-since'))
128 b3a77863 Christos Stavrakakis
    with image_backend(request.user_uniq) as backend:
129 14c94c48 Christos Stavrakakis
        images = backend.list_images()
130 b3a77863 Christos Stavrakakis
        if since:
131 14c94c48 Christos Stavrakakis
            updated_since = lambda img: date_parse(img["updated_at"]) >= since
132 14c94c48 Christos Stavrakakis
            images = ifilter(updated_since, images)
133 b3a77863 Christos Stavrakakis
            if not images:
134 b3a77863 Christos Stavrakakis
                return HttpResponse(status=304)
135 cd2b0bf5 Christos Stavrakakis
136 cd2b0bf5 Christos Stavrakakis
    images = sorted(images, key=lambda x: x['id'])
137 6ef51e9f Giorgos Verigakis
    reply = [image_to_dict(image, detail) for image in images]
138 cd2b0bf5 Christos Stavrakakis
139 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
140 6ef51e9f Giorgos Verigakis
        data = render_to_string('list_images.xml',
141 6ef51e9f Giorgos Verigakis
                                dict(images=reply, detail=detail))
142 c36934a7 Giorgos Verigakis
    else:
143 5029ff36 Christos Stavrakakis
        data = json.dumps(dict(images=reply))
144 cd2b0bf5 Christos Stavrakakis
145 d8e50a39 Giorgos Verigakis
    return HttpResponse(data, status=200)
146 c36934a7 Giorgos Verigakis
147 6ef51e9f Giorgos Verigakis
148 b3fd98ae Christos Stavrakakis
@api.api_method('POST', user_required=True, logger=log)
149 c36934a7 Giorgos Verigakis
def create_image(request):
150 c36934a7 Giorgos Verigakis
    # Normal Response Code: 202
151 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
152 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
153 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
154 c36934a7 Giorgos Verigakis
    #                       badMediaType(415),
155 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
156 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
157 c36934a7 Giorgos Verigakis
    #                       serverCapacityUnavailable (503),
158 c36934a7 Giorgos Verigakis
    #                       buildInProgress (409),
159 c36934a7 Giorgos Verigakis
    #                       resizeNotAllowed (403),
160 c36934a7 Giorgos Verigakis
    #                       backupOrResizeInProgress (409),
161 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
162 cd2b0bf5 Christos Stavrakakis
163 bd40abfa Christos Stavrakakis
    raise faults.NotImplemented('Not supported.')
164 aa197ee4 Vangelis Koukis
165 aa197ee4 Vangelis Koukis
166 b3fd98ae Christos Stavrakakis
@api.api_method('GET', user_required=True, logger=log)
167 c36934a7 Giorgos Verigakis
def get_image_details(request, image_id):
168 c36934a7 Giorgos Verigakis
    # Normal Response Codes: 200, 203
169 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
170 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
171 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
172 c36934a7 Giorgos Verigakis
    #                       badRequest (400),
173 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
174 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
175 cd2b0bf5 Christos Stavrakakis
176 0c37a721 Christos Stavrakakis
    log.debug('get_image_details %s', image_id)
177 cda71050 Christos Stavrakakis
    with image_backend(request.user_uniq) as backend:
178 cda71050 Christos Stavrakakis
        image = backend.get_image(image_id)
179 6ef51e9f Giorgos Verigakis
    reply = image_to_dict(image)
180 cd2b0bf5 Christos Stavrakakis
181 d8e50a39 Giorgos Verigakis
    if request.serialization == 'xml':
182 6ef51e9f Giorgos Verigakis
        data = render_to_string('image.xml', dict(image=reply))
183 c36934a7 Giorgos Verigakis
    else:
184 6ef51e9f Giorgos Verigakis
        data = json.dumps(dict(image=reply))
185 cd2b0bf5 Christos Stavrakakis
186 c36934a7 Giorgos Verigakis
    return HttpResponse(data, status=200)
187 c36934a7 Giorgos Verigakis
188 6ef51e9f Giorgos Verigakis
189 b3fd98ae Christos Stavrakakis
@api.api_method('DELETE', user_required=True, logger=log)
190 c36934a7 Giorgos Verigakis
def delete_image(request, image_id):
191 c36934a7 Giorgos Verigakis
    # Normal Response Code: 204
192 c36934a7 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
193 c36934a7 Giorgos Verigakis
    #                       serviceUnavailable (503),
194 c36934a7 Giorgos Verigakis
    #                       unauthorized (401),
195 c36934a7 Giorgos Verigakis
    #                       itemNotFound (404),
196 c36934a7 Giorgos Verigakis
    #                       overLimit (413)
197 cd2b0bf5 Christos Stavrakakis
198 bf5c82dc Christos Stavrakakis
    log.info('delete_image %s', image_id)
199 b3a77863 Christos Stavrakakis
    with image_backend(request.user_uniq) as backend:
200 f13aab5d Christos Stavrakakis
        backend.unregister(image_id)
201 4b3b8688 Giorgos Verigakis
    log.info('User %s deleted image %s', request.user_uniq, image_id)
202 c36934a7 Giorgos Verigakis
    return HttpResponse(status=204)
203 432fc8c3 Giorgos Verigakis
204 6ef51e9f Giorgos Verigakis
205 b3fd98ae Christos Stavrakakis
@api.api_method('GET', user_required=True, logger=log)
206 432fc8c3 Giorgos Verigakis
def list_metadata(request, image_id):
207 432fc8c3 Giorgos Verigakis
    # Normal Response Codes: 200, 203
208 432fc8c3 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
209 432fc8c3 Giorgos Verigakis
    #                       serviceUnavailable (503),
210 432fc8c3 Giorgos Verigakis
    #                       unauthorized (401),
211 432fc8c3 Giorgos Verigakis
    #                       badRequest (400),
212 432fc8c3 Giorgos Verigakis
    #                       overLimit (413)
213 cd2b0bf5 Christos Stavrakakis
214 0c37a721 Christos Stavrakakis
    log.debug('list_image_metadata %s', image_id)
215 cda71050 Christos Stavrakakis
    with image_backend(request.user_uniq) as backend:
216 cda71050 Christos Stavrakakis
        image = backend.get_image(image_id)
217 6ef51e9f Giorgos Verigakis
    metadata = image['properties']
218 5029ff36 Christos Stavrakakis
    return util.render_metadata(request, metadata, use_values=False,
219 5029ff36 Christos Stavrakakis
                                status=200)
220 432fc8c3 Giorgos Verigakis
221 6ef51e9f Giorgos Verigakis
222 b3fd98ae Christos Stavrakakis
@api.api_method('POST', user_required=True, logger=log)
223 432fc8c3 Giorgos Verigakis
def update_metadata(request, image_id):
224 432fc8c3 Giorgos Verigakis
    # Normal Response Code: 201
225 432fc8c3 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
226 432fc8c3 Giorgos Verigakis
    #                       serviceUnavailable (503),
227 432fc8c3 Giorgos Verigakis
    #                       unauthorized (401),
228 432fc8c3 Giorgos Verigakis
    #                       badRequest (400),
229 432fc8c3 Giorgos Verigakis
    #                       buildInProgress (409),
230 432fc8c3 Giorgos Verigakis
    #                       badMediaType(415),
231 432fc8c3 Giorgos Verigakis
    #                       overLimit (413)
232 cd2b0bf5 Christos Stavrakakis
233 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
234 bf5c82dc Christos Stavrakakis
    log.info('update_image_metadata %s %s', image_id, req)
235 cda71050 Christos Stavrakakis
    with image_backend(request.user_uniq) as backend:
236 cda71050 Christos Stavrakakis
        image = backend.get_image(image_id)
237 cda71050 Christos Stavrakakis
        try:
238 cda71050 Christos Stavrakakis
            metadata = req['metadata']
239 cda71050 Christos Stavrakakis
            assert isinstance(metadata, dict)
240 cda71050 Christos Stavrakakis
        except (KeyError, AssertionError):
241 cda71050 Christos Stavrakakis
            raise faults.BadRequest('Malformed request.')
242 cd2b0bf5 Christos Stavrakakis
243 cda71050 Christos Stavrakakis
        properties = image['properties']
244 cda71050 Christos Stavrakakis
        properties.update(metadata)
245 cd2b0bf5 Christos Stavrakakis
246 cda71050 Christos Stavrakakis
        backend.update_metadata(image_id, dict(properties=properties))
247 cd2b0bf5 Christos Stavrakakis
248 6ef51e9f Giorgos Verigakis
    return util.render_metadata(request, properties, status=201)
249 432fc8c3 Giorgos Verigakis
250 6ef51e9f Giorgos Verigakis
251 b3fd98ae Christos Stavrakakis
@api.api_method('GET', user_required=True, logger=log)
252 432fc8c3 Giorgos Verigakis
def get_metadata_item(request, image_id, key):
253 432fc8c3 Giorgos Verigakis
    # Normal Response Codes: 200, 203
254 432fc8c3 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
255 432fc8c3 Giorgos Verigakis
    #                       serviceUnavailable (503),
256 432fc8c3 Giorgos Verigakis
    #                       unauthorized (401),
257 432fc8c3 Giorgos Verigakis
    #                       itemNotFound (404),
258 432fc8c3 Giorgos Verigakis
    #                       badRequest (400),
259 432fc8c3 Giorgos Verigakis
    #                       overLimit (413)
260 cd2b0bf5 Christos Stavrakakis
261 0c37a721 Christos Stavrakakis
    log.debug('get_image_metadata_item %s %s', image_id, key)
262 cda71050 Christos Stavrakakis
    with image_backend(request.user_uniq) as backend:
263 cda71050 Christos Stavrakakis
        image = backend.get_image(image_id)
264 6ef51e9f Giorgos Verigakis
    val = image['properties'].get(key)
265 6ef51e9f Giorgos Verigakis
    if val is None:
266 bd40abfa Christos Stavrakakis
        raise faults.ItemNotFound('Metadata key not found.')
267 6ef51e9f Giorgos Verigakis
    return util.render_meta(request, {key: val}, status=200)
268 6ef51e9f Giorgos Verigakis
269 432fc8c3 Giorgos Verigakis
270 b3fd98ae Christos Stavrakakis
@api.api_method('PUT', user_required=True, logger=log)
271 432fc8c3 Giorgos Verigakis
def create_metadata_item(request, image_id, key):
272 432fc8c3 Giorgos Verigakis
    # Normal Response Code: 201
273 432fc8c3 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
274 432fc8c3 Giorgos Verigakis
    #                       serviceUnavailable (503),
275 432fc8c3 Giorgos Verigakis
    #                       unauthorized (401),
276 432fc8c3 Giorgos Verigakis
    #                       itemNotFound (404),
277 432fc8c3 Giorgos Verigakis
    #                       badRequest (400),
278 432fc8c3 Giorgos Verigakis
    #                       buildInProgress (409),
279 432fc8c3 Giorgos Verigakis
    #                       badMediaType(415),
280 432fc8c3 Giorgos Verigakis
    #                       overLimit (413)
281 cd2b0bf5 Christos Stavrakakis
282 b3fd98ae Christos Stavrakakis
    req = utils.get_request_dict(request)
283 bf5c82dc Christos Stavrakakis
    log.info('create_image_metadata_item %s %s %s', image_id, key, req)
284 432fc8c3 Giorgos Verigakis
    try:
285 432fc8c3 Giorgos Verigakis
        metadict = req['meta']
286 432fc8c3 Giorgos Verigakis
        assert isinstance(metadict, dict)
287 432fc8c3 Giorgos Verigakis
        assert len(metadict) == 1
288 432fc8c3 Giorgos Verigakis
        assert key in metadict
289 432fc8c3 Giorgos Verigakis
    except (KeyError, AssertionError):
290 bd40abfa Christos Stavrakakis
        raise faults.BadRequest('Malformed request.')
291 6ef51e9f Giorgos Verigakis
292 6ef51e9f Giorgos Verigakis
    val = metadict[key]
293 b3a77863 Christos Stavrakakis
    with image_backend(request.user_uniq) as backend:
294 cda71050 Christos Stavrakakis
        image = backend.get_image(image_id)
295 cda71050 Christos Stavrakakis
        properties = image['properties']
296 cda71050 Christos Stavrakakis
        properties[key] = val
297 cda71050 Christos Stavrakakis
298 cda71050 Christos Stavrakakis
        backend.update_metadata(image_id, dict(properties=properties))
299 cd2b0bf5 Christos Stavrakakis
300 6ef51e9f Giorgos Verigakis
    return util.render_meta(request, {key: val}, status=201)
301 6ef51e9f Giorgos Verigakis
302 432fc8c3 Giorgos Verigakis
303 b3fd98ae Christos Stavrakakis
@api.api_method('DELETE', user_required=True, logger=log)
304 432fc8c3 Giorgos Verigakis
def delete_metadata_item(request, image_id, key):
305 432fc8c3 Giorgos Verigakis
    # Normal Response Code: 204
306 432fc8c3 Giorgos Verigakis
    # Error Response Codes: computeFault (400, 500),
307 432fc8c3 Giorgos Verigakis
    #                       serviceUnavailable (503),
308 432fc8c3 Giorgos Verigakis
    #                       unauthorized (401),
309 432fc8c3 Giorgos Verigakis
    #                       itemNotFound (404),
310 432fc8c3 Giorgos Verigakis
    #                       badRequest (400),
311 432fc8c3 Giorgos Verigakis
    #                       buildInProgress (409),
312 432fc8c3 Giorgos Verigakis
    #                       badMediaType(415),
313 432fc8c3 Giorgos Verigakis
    #                       overLimit (413),
314 cd2b0bf5 Christos Stavrakakis
315 bf5c82dc Christos Stavrakakis
    log.info('delete_image_metadata_item %s %s', image_id, key)
316 b3a77863 Christos Stavrakakis
    with image_backend(request.user_uniq) as backend:
317 cda71050 Christos Stavrakakis
        image = backend.get_image(image_id)
318 cda71050 Christos Stavrakakis
        properties = image['properties']
319 cda71050 Christos Stavrakakis
        properties.pop(key, None)
320 cda71050 Christos Stavrakakis
321 cda71050 Christos Stavrakakis
        backend.update_metadata(image_id, dict(properties=properties))
322 cd2b0bf5 Christos Stavrakakis
323 432fc8c3 Giorgos Verigakis
    return HttpResponse(status=204)