Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / volume / views.py @ dec501fa

History | View | Annotate | Download (12.1 kB)

1 dec501fa Christos Stavrakakis
# Copyright 2013 GRNET S.A. All rights reserved.
2 dec501fa Christos Stavrakakis
#
3 dec501fa Christos Stavrakakis
# Redistribution and use in source and binary forms, with or
4 dec501fa Christos Stavrakakis
# without modification, are permitted provided that the following
5 dec501fa Christos Stavrakakis
# conditions are met:
6 dec501fa Christos Stavrakakis
#
7 dec501fa Christos Stavrakakis
#   1. Redistributions of source code must retain the above
8 dec501fa Christos Stavrakakis
#      copyright notice, this list of conditions and the following
9 dec501fa Christos Stavrakakis
#      disclaimer.
10 dec501fa Christos Stavrakakis
#
11 dec501fa Christos Stavrakakis
#   2. Redistributions in binary form must reproduce the above
12 dec501fa Christos Stavrakakis
#      copyright notice, this list of conditions and the following
13 dec501fa Christos Stavrakakis
#      disclaimer in the documentation and/or other materials
14 dec501fa Christos Stavrakakis
#      provided with the distribution.
15 dec501fa Christos Stavrakakis
#
16 dec501fa Christos Stavrakakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 dec501fa Christos Stavrakakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 dec501fa Christos Stavrakakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 dec501fa Christos Stavrakakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 dec501fa Christos Stavrakakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 dec501fa Christos Stavrakakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 dec501fa Christos Stavrakakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 dec501fa Christos Stavrakakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 dec501fa Christos Stavrakakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 dec501fa Christos Stavrakakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 dec501fa Christos Stavrakakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 dec501fa Christos Stavrakakis
# POSSIBILITY OF SUCH DAMAGE.
28 dec501fa Christos Stavrakakis
#
29 dec501fa Christos Stavrakakis
# The views and conclusions contained in the software and
30 dec501fa Christos Stavrakakis
# documentation are those of the authors and should not be
31 dec501fa Christos Stavrakakis
# interpreted as representing official policies, either expressed
32 dec501fa Christos Stavrakakis
# or implied, of GRNET S.A.
33 dec501fa Christos Stavrakakis
34 dec501fa Christos Stavrakakis
from itertools import ifilter
35 dec501fa Christos Stavrakakis
from logging import getLogger
36 dec501fa Christos Stavrakakis
from django.http import HttpResponse
37 dec501fa Christos Stavrakakis
from django.utils import simplejson as json
38 dec501fa Christos Stavrakakis
39 dec501fa Christos Stavrakakis
import datetime
40 dec501fa Christos Stavrakakis
from dateutil.parser import parse as date_parse
41 dec501fa Christos Stavrakakis
42 dec501fa Christos Stavrakakis
from snf_django.lib import api
43 dec501fa Christos Stavrakakis
from snf_django.lib.api import faults, utils
44 dec501fa Christos Stavrakakis
45 dec501fa Christos Stavrakakis
from synnefo.volume import volumes, snapshots, util
46 dec501fa Christos Stavrakakis
from synnefo.db.models import Volume
47 dec501fa Christos Stavrakakis
from synnefo.plankton.utils import image_backend
48 dec501fa Christos Stavrakakis
log = getLogger('synnefo.volume')
49 dec501fa Christos Stavrakakis
50 dec501fa Christos Stavrakakis
51 dec501fa Christos Stavrakakis
def display_null_field(field):
52 dec501fa Christos Stavrakakis
    if field is None:
53 dec501fa Christos Stavrakakis
        return None
54 dec501fa Christos Stavrakakis
    else:
55 dec501fa Christos Stavrakakis
        str(field)
56 dec501fa Christos Stavrakakis
57 dec501fa Christos Stavrakakis
58 dec501fa Christos Stavrakakis
def volume_to_dict(volume, detail=True):
59 dec501fa Christos Stavrakakis
    data = {
60 dec501fa Christos Stavrakakis
        "id": str(volume.id),
61 dec501fa Christos Stavrakakis
        "name": display_null_field(volume.name),
62 dec501fa Christos Stavrakakis
        # TODO: Links!
63 dec501fa Christos Stavrakakis
        "links": "",
64 dec501fa Christos Stavrakakis
    }
65 dec501fa Christos Stavrakakis
    if detail:
