Statistics
| Branch: | Tag: | Revision:

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

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