Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / logic / backend.py @ f5b4f2a3

History | View | Annotate | Download (14.8 kB)

1 adee02b8 Giorgos Verigakis
# Copyright 2011 GRNET S.A. All rights reserved.
2 37ca953f Christodoulos Psaltis
#
3 adee02b8 Giorgos Verigakis
# Redistribution and use in source and binary forms, with or
4 adee02b8 Giorgos Verigakis
# without modification, are permitted provided that the following
5 adee02b8 Giorgos Verigakis
# conditions are met:
6 37ca953f Christodoulos Psaltis
#
7 adee02b8 Giorgos Verigakis
#   1. Redistributions of source code must retain the above
8 adee02b8 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
9 adee02b8 Giorgos Verigakis
#      disclaimer.
10 37ca953f Christodoulos Psaltis
#
11 adee02b8 Giorgos Verigakis
#   2. Redistributions in binary form must reproduce the above
12 adee02b8 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
13 adee02b8 Giorgos Verigakis
#      disclaimer in the documentation and/or other materials
14 adee02b8 Giorgos Verigakis
#      provided with the distribution.
15 37ca953f Christodoulos Psaltis
#
16 adee02b8 Giorgos Verigakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 adee02b8 Giorgos Verigakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 adee02b8 Giorgos Verigakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 adee02b8 Giorgos Verigakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 adee02b8 Giorgos Verigakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 adee02b8 Giorgos Verigakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 adee02b8 Giorgos Verigakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 adee02b8 Giorgos Verigakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 adee02b8 Giorgos Verigakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 adee02b8 Giorgos Verigakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 adee02b8 Giorgos Verigakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 adee02b8 Giorgos Verigakis
# POSSIBILITY OF SUCH DAMAGE.
28 37ca953f Christodoulos Psaltis
#
29 adee02b8 Giorgos Verigakis
# The views and conclusions contained in the software and
30 adee02b8 Giorgos Verigakis
# documentation are those of the authors and should not be
31 adee02b8 Giorgos Verigakis
# interpreted as representing official policies, either expressed
32 adee02b8 Giorgos Verigakis
# or implied, of GRNET S.A.
33 02feca11 Vassilios Karakoidas
34 2b1db26f Giorgos Verigakis
import json
35 2b1db26f Giorgos Verigakis
36 2035039b Giorgos Verigakis
from logging import getLogger
37 529178b1 Giorgos Verigakis
from django.conf import settings
38 207b70d5 Giorgos Verigakis
from django.db import transaction
39 207b70d5 Giorgos Verigakis
40 f5b4f2a3 Christos Stavrakakis
from synnefo.db.models import (Backend, VirtualMachine, Network, NetworkLink)
41 234f8b07 Vangelis Koukis
from synnefo.logic import utils
42 529178b1 Giorgos Verigakis
from synnefo.util.rapi import GanetiRapiClient
43 529178b1 Giorgos Verigakis
44 529178b1 Giorgos Verigakis
45 f5b4f2a3 Christos Stavrakakis
46 9e98ba3c Giorgos Verigakis
log = getLogger('synnefo.logic')
47 9e98ba3c Giorgos Verigakis
48 529178b1 Giorgos Verigakis
49 efff6193 Giorgos Verigakis
_firewall_tags = {
50 efff6193 Giorgos Verigakis
    'ENABLED': settings.GANETI_FIREWALL_ENABLED_TAG,
51 efff6193 Giorgos Verigakis
    'DISABLED': settings.GANETI_FIREWALL_DISABLED_TAG,
52 efff6193 Giorgos Verigakis
    'PROTECTED': settings.GANETI_FIREWALL_PROTECTED_TAG}
53 efff6193 Giorgos Verigakis
54 efff6193 Giorgos Verigakis
_reverse_tags = dict((v.split(':')[3], k) for k, v in _firewall_tags.items())
55 efff6193 Giorgos Verigakis
56 02feca11 Vassilios Karakoidas
57 924d8085 Christos Stavrakakis
def create_client(hostname, port=5080, username=None, password=None):
58 924d8085 Christos Stavrakakis
    return GanetiRapiClient(hostname=hostname,
59 924d8085 Christos Stavrakakis
                            port=port,
60 924d8085 Christos Stavrakakis
                            username=username,
61 924d8085 Christos Stavrakakis
                            password=password)