66 dec501fa Christos Stavrakakis
        details = {
67 dec501fa Christos Stavrakakis
            "status": volume.status.lower(),
68 dec501fa Christos Stavrakakis
            "size": volume.size,
69 dec501fa Christos Stavrakakis
            "description": volume.description,
70 dec501fa Christos Stavrakakis
            "created_at": utils.isoformat(volume.created),
71 dec501fa Christos Stavrakakis
            "metadata": dict((m.key, m.value) for m in volume.metadata.all()),
72 dec501fa Christos Stavrakakis
            "snapshot_id": display_null_field(volume.source_snapshot_id),
73 dec501fa Christos Stavrakakis
            "source_volid": display_null_field(volume.source_volume_id),
74 dec501fa Christos Stavrakakis
            "image_id": display_null_field(volume.source_image_id),
75 dec501fa Christos Stavrakakis
            "attachments": get_volume_attachments(volume),
76 dec501fa Christos Stavrakakis
            # TODO:
77 dec501fa Christos Stavrakakis
            "volume_type": None,
78 dec501fa Christos Stavrakakis
            #"availabilit_zone": None,
79 dec501fa Christos Stavrakakis
            #"bootable": None,
80 dec501fa Christos Stavrakakis
            #"os-vol-tenant-attr:tenant_id": None,
81 dec501fa Christos Stavrakakis
            #"os-vol-host-attr:host": None,
82 dec501fa Christos Stavrakakis
            #"os-vol-mig-status-attr:name_id": None,
83 dec501fa Christos Stavrakakis
            #"os-vol-mig-status-attr:migstat": None,
84 dec501fa Christos Stavrakakis
        }
85 dec501fa Christos Stavrakakis
        data.update(details)
86 dec501fa Christos Stavrakakis
    return data
87 dec501fa Christos Stavrakakis
88 dec501fa Christos Stavrakakis
89 dec501fa Christos Stavrakakis
def get_volume_attachments(volume):
90 dec501fa Christos Stavrakakis
    if volume.machine_id is None:
91 dec501fa Christos Stavrakakis
        return []
92 dec501fa Christos Stavrakakis
    else:
93 dec501fa Christos Stavrakakis
        return [{"server_id": volume.machine_id,
94 dec501fa Christos Stavrakakis
                 "volume_id": volume.id,
95 dec501fa Christos Stavrakakis
                 "device_index": volume.index}]
96 dec501fa Christos Stavrakakis
97 dec501fa Christos Stavrakakis
98 dec501fa Christos Stavrakakis
@api.api_method(http_method="POST", user_required=True, logger=log)
99 dec501fa Christos Stavrakakis
def create_volume(request):
100 dec501fa Christos Stavrakakis
    """Create a new Volume."""
101 dec501fa Christos Stavrakakis
102 dec501fa Christos Stavrakakis
    req = utils.get_request_dict(request)
103 dec501fa Christos Stavrakakis
    log.debug("create_volume %s", req)
104 dec501fa Christos Stavrakakis
105 dec501fa Christos Stavrakakis
    user_id = request.user_uniq
106 dec501fa Christos Stavrakakis
    # Get and validate 'name' parameter
107 dec501fa Christos Stavrakakis
    # TODO: auto generate name
108 dec501fa Christos Stavrakakis
    name = req.get("name", None)
109 dec501fa Christos Stavrakakis
    if name is None:
110 dec501fa Christos Stavrakakis
        raise faults.BadRequest("Volume 'name' is needed.")
111 dec501fa Christos Stavrakakis
    # Get and validate 'size' parameter
112 dec501fa Christos Stavrakakis
    size = req.get("size")
113 dec501fa Christos Stavrakakis
    if size is None:
114 dec501fa Christos Stavrakakis
        raise faults.BadRequest("Volume 'size' is needed.")
115 dec501fa Christos Stavrakakis
    try:
116 dec501fa Christos Stavrakakis
        size = int(size)
117 dec501fa Christos Stavrakakis
        if size <= 0:
118 dec501fa Christos Stavrakakis
            raise ValueError
119 dec501fa Christos Stavrakakis
    except ValueError:
120 dec501fa Christos Stavrakakis
        raise faults.BadRequest("Volume 'size' needs to be a positive integer"
121 dec501fa Christos Stavrakakis
                                " value. '%s' cannot be accepted." % size)
