Statistics
| Branch: | Tag: | Revision:

root / logic / backend.py @ ac63eb4f

History | View | Annotate | Download (4.2 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_op_status(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' and VirtualMachine.OPER_STATE_FROM_OPCODE[opcode] is not None:
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

    
48
def process_net_status(vm, nics):
49
    """Process a net status notification from the backend
50

51
    Process an incoming message from the Ganeti backend,
52
    detailing the NIC configuration of a VM instance.
53

54
    Update the state of the VM in the DB accordingly.
55

56
    """
57

    
58
    # For the time being, we can only update the ipfour field,
59
    # based on the IPv4 address of the first NIC
60
    if len(nics) > 0:
61
        ipv4 = nics[0]['ip']
62
        if ipv4 == '':
63
            ipv4 = '0.0.0.0'
64
        vm.ipfour = ipv4
65
    vm.save()
66

    
67

    
68
def start_action(vm, action):
69
    """Update the state of a VM when a new action is initiated."""
70
    if not action in [x[0] for x in VirtualMachine.ACTIONS]:
71
        raise VirtualMachine.InvalidActionError(action)
72

    
73
    # No actions to deleted and no actions beside destroy to suspended VMs
74
    if vm.deleted:
75
        raise VirtualMachine.DeletedError
76
   
77
    # No actions to machines being built. They may be destroyed, however.
78
    if vm.operstate == 'BUILD' and action != 'DESTROY':
79
        raise VirtualMachine.BuildingError
80
    
81
    vm.action = action
82
    vm.backendjobid = None
83
    vm.backendopcode = None
84
    vm.backendjobstatus = None
85
    vm.backendlogmsg = None
86

    
87
    # Update the relevant flags if the VM is being suspended or destroyed
88
    if action == "DESTROY":
89
        vm.deleted = True
90
    elif action == "SUSPEND":
91
        vm.suspended = True
92
    elif action == "START":
93
        vm.suspended = False
94
    vm.save()
95

    
96

    
97
def create_instance(vm, flavor, password):
98
    # FIXME: `password` must be passed to the Ganeti OS provider via CreateInstance()
99
    return rapi.CreateInstance(
100
        mode='create',
101
        name=vm.backend_id,
102
        disk_template='plain',
103
        disks=[{"size": 2000}],         #FIXME: Always ask for a 2GB disk for now
104
        nics=[{}],
105
        os='debootstrap+default',       #TODO: select OS from imageRef
106
        ip_check=False,
107
        name_check=False,
108
        pnode=rapi.GetNodes()[0],       #TODO: verify if this is necessary
109
        dry_run=settings.TEST,
110
        beparams=dict(auto_balance=True, vcpus=flavor.cpu, memory=flavor.ram))
111

    
112
def delete_instance(vm):
113
    start_action(vm, 'DESTROY')
114
    rapi.DeleteInstance(vm.backend_id)
115

    
116

    
117
def reboot_instance(vm, reboot_type):
118
    assert reboot_type in ('soft', 'hard')
119
    rapi.RebootInstance(vm.backend_id, reboot_type)
120

    
121

    
122
def startup_instance(vm):
123
    start_action(vm, 'START')
124
    rapi.StartupInstance(vm.backend_id)
125

    
126

    
127
def shutdown_instance(vm):
128
    start_action(vm, 'STOP')
129
    rapi.ShutdownInstance(vm.backend_id)
130

    
131

    
132
def get_instance_console(vm):
133
    return rapi.GetInstanceConsole(vm.backend_id)