62 924d8085 Christos Stavrakakis
63 093f9c53 Vangelis Koukis
@transaction.commit_on_success
64 c4e55622 Christos Stavrakakis
def process_op_status(vm, etime, jobid, opcode, status, logmsg):
65 ad2d6807 Vangelis Koukis
    """Process a job progress notification from the backend
66 02feca11 Vassilios Karakoidas

67 02feca11 Vassilios Karakoidas
    Process an incoming message from the backend (currently Ganeti).
68 02feca11 Vassilios Karakoidas
    Job notifications with a terminating status (sucess, error, or canceled),
69 02feca11 Vassilios Karakoidas
    also update the operating state of the VM.
70 02feca11 Vassilios Karakoidas

71 02feca11 Vassilios Karakoidas
    """
72 41303ed0 Vangelis Koukis
    # See #1492, #1031, #1111 why this line has been removed
73 41303ed0 Vangelis Koukis
    #if (opcode not in [x[0] for x in VirtualMachine.BACKEND_OPCODES] or
74 41303ed0 Vangelis Koukis
    if status not in [x[0] for x in VirtualMachine.BACKEND_STATUSES]:
75 02feca11 Vassilios Karakoidas
        raise VirtualMachine.InvalidBackendMsgError(opcode, status)
76 02feca11 Vassilios Karakoidas
77 dfd19c2d Vassilios Karakoidas
    vm.backendjobid = jobid
78 dfd19c2d Vassilios Karakoidas
    vm.backendjobstatus = status
79 dfd19c2d Vassilios Karakoidas
    vm.backendopcode = opcode
80 dfd19c2d Vassilios Karakoidas
    vm.backendlogmsg = logmsg
81 02feca11 Vassilios Karakoidas
82 02feca11 Vassilios Karakoidas
    # Notifications of success change the operating state
83 41303ed0 Vangelis Koukis
    state_for_success = VirtualMachine.OPER_STATE_FROM_OPCODE.get(opcode, None)
84 41303ed0 Vangelis Koukis
    if status == 'success' and state_for_success is not None:
85 41303ed0 Vangelis Koukis
        utils.update_state(vm, state_for_success)
86 41303ed0 Vangelis Koukis
        # Set the deleted flag explicitly, cater for admin-initiated removals
87 685b219e Vangelis Koukis
        if opcode == 'OP_INSTANCE_REMOVE':
88 685b219e Vangelis Koukis
            vm.deleted = True
89 9c21a2e2 Christos Stavrakakis
            vm.nics.all().delete()
90 685b219e Vangelis Koukis
91 685b219e Vangelis Koukis
    # Special case: if OP_INSTANCE_CREATE fails --> ERROR
92 02feca11 Vassilios Karakoidas
    if status in ('canceled', 'error') and opcode == 'OP_INSTANCE_CREATE':
93 234f8b07 Vangelis Koukis
        utils.update_state(vm, 'ERROR')
94 093f9c53 Vangelis Koukis
95 093f9c53 Vangelis Koukis
    # Special case: OP_INSTANCE_REMOVE fails for machines in ERROR,
96 093f9c53 Vangelis Koukis
    # when no instance exists at the Ganeti backend.
97 093f9c53 Vangelis Koukis
    # See ticket #799 for all the details.
98 093f9c53 Vangelis Koukis
    #
99 093f9c53 Vangelis Koukis
    if (status == 'error' and opcode == 'OP_INSTANCE_REMOVE' and
100 093f9c53 Vangelis Koukis
        vm.operstate == 'ERROR'):
101 093f9c53 Vangelis Koukis
        vm.deleted = True
102 9c21a2e2 Christos Stavrakakis
        vm.nics.all().delete()
103 093f9c53 Vangelis Koukis
104 c4e55622 Christos Stavrakakis
    vm.backendtime = etime
105 02feca11 Vassilios Karakoidas
    # Any other notification of failure leaves the operating state unchanged
106 02feca11 Vassilios Karakoidas
107 02feca11 Vassilios Karakoidas
    vm.save()
108 22e52ede Vassilios Karakoidas
109 ad2d6807 Vangelis Koukis
110 207b70d5 Giorgos Verigakis
@transaction.commit_on_success
111 c4e55622 Christos Stavrakakis
def process_net_status(vm, etime, nics):
112 ad2d6807 Vangelis Koukis
    """Process a net status notification from the backend
113 ad2d6807 Vangelis Koukis

114 ad2d6807 Vangelis Koukis
    Process an incoming message from the Ganeti backend,
115 ad2d6807 Vangelis Koukis
    detailing the NIC configuration of a VM instance.
116 ad2d6807 Vangelis Koukis

117 ad2d6807 Vangelis Koukis
    Update the state of the VM in the DB accordingly.
118 ad2d6807 Vangelis Koukis
    """