122 dec501fa Christos Stavrakakis
123 dec501fa Christos Stavrakakis
    # TODO: Fix volume type, validate, etc..
124 dec501fa Christos Stavrakakis
    volume_type = req.get("volume_type", None)
125 dec501fa Christos Stavrakakis
126 dec501fa Christos Stavrakakis
    # Optional parameters
127 dec501fa Christos Stavrakakis
    description = req.get("description", "")
128 dec501fa Christos Stavrakakis
    metadata = req.get("metadata", {})
129 dec501fa Christos Stavrakakis
    if not isinstance(metadata, dict):
130 dec501fa Christos Stavrakakis
        msg = "Volume 'metadata' needs to be a dictionary of key-value pairs."\
131 dec501fa Christos Stavrakakis
              " '%s' can not be accepted." % metadata
132 dec501fa Christos Stavrakakis
        raise faults.BadRequest(msg)
133 dec501fa Christos Stavrakakis
134 dec501fa Christos Stavrakakis
    # Id of the volume to clone from
135 dec501fa Christos Stavrakakis
    source_volume_id = req.get("source_volid")
136 dec501fa Christos Stavrakakis
    # Id of the snapshot to create the volume from
137 dec501fa Christos Stavrakakis
    source_snapshot_id = req.get("snapshot_id")
138 dec501fa Christos Stavrakakis
    # Reference to an Image stored in Glance
139 dec501fa Christos Stavrakakis
    source_image_id = req.get("imageRef")
140 dec501fa Christos Stavrakakis
    # TODO: Check that not all of them are used
141 dec501fa Christos Stavrakakis
142 dec501fa Christos Stavrakakis
    server_id = req.get("server_id")
143 dec501fa Christos Stavrakakis
    if server_id is None:
144 dec501fa Christos Stavrakakis
        raise faults.BadRequest("Attribute 'server_id' is mandatory")
145 dec501fa Christos Stavrakakis
146 dec501fa Christos Stavrakakis
    # Create the volume
147 dec501fa Christos Stavrakakis
    volume = volumes.create(user_id=user_id, size=size, name=name,
148 dec501fa Christos Stavrakakis
                            source_volume_id=source_volume_id,
149 dec501fa Christos Stavrakakis
                            source_snapshot_id=source_snapshot_id,
150 dec501fa Christos Stavrakakis
                            source_image_id=source_image_id,
151 dec501fa Christos Stavrakakis
                            volume_type=volume_type, description=description,
152 dec501fa Christos Stavrakakis
                            metadata=metadata, server_id=server_id)
153 dec501fa Christos Stavrakakis
154 dec501fa Christos Stavrakakis
    # Render response
155 dec501fa Christos Stavrakakis
    data = json.dumps(dict(volume=volume_to_dict(volume, detail=False)))
156 dec501fa Christos Stavrakakis
    return HttpResponse(data, status=200)
157 dec501fa Christos Stavrakakis
158 dec501fa Christos Stavrakakis
159 dec501fa Christos Stavrakakis
@api.api_method(http_method="GET", user_required=True, logger=log)
160 dec501fa Christos Stavrakakis
def list_volumes(request, detail=False):
161 dec501fa Christos Stavrakakis
    log.debug('list_volumes detail=%s', detail)
162 dec501fa Christos Stavrakakis
    volumes = Volume.objects.filter(userid=request.user_uniq)
163 dec501fa Christos Stavrakakis
164 dec501fa Christos Stavrakakis
    since = utils.isoparse(request.GET.get('changes-since'))
165 dec501fa Christos Stavrakakis
    if since:
166 dec501fa Christos Stavrakakis
        volumes = volumes.filter(updated__gte=since)
167 dec501fa Christos Stavrakakis
        if not volumes:
168 dec501fa Christos Stavrakakis
            return HttpResponse(status=304)
169 dec501fa Christos Stavrakakis
    else:
170 dec501fa Christos Stavrakakis
        volumes = volumes.filter(deleted=False)
171 dec501fa Christos Stavrakakis
172 dec501fa Christos Stavrakakis
    volumes = [volume_to_dict(v, detail) for v in volumes.order_by("id")]
173 dec501fa Christos Stavrakakis
174 dec501fa Christos Stavrakakis
    data = json.dumps({'volumes': volumes})
175 dec501fa Christos Stavrakakis
    return HttpResponse(data, content_type="application/json", status=200)
