root / snf-cyclades-app / synnefo / volume / volumes.py @ 5d805533
History | View | Annotate | Download (6 kB)
1 | dec501fa | Christos Stavrakakis | import logging |
---|---|---|---|
2 | dec501fa | Christos Stavrakakis | |
3 | dec501fa | Christos Stavrakakis | from django.db import transaction |
4 | dec501fa | Christos Stavrakakis | from snf_django.lib.api import faults |
5 | 5d805533 | Christos Stavrakakis | from synnefo.db.models import Volume |
6 | dec501fa | Christos Stavrakakis | from synnefo.volume import util |
7 | 5d805533 | Christos Stavrakakis | from synnefo.logic import server_attachments |
8 | dec501fa | Christos Stavrakakis | |
9 | dec501fa | Christos Stavrakakis | log = logging.getLogger(__name__) |
10 | dec501fa | Christos Stavrakakis | |
11 | dec501fa | Christos Stavrakakis | |
12 | dec501fa | Christos Stavrakakis | @transaction.commit_on_success
|
13 | dec501fa | Christos Stavrakakis | def create(user_id, size, server_id, name=None, description=None, |
14 | dec501fa | Christos Stavrakakis | source_volume_id=None, source_snapshot_id=None, |
15 | dec501fa | Christos Stavrakakis | source_image_id=None, metadata=None): |
16 | dec501fa | Christos Stavrakakis | |
17 | 5d805533 | Christos Stavrakakis | # Currently we cannot create volumes without being attached to a server
|
18 | dec501fa | Christos Stavrakakis | if server_id is None: |
19 | dec501fa | Christos Stavrakakis | raise faults.BadRequest("Volume must be attached to server") |
20 | dec501fa | Christos Stavrakakis | server = util.get_server(user_id, server_id, for_update=True,
|
21 | dec501fa | Christos Stavrakakis | exception=faults.BadRequest) |
22 | dec501fa | Christos Stavrakakis | |
23 | dec501fa | Christos Stavrakakis | # Assert that not more than one source are used
|
24 | dec501fa | Christos Stavrakakis | sources = filter(lambda x: x is not None, |
25 | dec501fa | Christos Stavrakakis | [source_volume_id, source_snapshot_id, source_image_id]) |
26 | dec501fa | Christos Stavrakakis | if len(sources) > 1: |
27 | dec501fa | Christos Stavrakakis | raise faults.BadRequest("Volume can not have more than one source!") |
28 | dec501fa | Christos Stavrakakis | |
29 | 5d805533 | Christos Stavrakakis | if source_volume_id is not None: |
30 | 5d805533 | Christos Stavrakakis | source_type = "volume"
|
31 | 5d805533 | Christos Stavrakakis | source_uuid = source_volume_id |
32 | 5d805533 | Christos Stavrakakis | elif source_snapshot_id is not None: |
33 | 5d805533 | Christos Stavrakakis | source_type = "snapshot"
|
34 | 5d805533 | Christos Stavrakakis | source_uuid = source_snapshot_id |
35 | 5d805533 | Christos Stavrakakis | elif source_image_id is not None: |
36 | 5d805533 | Christos Stavrakakis | source_type = "image"
|
37 | 5d805533 | Christos Stavrakakis | source_uuid = source_image_id |
38 | 5d805533 | Christos Stavrakakis | else:
|
39 | 5d805533 | Christos Stavrakakis | source_type = source_uuid = None
|
40 | 5d805533 | Christos Stavrakakis | |
41 | 5d805533 | Christos Stavrakakis | volume = _create_volume(server, user_id, size, source_type, source_uuid, |
42 | 5d805533 | Christos Stavrakakis | name, description, index=None)
|
43 | 5d805533 | Christos Stavrakakis | |
44 | 5d805533 | Christos Stavrakakis | if metadata is not None: |
45 | 5d805533 | Christos Stavrakakis | for meta_key, meta_val in metadata.items(): |
46 | 5d805533 | Christos Stavrakakis | volume.metadata.create(key=meta_key, value=meta_val) |
47 | 5d805533 | Christos Stavrakakis | |
48 | 5d805533 | Christos Stavrakakis | server_attachments.attach_volume(server, volume) |
49 | 5d805533 | Christos Stavrakakis | |
50 | 5d805533 | Christos Stavrakakis | return volume
|
51 | 5d805533 | Christos Stavrakakis | |
52 | 5d805533 | Christos Stavrakakis | |
53 | 5d805533 | Christos Stavrakakis | def _create_volume(server, user_id, size, source_type, source_uuid, |
54 | 5d805533 | Christos Stavrakakis | name=None, description=None, index=None, |
55 | 5d805533 | Christos Stavrakakis | delete_on_termination=True):
|
56 | 5d805533 | Christos Stavrakakis | |
57 | 5d805533 | Christos Stavrakakis | # Only ext_ disk template supports cloning from another source. Otherwise
|
58 | 5d805533 | Christos Stavrakakis | # is must be the root volume so that 'snf-image' fill the volume
|
59 | 5f90e24c | Christos Stavrakakis | disk_template = server.flavor.disk_template |
60 | 5d805533 | Christos Stavrakakis | can_have_source = (index == 0 or disk_template.startswith("ext_")) |
61 | 5d805533 | Christos Stavrakakis | if not can_have_source and source_type != "blank": |
62 | 5f90e24c | Christos Stavrakakis | msg = ("Volumes of '%s' disk template cannot have a source" %
|
63 | 5f90e24c | Christos Stavrakakis | disk_template) |
64 | 5f90e24c | Christos Stavrakakis | raise faults.BadRequest(msg)
|
65 | 5f90e24c | Christos Stavrakakis | |
66 | 5d805533 | Christos Stavrakakis | # TODO: Check Volume/Snapshot Status
|
67 | 5d805533 | Christos Stavrakakis | if source_type == "volume": |
68 | 5d805533 | Christos Stavrakakis | source_volume = util.get_volume(user_id, source_uuid, |
69 | dec501fa | Christos Stavrakakis | for_update=True,
|
70 | dec501fa | Christos Stavrakakis | exception=faults.BadRequest) |
71 | 5d805533 | Christos Stavrakakis | if source_volume.status != "IN_USE": |
72 | 5d805533 | Christos Stavrakakis | raise faults.BadRequest("Cannot clone volume while it is in '%s'" |
73 | 5d805533 | Christos Stavrakakis | " status" % source_volume.status)
|
74 | 5d805533 | Christos Stavrakakis | # If no size is specified, use the size of the volume
|
75 | 5d805533 | Christos Stavrakakis | if size is None: |
76 | 5d805533 | Christos Stavrakakis | size = source_volume.size |
77 | 5d805533 | Christos Stavrakakis | elif size < source_volume.size:
|
78 | 5d805533 | Christos Stavrakakis | raise faults.BadRequest("Volume size cannot be smaller than the" |
79 | 5d805533 | Christos Stavrakakis | " source volume")
|
80 | 5d805533 | Christos Stavrakakis | source = Volume.prefix_source(source_uuid, source_type="volume")
|
81 | 5f90e24c | Christos Stavrakakis | origin = source_volume.backend_volume_uuid |
82 | 5d805533 | Christos Stavrakakis | elif source_type == "snapshot": |
83 | 5d805533 | Christos Stavrakakis | source_snapshot = util.get_snapshot(user_id, source_uuid, |
84 | dec501fa | Christos Stavrakakis | exception=faults.BadRequest) |
85 | 5d805533 | Christos Stavrakakis | source = Volume.prefix_source(source_uuid, |
86 | c19ad1e9 | Christos Stavrakakis | source_type="snapshot")
|
87 | 5d805533 | Christos Stavrakakis | if size is None: |
88 | 5d805533 | Christos Stavrakakis | raise faults.BadRequest("Volume size is required") |
89 | 5d805533 | Christos Stavrakakis | elif (size << 30) < int(source_snapshot["size"]): |
90 | 5d805533 | Christos Stavrakakis | raise faults.BadRequest("Volume size '%s' is smaller than" |
91 | 5d805533 | Christos Stavrakakis | " snapshot's size '%s'"
|
92 | 5d805533 | Christos Stavrakakis | % (size << 30, source_snapshot["size"])) |
93 | 5f90e24c | Christos Stavrakakis | origin = source_snapshot["checksum"]
|
94 | 5d805533 | Christos Stavrakakis | elif source_type == "image": |
95 | 5d805533 | Christos Stavrakakis | source_image = util.get_image(user_id, source_uuid, |
96 | dec501fa | Christos Stavrakakis | exception=faults.BadRequest) |
97 | 5d805533 | Christos Stavrakakis | if size is None: |
98 | 5d805533 | Christos Stavrakakis | raise faults.BadRequest("Volume size is required") |
99 | 5d805533 | Christos Stavrakakis | elif (size << 30) < int(source_image["size"]): |
100 | 5d805533 | Christos Stavrakakis | raise faults.BadRequest("Volume size '%s' is smaller than" |
101 | 5d805533 | Christos Stavrakakis | " image's size '%s'"
|
102 | 5d805533 | Christos Stavrakakis | % (size << 30, source_image["size"])) |
103 | 5d805533 | Christos Stavrakakis | source = Volume.prefix_source(source_uuid, source_type="image")
|
104 | 5f90e24c | Christos Stavrakakis | origin = source_image["checksum"]
|
105 | 5d805533 | Christos Stavrakakis | elif source_type == "blank": |
106 | 5d805533 | Christos Stavrakakis | if size is None: |
107 | 5d805533 | Christos Stavrakakis | raise faults.BadRequest("Volume size is required") |
108 | 5d805533 | Christos Stavrakakis | source = origin = None
|
109 | 5d805533 | Christos Stavrakakis | else:
|
110 | 5d805533 | Christos Stavrakakis | raise faults.BadRequest("Unknwon source type") |
111 | dec501fa | Christos Stavrakakis | |
112 | dec501fa | Christos Stavrakakis | volume = Volume.objects.create(userid=user_id, |
113 | dec501fa | Christos Stavrakakis | size=size, |
114 | dec501fa | Christos Stavrakakis | name=name, |
115 | dec501fa | Christos Stavrakakis | machine=server, |
116 | dec501fa | Christos Stavrakakis | description=description, |
117 | 5d805533 | Christos Stavrakakis | delete_on_termination=delete_on_termination, |
118 | 5f90e24c | Christos Stavrakakis | source=source, |
119 | 5f90e24c | Christos Stavrakakis | origin=origin, |
120 | dec501fa | Christos Stavrakakis | #volume_type=volume_type,
|
121 | dec501fa | Christos Stavrakakis | status="CREATING")
|
122 | dec501fa | Christos Stavrakakis | return volume
|
123 | dec501fa | Christos Stavrakakis | |
124 | dec501fa | Christos Stavrakakis | |
125 | dec501fa | Christos Stavrakakis | @transaction.commit_on_success
|
126 | dec501fa | Christos Stavrakakis | def delete(volume): |
127 | 5f90e24c | Christos Stavrakakis | """Delete a Volume"""
|
128 | 5f90e24c | Christos Stavrakakis | # A volume is deleted by detaching it from the server that is attached.
|
129 | 5f90e24c | Christos Stavrakakis | # Deleting a detached volume is not implemented.
|
130 | 5f90e24c | Christos Stavrakakis | if volume.machine_id is not None: |
131 | 5d805533 | Christos Stavrakakis | server_attachments.detach_volume(volume.machine, volume) |
132 | 5f90e24c | Christos Stavrakakis | log.info("Detach volume '%s' from server '%s', job: %s",
|
133 | 5f90e24c | Christos Stavrakakis | volume.id, volume.machine_id, volume.backendjobid) |
134 | 5f90e24c | Christos Stavrakakis | else:
|
135 | 5f90e24c | Christos Stavrakakis | raise faults.BadRequest("Cannot delete a detached volume") |
136 | dec501fa | Christos Stavrakakis | |
137 | dec501fa | Christos Stavrakakis | return volume
|
138 | dec501fa | Christos Stavrakakis | |
139 | dec501fa | Christos Stavrakakis | |
140 | dec501fa | Christos Stavrakakis | @transaction.commit_on_success
|
141 | dec501fa | Christos Stavrakakis | def rename(volume, new_name): |
142 | dec501fa | Christos Stavrakakis | volume.name = new_name |
143 | dec501fa | Christos Stavrakakis | volume.save() |
144 | dec501fa | Christos Stavrakakis | return volume
|
145 | dec501fa | Christos Stavrakakis | |
146 | dec501fa | Christos Stavrakakis | |
147 | dec501fa | Christos Stavrakakis | @transaction.commit_on_success
|
148 | dec501fa | Christos Stavrakakis | def update_description(volume, new_description): |
149 | dec501fa | Christos Stavrakakis | volume.description = new_description |
150 | dec501fa | Christos Stavrakakis | volume.save() |
151 | dec501fa | Christos Stavrakakis | return volume |