119 37ca953f Christodoulos Psaltis
120 64938cb0 Giorgos Verigakis
    vm.nics.all().delete()
121 64938cb0 Giorgos Verigakis
    for i, nic in enumerate(nics):
122 64938cb0 Giorgos Verigakis
        if i == 0:
123 ca792e04 Giorgos Verigakis
            net = Network.objects.get(public=True)
124 64938cb0 Giorgos Verigakis
        else:
125 a1dccf43 Vangelis Koukis
            try:
126 a1dccf43 Vangelis Koukis
                link = NetworkLink.objects.get(name=nic['link'])
127 a1dccf43 Vangelis Koukis
            except NetworkLink.DoesNotExist:
128 a1dccf43 Vangelis Koukis
                # Cannot find an instance of NetworkLink for
129 a1dccf43 Vangelis Koukis
                # the link attribute specified in the notification
130 a1dccf43 Vangelis Koukis
                raise NetworkLink.DoesNotExist("Cannot find a NetworkLink "
131 a1dccf43 Vangelis Koukis
                    "object for link='%s'" % nic['link'])
132 64938cb0 Giorgos Verigakis
            net = link.network
133 a1dccf43 Vangelis Koukis
            if net is None:
134 a1dccf43 Vangelis Koukis
                raise Network.DoesNotExist("NetworkLink for link='%s' not "
135 a1dccf43 Vangelis Koukis
                    "associated with an existing Network instance." %
136 a1dccf43 Vangelis Koukis
                    nic['link'])
137 9afeb669 Kostas Papadimitriou
138 658a825a Giorgos Verigakis
        firewall = nic.get('firewall', '')
139 658a825a Giorgos Verigakis
        firewall_profile = _reverse_tags.get(firewall, '')
140 658a825a Giorgos Verigakis
        if not firewall_profile and net.public:
141 658a825a Giorgos Verigakis
            firewall_profile = settings.DEFAULT_FIREWALL_PROFILE
142 9afeb669 Kostas Papadimitriou
143 64938cb0 Giorgos Verigakis
        vm.nics.create(
144 64938cb0 Giorgos Verigakis
            network=net,
145 64938cb0 Giorgos Verigakis
            index=i,
146 64938cb0 Giorgos Verigakis
            mac=nic.get('mac', ''),
147 746c6bf4 Vangelis Koukis
            ipv4=nic.get('ip', ''),
148 41303ed0 Vangelis Koukis
            ipv6=nic.get('ipv6', ''),
149 efff6193 Giorgos Verigakis
            firewall_profile=firewall_profile)
150 9afeb669 Kostas Papadimitriou
151 9afeb669 Kostas Papadimitriou
        # network nics modified, update network object
152 9afeb669 Kostas Papadimitriou
        net.save()
153 9afeb669 Kostas Papadimitriou
154 c4e55622 Christos Stavrakakis
    vm.backendtime = etime
155 ad2d6807 Vangelis Koukis
    vm.save()
156 ad2d6807 Vangelis Koukis
157 c25cc9ec Vangelis Koukis
158 9068cd85 Georgios Gousios
@transaction.commit_on_success
159 c4e55622 Christos Stavrakakis
def process_create_progress(vm, etime, rprogress, wprogress):
160 9068cd85 Georgios Gousios
161 c25cc9ec Vangelis Koukis
    # XXX: This only uses the read progress for now.
162 c25cc9ec Vangelis Koukis
    #      Explore whether it would make sense to use the value of wprogress
163 c25cc9ec Vangelis Koukis
    #      somewhere.
164 c25cc9ec Vangelis Koukis
    percentage = int(rprogress)
165 9068cd85 Georgios Gousios
166 af90d919 Vangelis Koukis
    # The percentage may exceed 100%, due to the way
167 af90d919 Vangelis Koukis
    # snf-progress-monitor tracks bytes read by image handling processes
168 af90d919 Vangelis Koukis
    percentage = 100 if percentage > 100 else percentage
169 af90d919 Vangelis Koukis
    if percentage < 0:
170 af90d919 Vangelis Koukis
        raise ValueError("Percentage cannot be negative")
171 9068cd85 Georgios Gousios
172 7ec9558b Vangelis Koukis
    # FIXME: log a warning here, see #1033