176 dec501fa Christos Stavrakakis
177 dec501fa Christos Stavrakakis
178 dec501fa Christos Stavrakakis
@api.api_method(http_method="DELETE", user_required=True, logger=log)
179 dec501fa Christos Stavrakakis
def delete_volume(request, volume_id):
180 dec501fa Christos Stavrakakis
    log.debug("delete_volume volume_id: %s", volume_id)
181 dec501fa Christos Stavrakakis
182 dec501fa Christos Stavrakakis
    volume = util.get.volume(request.user_uniq, volume_id, for_update=True)
183 dec501fa Christos Stavrakakis
    volumes.delete(volume)
184 dec501fa Christos Stavrakakis
185 dec501fa Christos Stavrakakis
    return HttpResponse(status=202)
186 dec501fa Christos Stavrakakis
187 dec501fa Christos Stavrakakis
188 dec501fa Christos Stavrakakis
@api.api_method(http_method="GET", user_required=True, logger=log)
189 dec501fa Christos Stavrakakis
def get_volume(request, volume_id):
190 dec501fa Christos Stavrakakis
    log.debug('get_volume volume_id: %s', volume_id)
191 dec501fa Christos Stavrakakis
192 dec501fa Christos Stavrakakis
    volume = util.get.volume(request.user_uniq, volume_id)
193 dec501fa Christos Stavrakakis
194 dec501fa Christos Stavrakakis
    data = json.dumps({'volume': volume_to_dict(volume, detail=True)})
195 dec501fa Christos Stavrakakis
    return HttpResponse(data, content_type="application/json", status=200)
196 dec501fa Christos Stavrakakis
197 dec501fa Christos Stavrakakis
198 dec501fa Christos Stavrakakis
@api.api_method(http_method="PUT", user_required=True, logger=log)
199 dec501fa Christos Stavrakakis
def update_volume(request, volume_id):
200 dec501fa Christos Stavrakakis
    req = utils.get_request_dict(request)
201 dec501fa Christos Stavrakakis
    log.debug('update_volume volume_id: %s, request: %s', volume_id, req)
202 dec501fa Christos Stavrakakis
203 dec501fa Christos Stavrakakis
    volume = util.get.volume(request.user_uniq, volume_id, for_update=True)
204 dec501fa Christos Stavrakakis
205 dec501fa Christos Stavrakakis
    new_name = req.get("name")
206 dec501fa Christos Stavrakakis
    description = req.get("description")
207 dec501fa Christos Stavrakakis
208 dec501fa Christos Stavrakakis
    if new_name is None and description is None:
209 dec501fa Christos Stavrakakis
        raise faults.BadRequest("Nothing to update.")
210 dec501fa Christos Stavrakakis
211 dec501fa Christos Stavrakakis
    if new_name is not None:
212 dec501fa Christos Stavrakakis
        volume = volumes.rename(volume, new_name)
213 dec501fa Christos Stavrakakis
    if description is not None:
214 dec501fa Christos Stavrakakis
        volume = volumes.update_description(volume, description)
215 dec501fa Christos Stavrakakis
    data = json.dumps({'volume': volume_to_dict(volume, detail=True)})
216 dec501fa Christos Stavrakakis
    return HttpResponse(data, content_type="application/json", status=200)
217 dec501fa Christos Stavrakakis
218 dec501fa Christos Stavrakakis
219 dec501fa Christos Stavrakakis
def snapshot_to_dict(snapshot, detail=True):
220 dec501fa Christos Stavrakakis
    owner = snapshot["owner"]
221 dec501fa Christos Stavrakakis
    status = snapshot["status"]
222 dec501fa Christos Stavrakakis
    progress = snapshot["progress"]
223 dec501fa Christos Stavrakakis
    data = {
224 dec501fa Christos Stavrakakis
        "id": snapshot["uuid"],
225 dec501fa Christos Stavrakakis
        "size": int(snapshot["size"]) >> 30,  # gigabytes
226 dec501fa Christos Stavrakakis
        "name": snapshot["name"],
227 dec501fa Christos Stavrakakis
        "description": snapshot["description"],
228 dec501fa Christos Stavrakakis
        "status": status,
229 dec501fa Christos Stavrakakis
        "user_id": owner,
230 dec501fa Christos Stavrakakis
        "tenant_id": owner,
231 dec501fa Christos Stavrakakis
        "os-extended-snapshot-attribute:progress": progress,
232 dec501fa Christos Stavrakakis
        #"os-extended-snapshot-attribute:project_id": project,
233 dec501fa Christos Stavrakakis
        "created_at": utils.isoformat(date_parse(snapshot["created_at"])),
234 dec501fa Christos Stavrakakis
        "metadata": snapshot.get("metadata", {}),
235 dec501fa Christos Stavrakakis
        "volume_id": snapshot.get("volume_id"),
236 dec501fa Christos Stavrakakis
        "links": "",  # TODO fix links
237 dec501fa Christos Stavrakakis
    }
