Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (5.1 kB)

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

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

48 5d805533 Christos Stavrakakis
    """
49 5d805533 Christos Stavrakakis
    # Check volume state
50 5d805533 Christos Stavrakakis
    if volume.status not in ["AVAILABLE", "CREATING"]:
51 5d805533 Christos Stavrakakis
        raise faults.BadRequest("Cannot attach volume while volume is in"
52 5d805533 Christos Stavrakakis
                                " '%s' status." % volume.status)
53 5d805533 Christos Stavrakakis
54 5d805533 Christos Stavrakakis
    # Check that disk templates are the same
55 5d805533 Christos Stavrakakis
    if volume.disk_template != vm.flavor.disk_template:
56 5d805533 Christos Stavrakakis
        msg = ("Volume and server must have the same disk template. Volume has"
57 5d805533 Christos Stavrakakis
               " disk template '%s' while server has '%s'"
58 5d805533 Christos Stavrakakis
               % (volume.disk_template, vm.flavor.disk_template))
59 5d805533 Christos Stavrakakis
        raise faults.BadRequest(msg)
60 5d805533 Christos Stavrakakis
61 5d805533 Christos Stavrakakis
    # Check maximum disk per instance hard limit
62 d05e5324 Christos Stavrakakis
    vm_volumes_num = vm.volumes.filter(deleted=False).count()
63 d05e5324 Christos Stavrakakis
    if vm_volumes_num == settings.GANETI_MAX_DISKS_PER_INSTANCE:
64 5d805533 Christos Stavrakakis
        raise faults.BadRequest("Maximum volumes per server limit reached")
65 5d805533 Christos Stavrakakis
66 d05e5324 Christos Stavrakakis
    if volume.status == "CREATING":
67 d05e5324 Christos Stavrakakis
        action_fields = {"disks": [("add", volume, {})]}
68 d05e5324 Christos Stavrakakis
    comm = commands.server_command("ATTACH_VOLUME",
69 d05e5324 Christos Stavrakakis
                                   action_fields=action_fields)
70 d05e5324 Christos Stavrakakis
    return comm(_attach_volume)(vm, volume)
71 d05e5324 Christos Stavrakakis
72 5d805533 Christos Stavrakakis
73 d05e5324 Christos Stavrakakis
def _attach_volume(vm, volume):
74 d05e5324 Christos Stavrakakis
    """Attach a Volume to a VM and update the Volume's status."""
75 d05e5324 Christos Stavrakakis
    jobid = backend.attach_volume(vm, volume)
76 5d805533 Christos Stavrakakis
    log.info("Attached volume '%s' to server '%s'. JobID: '%s'", volume.id,
77 5d805533 Christos Stavrakakis
             volume.machine_id, jobid)
78 5d805533 Christos Stavrakakis
    volume.backendjobid = jobid
79 5d805533 Christos Stavrakakis
    volume.machine = vm
80 d05e5324 Christos Stavrakakis
    if volume.status == "AVAILALBE":
81 d05e5324 Christos Stavrakakis
        volume.status = "ATTACHING"
82 d05e5324 Christos Stavrakakis
    else:
83 d05e5324 Christos Stavrakakis
        volume.status = "CREATING"
84 5d805533 Christos Stavrakakis
    volume.save()
85 5d805533 Christos Stavrakakis
    return jobid
86 5d805533 Christos Stavrakakis
87 5d805533 Christos Stavrakakis
88 5d805533 Christos Stavrakakis
def detach_volume(vm, volume):
89 d05e5324 Christos Stavrakakis
    """Detach a Volume from a VM
90 5d805533 Christos Stavrakakis

91 5d805533 Christos Stavrakakis
    The volume must be in 'IN_USE' status in order to be detached. Also,
92 5d805533 Christos Stavrakakis
    the root volume of the instance (index=0) can not be detached. This
93 5d805533 Christos Stavrakakis
    function will send the corresponding job to Ganeti backend and update the
94 5d805533 Christos Stavrakakis
    status of the volume to 'DETACHING'.
95 5d805533 Christos Stavrakakis

96 5d805533 Christos Stavrakakis
    """
97 5d805533 Christos Stavrakakis
98 5d805533 Christos Stavrakakis
    _check_attachment(vm, volume)
99 d05e5324 Christos Stavrakakis
    if volume.status not in ["IN_USE", "ERROR"]:
100 5d805533 Christos Stavrakakis
        raise faults.BadRequest("Cannot detach volume while volume is in"
101 5d805533 Christos Stavrakakis
                                " '%s' status." % volume.status)
102 5d805533 Christos Stavrakakis
    if volume.index == 0:
103 5d805533 Christos Stavrakakis
        raise faults.BadRequest("Cannot detach the root volume of a server")
104 d05e5324 Christos Stavrakakis
105 d05e5324 Christos Stavrakakis
    action_fields = {"disks": [("remove", volume, {})]}
106 d05e5324 Christos Stavrakakis
    comm = commands.server_command("DETACH_VOLUME",
107 d05e5324 Christos Stavrakakis
                                   action_fields=action_fields)
108 d05e5324 Christos Stavrakakis
    return comm(_detach_volume)(vm, volume)
109 d05e5324 Christos Stavrakakis
110 d05e5324 Christos Stavrakakis
111 d05e5324 Christos Stavrakakis
def _detach_volume(vm, volume):
112 d05e5324 Christos Stavrakakis
    """Detach a Volume from a VM and update the Volume's status"""
113 5d805533 Christos Stavrakakis
    jobid = backend.detach_volume(vm, volume)
114 5d805533 Christos Stavrakakis
    log.info("Detached volume '%s' from server '%s'. JobID: '%s'", volume.id,
115 5d805533 Christos Stavrakakis
             volume.machine_id, jobid)
116 5d805533 Christos Stavrakakis
    volume.backendjobid = jobid
117 d05e5324 Christos Stavrakakis
    if volume.delete_on_termination:
118 d05e5324 Christos Stavrakakis
        volume.status = "DELETING"
119 d05e5324 Christos Stavrakakis
    else:
120 d05e5324 Christos Stavrakakis
        volume.status = "DETACHING"
121 5d805533 Christos Stavrakakis
    volume.save()
122 5d805533 Christos Stavrakakis
    return jobid
123 5d805533 Christos Stavrakakis
124 5d805533 Christos Stavrakakis
125 5d805533 Christos Stavrakakis
def _check_attachment(vm, volume):
126 d05e5324 Christos Stavrakakis
    """Check that the Volume is attached to the VM"""
127 5d805533 Christos Stavrakakis
    if volume.machine_id != vm.id:
128 5d805533 Christos Stavrakakis
        raise faults.BadRequest("Volume '%s' is not attached to server '%s'"
129 5d805533 Christos Stavrakakis
                                % volume.id, vm.id)