173 7ec9558b Vangelis Koukis
#   if last_update > percentage:
174 7ec9558b Vangelis Koukis
#       raise ValueError("Build percentage should increase monotonically " \
175 7ec9558b Vangelis Koukis
#                        "(old = %d, new = %d)" % (last_update, percentage))
176 9068cd85 Georgios Gousios
177 c25cc9ec Vangelis Koukis
    # This assumes that no message of type 'ganeti-create-progress' is going to
178 c25cc9ec Vangelis Koukis
    # arrive once OP_INSTANCE_CREATE has succeeded for a Ganeti instance and
179 c25cc9ec Vangelis Koukis
    # the instance is STARTED.  What if the two messages are processed by two
180 c25cc9ec Vangelis Koukis
    # separate dispatcher threads, and the 'ganeti-op-status' message for
181 c25cc9ec Vangelis Koukis
    # successful creation gets processed before the 'ganeti-create-progress'
182 c25cc9ec Vangelis Koukis
    # message? [vkoukis]
183 c25cc9ec Vangelis Koukis
    #
184 c25cc9ec Vangelis Koukis
    #if not vm.operstate == 'BUILD':
185 c25cc9ec Vangelis Koukis
    #    raise VirtualMachine.IllegalState("VM is not in building state")
186 9068cd85 Georgios Gousios
187 c25cc9ec Vangelis Koukis
    vm.buildpercentage = percentage
188 c4e55622 Christos Stavrakakis
    vm.backendtime = etime
189 9068cd85 Georgios Gousios
    vm.save()
190 ad2d6807 Vangelis Koukis
191 c25cc9ec Vangelis Koukis
192 22e52ede Vassilios Karakoidas
def start_action(vm, action):
193 22e52ede Vassilios Karakoidas
    """Update the state of a VM when a new action is initiated."""
194 22e52ede Vassilios Karakoidas
    if not action in [x[0] for x in VirtualMachine.ACTIONS]:
195 22e52ede Vassilios Karakoidas
        raise VirtualMachine.InvalidActionError(action)
196 22e52ede Vassilios Karakoidas
197 22e52ede Vassilios Karakoidas
    # No actions to deleted and no actions beside destroy to suspended VMs
198 22e52ede Vassilios Karakoidas
    if vm.deleted:
199 5231a38a Giorgos Verigakis
        raise VirtualMachine.DeletedError
200 37ca953f Christodoulos Psaltis
201 30f3b5e5 Vangelis Koukis
    # No actions to machines being built. They may be destroyed, however.
202 30f3b5e5 Vangelis Koukis
    if vm.operstate == 'BUILD' and action != 'DESTROY':
203 5231a38a Giorgos Verigakis
        raise VirtualMachine.BuildingError
204 37ca953f Christodoulos Psaltis
205 dfd19c2d Vassilios Karakoidas
    vm.action = action
206 dfd19c2d Vassilios Karakoidas
    vm.backendjobid = None
207 dfd19c2d Vassilios Karakoidas
    vm.backendopcode = None
208 dfd19c2d Vassilios Karakoidas
    vm.backendjobstatus = None
209 dfd19c2d Vassilios Karakoidas
    vm.backendlogmsg = None
210 22e52ede Vassilios Karakoidas
211 f90c3d8c Vangelis Koukis
    # Update the relevant flags if the VM is being suspended or destroyed.
212 f90c3d8c Vangelis Koukis
    # Do not set the deleted flag here, see ticket #721.
213 f90c3d8c Vangelis Koukis
    #
214 f90c3d8c Vangelis Koukis
    # The deleted flag is set asynchronously, when an OP_INSTANCE_REMOVE
215 f90c3d8c Vangelis Koukis
    # completes successfully. Hence, a server may be visible for some time
216 f90c3d8c Vangelis Koukis
    # after a DELETE /servers/id returns HTTP 204.
217 f90c3d8c Vangelis Koukis
    #
218 22e52ede Vassilios Karakoidas
    if action == "DESTROY":
219 f90c3d8c Vangelis Koukis
        # vm.deleted = True
220 f90c3d8c Vangelis Koukis
        pass
221 22e52ede Vassilios Karakoidas
    elif action == "SUSPEND":
222 22e52ede Vassilios Karakoidas
        vm.suspended = True
223 22e52ede Vassilios Karakoidas
    elif action == "START":
224 22e52ede Vassilios Karakoidas
        vm.suspended = False