238 dec501fa Christos Stavrakakis
    return data
239 dec501fa Christos Stavrakakis
240 dec501fa Christos Stavrakakis
241 dec501fa Christos Stavrakakis
@api.api_method(http_method="POST", user_required=True, logger=log)
242 dec501fa Christos Stavrakakis
def create_snapshot(request):
243 dec501fa Christos Stavrakakis
    """Create a new Snapshot."""
244 dec501fa Christos Stavrakakis
245 dec501fa Christos Stavrakakis
    req = utils.get_request_dict(request)
246 dec501fa Christos Stavrakakis
    log.debug("create_snapshot %s", req)
247 dec501fa Christos Stavrakakis
248 dec501fa Christos Stavrakakis
    user_id = request.user_uniq
249 dec501fa Christos Stavrakakis
    # Get and validate 'name' parameter
250 dec501fa Christos Stavrakakis
    # TODO: auto generate name
251 dec501fa Christos Stavrakakis
    metadata = req.get("metadata", {})
252 dec501fa Christos Stavrakakis
    if not isinstance(metadata, dict):
253 dec501fa Christos Stavrakakis
        msg = "Snapshot 'metadata' needs to be a dictionary of key-value"\
254 dec501fa Christos Stavrakakis
              " pairs. '%s' can not be accepted." % metadata
255 dec501fa Christos Stavrakakis
        raise faults.BadRequest(msg)
256 dec501fa Christos Stavrakakis
257 dec501fa Christos Stavrakakis
    volume_id = req.get("volume_id", None)
258 dec501fa Christos Stavrakakis
    if volume_id is None:
259 dec501fa Christos Stavrakakis
        raise faults.BadRequest("'volume_id' attribute is missing.")
260 dec501fa Christos Stavrakakis
    volume = util.get_volume(user_id, volume_id, for_update=True,
261 dec501fa Christos Stavrakakis
                             exception=faults.BadRequest)
262 dec501fa Christos Stavrakakis
263 dec501fa Christos Stavrakakis
    name = req.get("name", None)
264 dec501fa Christos Stavrakakis
    if name is None:
265 dec501fa Christos Stavrakakis
        name = "snapshot_volume_%s_%s" %\
266 dec501fa Christos Stavrakakis
            (volume.id, str(datetime.datetime.now()))
267 dec501fa Christos Stavrakakis
    description = req.get("description", "")
268 dec501fa Christos Stavrakakis
269 dec501fa Christos Stavrakakis
    # TODO: What to do with force ?
270 dec501fa Christos Stavrakakis
    force = req.get("force", False)
271 dec501fa Christos Stavrakakis
    if not isinstance(force, bool):
272 dec501fa Christos Stavrakakis
        raise faults.BadRequest("Invalid value for 'force' attribute.")
273 dec501fa Christos Stavrakakis
274 dec501fa Christos Stavrakakis
    snapshot = snapshots.create(user_id=user_id, volume=volume, name=name,
275 dec501fa Christos Stavrakakis
                                description=description, metadata=metadata,
276 dec501fa Christos Stavrakakis
                                force=force)
277 dec501fa Christos Stavrakakis
278 dec501fa Christos Stavrakakis
    # Render response
279 dec501fa Christos Stavrakakis
    data = json.dumps(dict(snapshot=snapshot_to_dict(snapshot, detail=False)))
280 dec501fa Christos Stavrakakis
    return HttpResponse(data, status=200)  # TOO: Maybe 202 ?
281 dec501fa Christos Stavrakakis
282 dec501fa Christos Stavrakakis
283 dec501fa Christos Stavrakakis
@api.api_method(http_method="GET", user_required=True, logger=log)
284 dec501fa Christos Stavrakakis
def list_snapshots(request, detail=False):
285 dec501fa Christos Stavrakakis
    log.debug('list_snapshots detail=%s', detail)
