root / logic / backend.py @ 5231a38a
History | View | Annotate | Download (3.5 kB)
1 |
#
|
---|---|
2 |
# Business Logic for communication with the Ganeti backend
|
3 |
#
|
4 |
# Copyright 2010 Greek Research and Technology Network
|
5 |
#
|
6 |
|
7 |
from django.conf import settings |
8 |
from synnefo.db.models import VirtualMachine |
9 |
from synnefo.logic import utils |
10 |
from synnefo.util.rapi import GanetiRapiClient |
11 |
|
12 |
|
13 |
rapi = GanetiRapiClient(*settings.GANETI_CLUSTER_INFO) |
14 |
|
15 |
|
16 |
def process_backend_msg(vm, jobid, opcode, status, logmsg): |
17 |
"""Process a job progress notification from the backend.
|
18 |
|
19 |
Process an incoming message from the backend (currently Ganeti).
|
20 |
Job notifications with a terminating status (sucess, error, or canceled),
|
21 |
also update the operating state of the VM.
|
22 |
|
23 |
"""
|
24 |
if (opcode not in [x[0] for x in VirtualMachine.BACKEND_OPCODES] or |
25 |
status not in [x[0] for x in VirtualMachine.BACKEND_STATUSES]): |
26 |
raise VirtualMachine.InvalidBackendMsgError(opcode, status)
|
27 |
|
28 |
vm.backendjobid = jobid |
29 |
vm.backendjobstatus = status |
30 |
vm.backendopcode = opcode |
31 |
vm.backendlogmsg = logmsg |
32 |
|
33 |
# Notifications of success change the operating state
|
34 |
if status == 'success': |
35 |
utils.update_state(vm, VirtualMachine.OPER_STATE_FROM_OPCODE[opcode]) |
36 |
# Set the deleted flag explicitly, to cater for admin-initiated removals
|
37 |
if opcode == 'OP_INSTANCE_REMOVE': |
38 |
vm.deleted = True
|
39 |
|
40 |
# Special case: if OP_INSTANCE_CREATE fails --> ERROR
|
41 |
if status in ('canceled', 'error') and opcode == 'OP_INSTANCE_CREATE': |
42 |
utils.update_state(vm, 'ERROR')
|
43 |
# Any other notification of failure leaves the operating state unchanged
|
44 |
|
45 |
vm.save() |
46 |
|
47 |
def start_action(vm, action): |
48 |
"""Update the state of a VM when a new action is initiated."""
|
49 |
if not action in [x[0] for x in VirtualMachine.ACTIONS]: |
50 |
raise VirtualMachine.InvalidActionError(action)
|
51 |
|
52 |
# No actions to deleted and no actions beside destroy to suspended VMs
|
53 |
if vm.deleted:
|
54 |
raise VirtualMachine.DeletedError
|
55 |
|
56 |
if vm.operstate == 'BUILD': |
57 |
raise VirtualMachine.BuildingError
|
58 |
|
59 |
vm.action = action |
60 |
vm.backendjobid = None
|
61 |
vm.backendopcode = None
|
62 |
vm.backendjobstatus = None
|
63 |
vm.backendlogmsg = None
|
64 |
|
65 |
# Update the relevant flags if the VM is being suspended or destroyed
|
66 |
if action == "DESTROY": |
67 |
vm.deleted = True
|
68 |
elif action == "SUSPEND": |
69 |
vm.suspended = True
|
70 |
elif action == "START": |
71 |
vm.suspended = False
|
72 |
vm.save() |
73 |
|
74 |
def create_instance(vm, flavor, password): |
75 |
# FIXME: `password` must be passed to the Ganeti OS provider via CreateInstance()
|
76 |
return rapi.CreateInstance(
|
77 |
mode='create',
|
78 |
name=vm.backend_id, |
79 |
disk_template='plain',
|
80 |
disks=[{"size": 2000}], #FIXME: Always ask for a 2GB disk for now |
81 |
nics=[{}], |
82 |
os='debootstrap+default', #TODO: select OS from imageRef |
83 |
ip_check=False,
|
84 |
name_check=False,
|
85 |
pnode=rapi.GetNodes()[0], #TODO: verify if this is necessary |
86 |
dry_run=settings.TEST, |
87 |
beparams=dict(auto_balance=True, vcpus=flavor.cpu, memory=flavor.ram)) |
88 |
|
89 |
def delete_instance(vm): |
90 |
start_action(vm, 'DESTROY')
|
91 |
rapi.DeleteInstance(vm.backend_id) |
92 |
|
93 |
def reboot_instance(vm, reboot_type): |
94 |
assert reboot_type in ('soft', 'hard') |
95 |
rapi.RebootInstance(vm.backend_id, reboot_type) |
96 |
|
97 |
def startup_instance(vm): |
98 |
start_action(vm, 'START')
|
99 |
rapi.StartupInstance(vm.backend_id) |
100 |
|
101 |
def shutdown_instance(vm): |
102 |
start_action(vm, 'STOP')
|
103 |
rapi.ShutdownInstance(vm.backend_id) |
104 |
|
105 |
def get_instance_console(vm): |
106 |
return rapi.GetInstanceConsole(vm.backend_id)
|