225 22e52ede Vassilios Karakoidas
    vm.save()
226 529178b1 Giorgos Verigakis
227 ad2d6807 Vangelis Koukis
228 2b1db26f Giorgos Verigakis
def create_instance(vm, flavor, image, password, personality):
229 3a9b3cde Giorgos Verigakis
    """`image` is a dictionary which should contain the keys:
230 3a9b3cde Giorgos Verigakis
            'backend_id', 'format' and 'metadata'
231 7f691719 Christos Stavrakakis

232 3a9b3cde Giorgos Verigakis
        metadata value should be a dictionary.
233 3a9b3cde Giorgos Verigakis
    """
234 7f691719 Christos Stavrakakis
    nic = {'ip': 'pool', 'network': settings.GANETI_PUBLIC_NETWORK}
235 61868190 Vangelis Koukis
236 61868190 Vangelis Koukis
    if settings.IGNORE_FLAVOR_DISK_SIZES:
237 3a9b3cde Giorgos Verigakis
        if image['backend_id'].find("windows") >= 0:
238 61868190 Vangelis Koukis
            sz = 14000
239 61868190 Vangelis Koukis
        else:
240 61868190 Vangelis Koukis
            sz = 4000
241 cf0e4232 Vangelis Koukis
    else:
242 61868190 Vangelis Koukis
        sz = flavor.disk * 1024
243 37ca953f Christodoulos Psaltis
244 1c382247 Vangelis Koukis
    # Handle arguments to CreateInstance() as a dictionary,
245 1c382247 Vangelis Koukis
    # initialize it based on a deployment-specific value.
246 1c382247 Vangelis Koukis
    # This enables the administrator to override deployment-specific
247 c25cc9ec Vangelis Koukis
    # arguments, such as the disk template to use, name of os provider
248 1c382247 Vangelis Koukis
    # and hypervisor-specific parameters at will (see Synnefo #785, #835).
249 1c382247 Vangelis Koukis
    #
250 1c382247 Vangelis Koukis
    kw = settings.GANETI_CREATEINSTANCE_KWARGS
251 1c382247 Vangelis Koukis
    kw['mode'] = 'create'
252 924d8085 Christos Stavrakakis
    kw['name'] = vm.backend_vm_id
253 5949b704 Vangelis Koukis
    # Defined in settings.GANETI_CREATEINSTANCE_KWARGS
254 805c79ae Giorgos Verigakis
    kw['disk_template'] = flavor.disk_template
255 1c382247 Vangelis Koukis
    kw['disks'] = [{"size": sz}]
256 1c382247 Vangelis Koukis
    kw['nics'] = [nic]
257 5949b704 Vangelis Koukis
    # Defined in settings.GANETI_CREATEINSTANCE_KWARGS
258 1c382247 Vangelis Koukis
    # kw['os'] = settings.GANETI_OS_PROVIDER
259 1c382247 Vangelis Koukis
    kw['ip_check'] = False
260 1c382247 Vangelis Koukis
    kw['name_check'] = False
261 1c382247 Vangelis Koukis
    # Do not specific a node explicitly, have
262 1c382247 Vangelis Koukis
    # Ganeti use an iallocator instead
263 1c382247 Vangelis Koukis
    #
264 1c382247 Vangelis Koukis
    # kw['pnode']=rapi.GetNodes()[0]
265 1c382247 Vangelis Koukis
    kw['dry_run'] = settings.TEST
266 41303ed0 Vangelis Koukis
267 2b1db26f Giorgos Verigakis
    kw['beparams'] = {
268 2b1db26f Giorgos Verigakis
        'auto_balance': True,
269 2b1db26f Giorgos Verigakis
        'vcpus': flavor.cpu,
270 2b1db26f Giorgos Verigakis
        'memory': flavor.ram}
271 41303ed0 Vangelis Koukis
272 e3b5be49 Giorgos Verigakis
    kw['osparams'] = {
273 3a9b3cde Giorgos Verigakis
        'img_id': image['backend_id'],
274 e3b5be49 Giorgos Verigakis
        'img_passwd': password,
275 3a9b3cde Giorgos Verigakis
        'img_format': image['format']}
276 2b1db26f Giorgos Verigakis
    if personality:
277 e3b5be49 Giorgos Verigakis
        kw['osparams']['img_personality'] = json.dumps(personality)
278 d1eaa651 Christos Stavrakakis
279 3a9b3cde Giorgos Verigakis
    kw['osparams']['img_properties'] = json.dumps(image['metadata'])
