Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / logic / server_attachments.py @ ec987d7d

History | View | Annotate | Download (4.4 kB)

1
# Copyright 2011, 2012, 2013 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or without
4
# modification, are permitted provided that the following conditions
5
# are met:
6
#
7
#   1. Redistributions of source code must retain the above copyright
8
#      notice, this list of conditions and the following disclaimer.
9
#
10
#  2. Redistributions in binary form must reproduce the above copyright
11
#     notice, this list of conditions and the following disclaimer in the
12
#     documentation and/or other materials provided with the distribution.
13
#
14
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
15
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
18
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
# SUCH DAMAGE.
25
#
26
# The views and conclusions contained in the software and documentation are
27
# those of the authors and should not be interpreted as representing official
28
# policies, either expressed or implied, of GRNET S.A.
29

    
30
import logging
31

    
32
from snf_django.lib.api import faults
33
from django.conf import settings
34
from synnefo.logic import backend, commands
35

    
36
log = logging.getLogger(__name__)
37

    
38

    
39
@commands.server_command("ATTACH_VOLUME")
40
def attach_volume(vm, volume):
41
    """Attach a volume to a server.
42

43
    The volume must be in 'AVAILABLE' status in order to be attached. Also,
44
    number of the volumes that are attached to the server must remain less
45
    than 'GANETI_MAX_DISKS_PER_INSTANCE' setting. This function will send
46
    the corresponding job to Ganeti backend and update the status of the
47
    volume to 'ATTACHING'.
48

49
    """
50
    # Check volume state
51
    if volume.status not in ["AVAILABLE", "CREATING"]:
52
        raise faults.BadRequest("Cannot attach volume while volume is in"
53
                                " '%s' status." % volume.status)
54

    
55
    # Check that disk templates are the same
56
    if volume.disk_template != vm.flavor.disk_template:
57
        msg = ("Volume and server must have the same disk template. Volume has"
58
               " disk template '%s' while server has '%s'"
59
               % (volume.disk_template, vm.flavor.disk_template))
60
        raise faults.BadRequest(msg)
61

    
62
    # Check maximum disk per instance hard limit
63
    if vm.volumes.filter(deleted=False).count() == settings.GANETI_MAX_DISKS_PER_INSTANCE:
64
        raise faults.BadRequest("Maximum volumes per server limit reached")
65

    
66
    jobid = backend.attach_volume(vm, volume)
67

    
68
    log.info("Attached volume '%s' to server '%s'. JobID: '%s'", volume.id,
69
             volume.machine_id, jobid)
70

    
71
    volume.backendjobid = jobid
72
    volume.machine = vm
73
    volume.status = "ATTACHING"
74
    volume.save()
75
    return jobid
76

    
77

    
78
@commands.server_command("DETACH_VOLUME")
79
def detach_volume(vm, volume):
80
    """Detach a volume to a server.
81

82
    The volume must be in 'IN_USE' status in order to be detached. Also,
83
    the root volume of the instance (index=0) can not be detached. This
84
    function will send the corresponding job to Ganeti backend and update the
85
    status of the volume to 'DETACHING'.
86

87
    """
88

    
89
    _check_attachment(vm, volume)
90
    if volume.status != "IN_USE":
91
        #TODO: Maybe allow other statuses as well ?
92
        raise faults.BadRequest("Cannot detach volume while volume is in"
93
                                " '%s' status." % volume.status)
94
    if volume.index == 0:
95
        raise faults.BadRequest("Cannot detach the root volume of a server")
96
    jobid = backend.detach_volume(vm, volume)
97
    log.info("Detached volume '%s' from server '%s'. JobID: '%s'", volume.id,
98
             volume.machine_id, jobid)
99
    volume.backendjobid = jobid
100
    volume.status = "DETACHING"
101
    volume.save()
102
    return jobid
103

    
104

    
105
def _check_attachment(vm, volume):
106
    """Check that volume is attached to vm."""
107
    if volume.machine_id != vm.id:
108
        raise faults.BadRequest("Volume '%s' is not attached to server '%s'"
109
                                % volume.id, vm.id)