Revision 5d805533 snf-cyclades-app/synnefo/volume/volumes.py

b/snf-cyclades-app/synnefo/volume/volumes.py
1 1
import logging
2 2

  
3 3
from django.db import transaction
4
from synnefo.db.models import Volume
5 4
from snf_django.lib.api import faults
5
from synnefo.db.models import Volume
6 6
from synnefo.volume import util
7
from synnefo.logic import backend, servers
7
from synnefo.logic import server_attachments
8 8

  
9 9
log = logging.getLogger(__name__)
10 10

  
......
14 14
           source_volume_id=None, source_snapshot_id=None,
15 15
           source_image_id=None, metadata=None):
16 16

  
17
    # Currently we cannot create volumes without being attached to a server
17 18
    if server_id is None:
18 19
        raise faults.BadRequest("Volume must be attached to server")
19 20
    server = util.get_server(user_id, server_id, for_update=True,
......
25 26
    if len(sources) > 1:
26 27
        raise faults.BadRequest("Volume can not have more than one source!")
27 28

  
28
    # Only ext_ disk template supports cloning from another source
29
    if source_volume_id is not None:
30
        source_type = "volume"
31
        source_uuid = source_volume_id
32
    elif source_snapshot_id is not None:
33
        source_type = "snapshot"
34
        source_uuid = source_snapshot_id
35
    elif source_image_id is not None:
36
        source_type = "image"
37
        source_uuid = source_image_id
38
    else:
39
        source_type = source_uuid = None
40

  
41
    volume = _create_volume(server, user_id, size, source_type, source_uuid,
42
                            name, description, index=None)
43

  
44
    if metadata is not None:
45
        for meta_key, meta_val in metadata.items():
46
            volume.metadata.create(key=meta_key, value=meta_val)
47

  
48
    server_attachments.attach_volume(server, volume)
49

  
50
    return volume
51

  
52

  
53
def _create_volume(server, user_id, size, source_type, source_uuid,
54
                   name=None, description=None, index=None,
55
                   delete_on_termination=True):
56

  
57
    # Only ext_ disk template supports cloning from another source. Otherwise
58
    # is must be the root volume so that 'snf-image' fill the volume
29 59
    disk_template = server.flavor.disk_template
30
    if not disk_template.startswith("ext_") and sources:
60
    can_have_source = (index == 0 or disk_template.startswith("ext_"))
61
    if not can_have_source and source_type != "blank":
31 62
        msg = ("Volumes of '%s' disk template cannot have a source" %
32 63
               disk_template)
33 64
        raise faults.BadRequest(msg)
34 65

  
35
    origin = None
36
    source = None
37
    if source_volume_id is not None:
38
        source_volume = util.get_volume(user_id, source_volume_id,
66
    # TODO: Check Volume/Snapshot Status
67
    if source_type == "volume":
68
        source_volume = util.get_volume(user_id, source_uuid,
39 69
                                        for_update=True,
40 70
                                        exception=faults.BadRequest)
41
        # Check that volume is ready to be snapshotted
42
        if source_volume.status != "AVAILABLE":
43
            msg = ("Cannot take a snapshot while snapshot is in '%s' state"
44
                   % source_volume.status)
45
            raise faults.BadRequest(msg)
46
        source = Volume.prefix_source(source_volume_id, source_type="volume")
71
        if source_volume.status != "IN_USE":
72
            raise faults.BadRequest("Cannot clone volume while it is in '%s'"
73
                                    " status" % source_volume.status)
74
        # If no size is specified, use the size of the volume
75
        if size is None:
76
            size = source_volume.size
77
        elif size < source_volume.size:
78
            raise faults.BadRequest("Volume size cannot be smaller than the"
79
                                    " source volume")
80
        source = Volume.prefix_source(source_uuid, source_type="volume")
47 81
        origin = source_volume.backend_volume_uuid
48
    elif source_snapshot_id is not None:
49
        source_snapshot = util.get_snapshot(user_id, source_snapshot_id,
82
    elif source_type == "snapshot":
83
        source_snapshot = util.get_snapshot(user_id, source_uuid,
50 84
                                            exception=faults.BadRequest)
51
        # TODO: Check the state of the snapshot!!
52
        source = Volume.prefix_source(source_snapshot_id,
85
        source = Volume.prefix_source(source_uuid,
53 86
                                      source_type="snapshot")
87
        if size is None:
88
            raise faults.BadRequest("Volume size is required")
89
        elif (size << 30) < int(source_snapshot["size"]):
90
            raise faults.BadRequest("Volume size '%s' is smaller than"
91
                                    " snapshot's size '%s'"
92
                                    % (size << 30, source_snapshot["size"]))
54 93
        origin = source_snapshot["checksum"]
55
    elif source_image_id is not None:
56
        source_image = util.get_image(user_id, source_image_id,
94
    elif source_type == "image":
95
        source_image = util.get_image(user_id, source_uuid,
57 96
                                      exception=faults.BadRequest)
58
        source = Volume.prefix_source(source_image_id, source_type="image")
97
        if size is None:
98
            raise faults.BadRequest("Volume size is required")
99
        elif (size << 30) < int(source_image["size"]):
100
            raise faults.BadRequest("Volume size '%s' is smaller than"
101
                                    " image's size '%s'"
102
                                    % (size << 30, source_image["size"]))
103
        source = Volume.prefix_source(source_uuid, source_type="image")
59 104
        origin = source_image["checksum"]
105
    elif source_type == "blank":
106
        if size is None:
107
            raise faults.BadRequest("Volume size is required")
108
        source = origin = None
109
    else:
110
        raise faults.BadRequest("Unknwon source type")
60 111

  
61 112
    volume = Volume.objects.create(userid=user_id,
62 113
                                   size=size,
63 114
                                   name=name,
64 115
                                   machine=server,
65 116
                                   description=description,
117
                                   delete_on_termination=delete_on_termination,
66 118
                                   source=source,
67 119
                                   origin=origin,
68 120
                                   #volume_type=volume_type,
69 121
                                   status="CREATING")
70

  
71
    if metadata is not None:
72
        for meta_key, meta_val in metadata.items():
73
            volume.metadata.create(key=meta_key, value=meta_val)
74

  
75
    servers.attach_volume(server, volume)
76

  
77 122
    return volume
78 123

  
79 124

  
......
83 128
    # A volume is deleted by detaching it from the server that is attached.
84 129
    # Deleting a detached volume is not implemented.
85 130
    if volume.machine_id is not None:
86
        servers.detach_volume(volume.machine, volume)
131
        server_attachments.detach_volume(volume.machine, volume)
87 132
        log.info("Detach volume '%s' from server '%s', job: %s",
88 133
                 volume.id, volume.machine_id, volume.backendjobid)
89 134
    else:

Also available in: Unified diff