280 d1eaa651 Christos Stavrakakis
281 5949b704 Vangelis Koukis
    # Defined in settings.GANETI_CREATEINSTANCE_KWARGS
282 1c382247 Vangelis Koukis
    # kw['hvparams'] = dict(serial_console=False)
283 1c382247 Vangelis Koukis
284 f5b4f2a3 Christos Stavrakakis
    return vm.client.CreateInstance(**kw)
285 f533f224 Vangelis Koukis
286 529178b1 Giorgos Verigakis
287 529178b1 Giorgos Verigakis
def delete_instance(vm):
288 529178b1 Giorgos Verigakis
    start_action(vm, 'DESTROY')
289 f5b4f2a3 Christos Stavrakakis
    vm.client.DeleteInstance(vm.backend_vm_id, dry_run=settings.TEST)
290 529178b1 Giorgos Verigakis
291 ad2d6807 Vangelis Koukis
292 529178b1 Giorgos Verigakis
def reboot_instance(vm, reboot_type):
293 529178b1 Giorgos Verigakis
    assert reboot_type in ('soft', 'hard')
294 f5b4f2a3 Christos Stavrakakis
    vm.client.RebootInstance(vm.backend_vm_id, reboot_type, dry_run=settings.TEST)
295 924d8085 Christos Stavrakakis
    log.info('Rebooting instance %s', vm.backend_vm_id)
296 529178b1 Giorgos Verigakis
297 ad2d6807 Vangelis Koukis
298 529178b1 Giorgos Verigakis
def startup_instance(vm):
299 529178b1 Giorgos Verigakis
    start_action(vm, 'START')
300 f5b4f2a3 Christos Stavrakakis
    vm.client.StartupInstance(vm.backend_vm_id, dry_run=settings.TEST)
301 529178b1 Giorgos Verigakis
302 ad2d6807 Vangelis Koukis
303 529178b1 Giorgos Verigakis
def shutdown_instance(vm):
304 529178b1 Giorgos Verigakis
    start_action(vm, 'STOP')
305 f5b4f2a3 Christos Stavrakakis
    vm.client.ShutdownInstance(vm.backend_vm_id, dry_run=settings.TEST)
306 529178b1 Giorgos Verigakis
307 ad2d6807 Vangelis Koukis
308 529178b1 Giorgos Verigakis
def get_instance_console(vm):
309 71099804 Vangelis Koukis
    # RAPI GetInstanceConsole() returns endpoints to the vnc_bind_address,
310 71099804 Vangelis Koukis
    # which is a cluster-wide setting, either 0.0.0.0 or 127.0.0.1, and pretty
311 71099804 Vangelis Koukis
    # useless (see #783).
312 71099804 Vangelis Koukis
    #
313 71099804 Vangelis Koukis
    # Until this is fixed on the Ganeti side, construct a console info reply
314 71099804 Vangelis Koukis
    # directly.
315 9afeb669 Kostas Papadimitriou
    #
316 71099804 Vangelis Koukis
    # WARNING: This assumes that VNC runs on port network_port on
317 71099804 Vangelis Koukis
    #          the instance's primary node, and is probably
318 71099804 Vangelis Koukis
    #          hypervisor-specific.
319 71099804 Vangelis Koukis
    #
320 71099804 Vangelis Koukis
    console = {}
321 71099804 Vangelis Koukis
    console['kind'] = 'vnc'
322 f5b4f2a3 Christos Stavrakakis
    i = vm.client.GetInstance(vm.backend_vm_id)
323 71099804 Vangelis Koukis
    if i['hvparams']['serial_console']:
324 71099804 Vangelis Koukis
        raise Exception("hv parameter serial_console cannot be true")
325 71099804 Vangelis Koukis
    console['host'] = i['pnode']
326 71099804 Vangelis Koukis
    console['port'] = i['network_port']
327 9afeb669 Kostas Papadimitriou
328 71099804 Vangelis Koukis
    return console
329 924d8085 Christos Stavrakakis
    # return rapi.GetInstanceConsole(vm.backend_vm_id)
330 64938cb0 Giorgos Verigakis
331 c25cc9ec Vangelis Koukis
332 604b2bf8 Georgios Gousios
def request_status_update(vm):
333 f5b4f2a3 Christos Stavrakakis
    return vm.client.GetInstanceInfo(vm.backend_vm_id)