286 dec501fa Christos Stavrakakis
    since = utils.isoparse(request.GET.get('changes-since'))
287 dec501fa Christos Stavrakakis
    with image_backend(request.user_uniq) as backend:
288 dec501fa Christos Stavrakakis
        snapshots = backend.list_snapshots()
289 dec501fa Christos Stavrakakis
        if since:
290 dec501fa Christos Stavrakakis
            updated_since = lambda snap:\
291 dec501fa Christos Stavrakakis
                date_parse(snap["updated_at"]) >= since
292 dec501fa Christos Stavrakakis
            snapshots = ifilter(updated_since, snapshots)
293 dec501fa Christos Stavrakakis
            if not snapshots:
294 dec501fa Christos Stavrakakis
                return HttpResponse(status=304)
295 dec501fa Christos Stavrakakis
296 dec501fa Christos Stavrakakis
    snapshots = sorted(snapshots, key=lambda x: x['id'])
297 dec501fa Christos Stavrakakis
    snapshots_dict = [snapshot_to_dict(snapshot, detail)
298 dec501fa Christos Stavrakakis
                      for snapshot in snapshots]
299 dec501fa Christos Stavrakakis
300 dec501fa Christos Stavrakakis
    data = json.dumps(dict(snapshots=snapshots_dict))
301 dec501fa Christos Stavrakakis
302 dec501fa Christos Stavrakakis
    return HttpResponse(data, status=200)
303 dec501fa Christos Stavrakakis
304 dec501fa Christos Stavrakakis
305 dec501fa Christos Stavrakakis
@api.api_method(http_method="DELETE", user_required=True, logger=log)
306 dec501fa Christos Stavrakakis
def delete_snapshot(request, snapshot_id):
307 dec501fa Christos Stavrakakis
    log.debug("delete_snapshot snapshot_id: %s", snapshot_id)
308 dec501fa Christos Stavrakakis
309 dec501fa Christos Stavrakakis
    snapshot = util.get_snapshot(request.user_uniq, snapshot_id)
310 dec501fa Christos Stavrakakis
    snapshots.delete(snapshot)
311 dec501fa Christos Stavrakakis
312 dec501fa Christos Stavrakakis
    return HttpResponse(status=202)
313 dec501fa Christos Stavrakakis
314 dec501fa Christos Stavrakakis
315 dec501fa Christos Stavrakakis
@api.api_method(http_method="GET", user_required=True, logger=log)
316 dec501fa Christos Stavrakakis
def get_snapshot(request, snapshot_id):
317 dec501fa Christos Stavrakakis
    log.debug('get_snapshot snapshot_id: %s', snapshot_id)
318 dec501fa Christos Stavrakakis
319 dec501fa Christos Stavrakakis
    snapshot = util.get_snapshot(request.user_uniq, snapshot_id)
320 dec501fa Christos Stavrakakis
    data = json.dumps({'snapshot': snapshot_to_dict(snapshot, detail=True)})
321 dec501fa Christos Stavrakakis
    return HttpResponse(data, content_type="application/json", status=200)
322 dec501fa Christos Stavrakakis
323 dec501fa Christos Stavrakakis
324 dec501fa Christos Stavrakakis
@api.api_method(http_method="PUT", user_required=True, logger=log)
325 dec501fa Christos Stavrakakis
def update_snapshot(request, snapshot_id):
326 dec501fa Christos Stavrakakis
    req = utils.get_request_dict(request)
327 dec501fa Christos Stavrakakis
    log.debug('update_snapshot snapshot_id: %s, request: %s', snapshot_id, req)
328 dec501fa Christos Stavrakakis
    snapshot = util.get_snapshot(request.user_uniq, snapshot_id)
329 dec501fa Christos Stavrakakis
    # TODO
330 dec501fa Christos Stavrakakis
    #snapshot.name = req.get("name", snapshot.name)
331 dec501fa Christos Stavrakakis
    #snapshot.description = req.get("description", snapshot.description)
332 dec501fa Christos Stavrakakis
    #snapshot.save()
333 dec501fa Christos Stavrakakis
    data = json.dumps({'snapshot': snapshot_to_dict(snapshot, detail=True)})
334 dec501fa Christos Stavrakakis
    return HttpResponse(data, content_type="application/json", status=200)