334 604b2bf8 Georgios Gousios
335 604b2bf8 Georgios Gousios
336 604b2bf8 Georgios Gousios
def update_status(vm, status):
337 db7a3230 Vangelis Koukis
    utils.update_state(vm, status)
338 f533f224 Vangelis Koukis
339 c25cc9ec Vangelis Koukis
340 64938cb0 Giorgos Verigakis
def create_network_link():
341 64938cb0 Giorgos Verigakis
    try:
342 64938cb0 Giorgos Verigakis
        last = NetworkLink.objects.order_by('-index')[0]
343 64938cb0 Giorgos Verigakis
        index = last.index + 1
344 64938cb0 Giorgos Verigakis
    except IndexError:
345 64938cb0 Giorgos Verigakis
        index = 1
346 37ca953f Christodoulos Psaltis
347 64938cb0 Giorgos Verigakis
    if index <= settings.GANETI_MAX_LINK_NUMBER:
348 64938cb0 Giorgos Verigakis
        name = '%s%d' % (settings.GANETI_LINK_PREFIX, index)
349 f533f224 Vangelis Koukis
        return NetworkLink.objects.create(index=index, name=name,
350 a191bd4d Giorgos Verigakis
                                            available=True)
351 64938cb0 Giorgos Verigakis
    return None     # All link slots are filled
352 64938cb0 Giorgos Verigakis
353 c25cc9ec Vangelis Koukis
354 207b70d5 Giorgos Verigakis
@transaction.commit_on_success
355 6ef51e9f Giorgos Verigakis
def create_network(name, user_id):
356 64938cb0 Giorgos Verigakis
    try:
357 64938cb0 Giorgos Verigakis
        link = NetworkLink.objects.filter(available=True)[0]
358 64938cb0 Giorgos Verigakis
    except IndexError:
359 64938cb0 Giorgos Verigakis
        link = create_network_link()
360 64938cb0 Giorgos Verigakis
        if not link:
361 ce55f211 Kostas Papadimitriou
            raise NetworkLink.NotAvailable
362 37ca953f Christodoulos Psaltis
363 a3992827 Giorgos Verigakis
    network = Network.objects.create(
364 a3992827 Giorgos Verigakis
        name=name,
365 6ef51e9f Giorgos Verigakis
        userid=user_id,
366 a3992827 Giorgos Verigakis
        state='ACTIVE',
367 a3992827 Giorgos Verigakis
        link=link)
368 37ca953f Christodoulos Psaltis
369 a3992827 Giorgos Verigakis
    link.network = network
370 64938cb0 Giorgos Verigakis
    link.available = False
371 64938cb0 Giorgos Verigakis
    link.save()
372 37ca953f Christodoulos Psaltis
373 a3992827 Giorgos Verigakis
    return network
374 64938cb0 Giorgos Verigakis
375 c25cc9ec Vangelis Koukis
376 207b70d5 Giorgos Verigakis
@transaction.commit_on_success
377 64938cb0 Giorgos Verigakis
def delete_network(net):
378 64938cb0 Giorgos Verigakis
    link = net.link
379 06a16b24 Giorgos Verigakis
    if link.name != settings.GANETI_NULL_LINK:
380 06a16b24 Giorgos Verigakis
        link.available = True
381 06a16b24 Giorgos Verigakis
        link.network = None
382 06a16b24 Giorgos Verigakis
        link.save()
383 37ca953f Christodoulos Psaltis
384 64938cb0 Giorgos Verigakis
    for vm in net.machines.all():
385 64938cb0 Giorgos Verigakis
        disconnect_from_network(vm, net)
386 64938cb0 Giorgos Verigakis
        vm.save()
387 64938cb0 Giorgos Verigakis
    net.state = 'DELETED'
388 64938cb0 Giorgos Verigakis
    net.save()
389 64938cb0 Giorgos Verigakis
390 c25cc9ec Vangelis Koukis
391 64938cb0 Giorgos Verigakis
def connect_to_network(vm, net):
392 64938cb0 Giorgos Verigakis
    nic = {'mode': 'bridged', 'link': net.link.name}
393 f5b4f2a3 Christos Stavrakakis
    vm.client.ModifyInstance(vm.backend_vm_id, nics=[('add', -1, nic)],
394 3c755209 Dimitris Aragiorgis
                        hotplug=True, dry_run=settings.TEST)
395 64938cb0 Giorgos Verigakis
396 c25cc9ec Vangelis Koukis
397 64938cb0 Giorgos Verigakis
def disconnect_from_network(vm, net):
398 ca792e04 Giorgos Verigakis
    nics = vm.nics.filter(network__public=False).order_by('index')
399 d1eaa651 Christos Stavrakakis
    ops = [('remove', nic.index, {}) for nic in nics if nic.network == net]
400 924d8085 Christos Stavrakakis
    if not ops:  # Vm not connected to network
401 d1eaa651 Christos Stavrakakis
        return
402 f5b4f2a3 Christos Stavrakakis
    vm.client.ModifyInstance(vm.backend_vm_id, nics=ops[::-1],
403 3c755209 Dimitris Aragiorgis
                        hotplug=True, dry_run=settings.TEST)
404 91826390 Giorgos Verigakis
405 c25cc9ec Vangelis Koukis
406 91826390 Giorgos Verigakis
def set_firewall_profile(vm, profile):
407 26563957 Giorgos Verigakis
    try:
408 26563957 Giorgos Verigakis
        tag = _firewall_tags[profile]
409 26563957 Giorgos Verigakis
    except KeyError:
410 91826390 Giorgos Verigakis
        raise ValueError("Unsopported Firewall Profile: %s" % profile)
411 37ca953f Christodoulos Psaltis
412 f5b4f2a3 Christos Stavrakakis
    client = vm.client
413 26563957 Giorgos Verigakis
    # Delete all firewall tags
414 efff6193 Giorgos Verigakis
    for t in _firewall_tags.values():
415 f5b4f2a3 Christos Stavrakakis
        client.DeleteInstanceTags(vm.backend_vm_id, [t], dry_run=settings.TEST)
416 37ca953f Christodoulos Psaltis
417 f5b4f2a3 Christos Stavrakakis
    client.AddInstanceTags(vm.backend_vm_id, [tag], dry_run=settings.TEST)
418 9afeb669 Kostas Papadimitriou
419 2da5f785 Giorgos Verigakis
    # XXX NOP ModifyInstance call to force process_net_status to run
420 2da5f785 Giorgos Verigakis
    # on the dispatcher
421 f5b4f2a3 Christos Stavrakakis
    vm.client.ModifyInstance(vm.backend_vm_id,
422 5eedb0e4 Vangelis Koukis
                        os_name=settings.GANETI_CREATEINSTANCE_KWARGS['os'])
423 5eedb0e4 Vangelis Koukis
424 41303ed0 Vangelis Koukis
425 f5b4f2a3 Christos Stavrakakis
def get_ganeti_instances(backend=None, bulk=False):
426 f5b4f2a3 Christos Stavrakakis
    Instances = [c.client.GetInstances(bulk=bulk) for c in get_backends(backend)]
427 f5b4f2a3 Christos Stavrakakis
    return reduce(list.__add__, Instances, [])
428 f5b4f2a3 Christos Stavrakakis
429 f5b4f2a3 Christos Stavrakakis
430 f5b4f2a3 Christos Stavrakakis
def get_ganeti_nodes(backend=None, bulk=False):
431 f5b4f2a3 Christos Stavrakakis
    Nodes = [c.client.GetNodes(bulk=bulk) for c in get_backends(backend)]
432 f5b4f2a3 Christos Stavrakakis
    return reduce(list.__add__, Nodes, [])
433 f5b4f2a3 Christos Stavrakakis
434 f5b4f2a3 Christos Stavrakakis
435 f5b4f2a3 Christos Stavrakakis
def get_ganeti_jobs(backend=None, bulk=False):
436 f5b4f2a3 Christos Stavrakakis
    Jobs = [c.client.GetJobs(bulk=bulk) for c in get_backends(backend)]
437 f5b4f2a3 Christos Stavrakakis
    return reduce(list.__add__, Jobs, [])
438 f5b4f2a3 Christos Stavrakakis
439 f5b4f2a3 Christos Stavrakakis
##
440 f5b4f2a3 Christos Stavrakakis
##
441 f5b4f2a3 Christos Stavrakakis
##
442 f5b4f2a3 Christos Stavrakakis
def get_backends(backend=None):
443 f5b4f2a3 Christos Stavrakakis
    if backend:
444 f5b4f2a3 Christos Stavrakakis
        return [backend]
445 f5b4f2a3 Christos Stavrakakis
    return Backend.objects.all()
446 f5b4f2a3 Christos Stavrakakis
447 17852fe9 Giorgos Verigakis
448 41303ed0 Vangelis Koukis
449 17852fe9 Giorgos Verigakis