root / logic / backend.py @ 207b70d5
History | View | Annotate | Download (6.2 kB)
1 | 234f8b07 | Vangelis Koukis | #
|
---|---|---|---|
2 | 234f8b07 | Vangelis Koukis | # Business Logic for communication with the Ganeti backend
|
3 | 234f8b07 | Vangelis Koukis | #
|
4 | 234f8b07 | Vangelis Koukis | # Copyright 2010 Greek Research and Technology Network
|
5 | 234f8b07 | Vangelis Koukis | #
|
6 | 02feca11 | Vassilios Karakoidas | |
7 | 529178b1 | Giorgos Verigakis | from django.conf import settings |
8 | 207b70d5 | Giorgos Verigakis | from django.db import transaction |
9 | 207b70d5 | Giorgos Verigakis | |
10 | 64938cb0 | Giorgos Verigakis | from synnefo.db.models import VirtualMachine, Network, NetworkLink |
11 | 234f8b07 | Vangelis Koukis | from synnefo.logic import utils |
12 | 529178b1 | Giorgos Verigakis | from synnefo.util.rapi import GanetiRapiClient |
13 | 529178b1 | Giorgos Verigakis | |
14 | 529178b1 | Giorgos Verigakis | |
15 | 529178b1 | Giorgos Verigakis | rapi = GanetiRapiClient(*settings.GANETI_CLUSTER_INFO) |
16 | 529178b1 | Giorgos Verigakis | |
17 | 02feca11 | Vassilios Karakoidas | |
18 | ad2d6807 | Vangelis Koukis | def process_op_status(vm, jobid, opcode, status, logmsg): |
19 | ad2d6807 | Vangelis Koukis | """Process a job progress notification from the backend
|
20 | 02feca11 | Vassilios Karakoidas |
|
21 | 02feca11 | Vassilios Karakoidas | Process an incoming message from the backend (currently Ganeti).
|
22 | 02feca11 | Vassilios Karakoidas | Job notifications with a terminating status (sucess, error, or canceled),
|
23 | 02feca11 | Vassilios Karakoidas | also update the operating state of the VM.
|
24 | 02feca11 | Vassilios Karakoidas |
|
25 | 02feca11 | Vassilios Karakoidas | """
|
26 | 02feca11 | Vassilios Karakoidas | if (opcode not in [x[0] for x in VirtualMachine.BACKEND_OPCODES] or |
27 | 02feca11 | Vassilios Karakoidas | status not in [x[0] for x in VirtualMachine.BACKEND_STATUSES]): |
28 | 02feca11 | Vassilios Karakoidas | raise VirtualMachine.InvalidBackendMsgError(opcode, status)
|
29 | 02feca11 | Vassilios Karakoidas | |
30 | dfd19c2d | Vassilios Karakoidas | vm.backendjobid = jobid |
31 | dfd19c2d | Vassilios Karakoidas | vm.backendjobstatus = status |
32 | dfd19c2d | Vassilios Karakoidas | vm.backendopcode = opcode |
33 | dfd19c2d | Vassilios Karakoidas | vm.backendlogmsg = logmsg |
34 | 02feca11 | Vassilios Karakoidas | |
35 | 02feca11 | Vassilios Karakoidas | # Notifications of success change the operating state
|
36 | ac63eb4f | Vangelis Koukis | if status == 'success' and VirtualMachine.OPER_STATE_FROM_OPCODE[opcode] is not None: |
37 | 234f8b07 | Vangelis Koukis | utils.update_state(vm, VirtualMachine.OPER_STATE_FROM_OPCODE[opcode]) |
38 | 685b219e | Vangelis Koukis | # Set the deleted flag explicitly, to cater for admin-initiated removals
|
39 | 685b219e | Vangelis Koukis | if opcode == 'OP_INSTANCE_REMOVE': |
40 | 685b219e | Vangelis Koukis | vm.deleted = True
|
41 | 685b219e | Vangelis Koukis | |
42 | 685b219e | Vangelis Koukis | # Special case: if OP_INSTANCE_CREATE fails --> ERROR
|
43 | 02feca11 | Vassilios Karakoidas | if status in ('canceled', 'error') and opcode == 'OP_INSTANCE_CREATE': |
44 | 234f8b07 | Vangelis Koukis | utils.update_state(vm, 'ERROR')
|
45 | 02feca11 | Vassilios Karakoidas | # Any other notification of failure leaves the operating state unchanged
|
46 | 02feca11 | Vassilios Karakoidas | |
47 | 02feca11 | Vassilios Karakoidas | vm.save() |
48 | 22e52ede | Vassilios Karakoidas | |
49 | ad2d6807 | Vangelis Koukis | |
50 | 207b70d5 | Giorgos Verigakis | @transaction.commit_on_success
|
51 | ad2d6807 | Vangelis Koukis | def process_net_status(vm, nics): |
52 | ad2d6807 | Vangelis Koukis | """Process a net status notification from the backend
|
53 | ad2d6807 | Vangelis Koukis |
|
54 | ad2d6807 | Vangelis Koukis | Process an incoming message from the Ganeti backend,
|
55 | ad2d6807 | Vangelis Koukis | detailing the NIC configuration of a VM instance.
|
56 | ad2d6807 | Vangelis Koukis |
|
57 | ad2d6807 | Vangelis Koukis | Update the state of the VM in the DB accordingly.
|
58 | ad2d6807 | Vangelis Koukis | """
|
59 | 64938cb0 | Giorgos Verigakis | |
60 | 64938cb0 | Giorgos Verigakis | vm.nics.all().delete() |
61 | 64938cb0 | Giorgos Verigakis | for i, nic in enumerate(nics): |
62 | 64938cb0 | Giorgos Verigakis | if i == 0: |
63 | 64938cb0 | Giorgos Verigakis | net = Network.objects.filter(public=True)[0] |
64 | 64938cb0 | Giorgos Verigakis | else:
|
65 | 64938cb0 | Giorgos Verigakis | link = NetworkLink.objects.get(name=nic['link'])
|
66 | 64938cb0 | Giorgos Verigakis | net = link.network |
67 | 64938cb0 | Giorgos Verigakis | |
68 | 64938cb0 | Giorgos Verigakis | vm.nics.create( |
69 | 64938cb0 | Giorgos Verigakis | network=net, |
70 | 64938cb0 | Giorgos Verigakis | index=i, |
71 | 64938cb0 | Giorgos Verigakis | mac=nic.get('mac', ''), |
72 | 64938cb0 | Giorgos Verigakis | ipv4=nic.get('ip', '')) |
73 | ad2d6807 | Vangelis Koukis | vm.save() |
74 | ad2d6807 | Vangelis Koukis | |
75 | ad2d6807 | Vangelis Koukis | |
76 | 22e52ede | Vassilios Karakoidas | def start_action(vm, action): |
77 | 22e52ede | Vassilios Karakoidas | """Update the state of a VM when a new action is initiated."""
|
78 | 22e52ede | Vassilios Karakoidas | if not action in [x[0] for x in VirtualMachine.ACTIONS]: |
79 | 22e52ede | Vassilios Karakoidas | raise VirtualMachine.InvalidActionError(action)
|
80 | 22e52ede | Vassilios Karakoidas | |
81 | 22e52ede | Vassilios Karakoidas | # No actions to deleted and no actions beside destroy to suspended VMs
|
82 | 22e52ede | Vassilios Karakoidas | if vm.deleted:
|
83 | 5231a38a | Giorgos Verigakis | raise VirtualMachine.DeletedError
|
84 | 30f3b5e5 | Vangelis Koukis | |
85 | 30f3b5e5 | Vangelis Koukis | # No actions to machines being built. They may be destroyed, however.
|
86 | 30f3b5e5 | Vangelis Koukis | if vm.operstate == 'BUILD' and action != 'DESTROY': |
87 | 5231a38a | Giorgos Verigakis | raise VirtualMachine.BuildingError
|
88 | 5231a38a | Giorgos Verigakis | |
89 | dfd19c2d | Vassilios Karakoidas | vm.action = action |
90 | dfd19c2d | Vassilios Karakoidas | vm.backendjobid = None
|
91 | dfd19c2d | Vassilios Karakoidas | vm.backendopcode = None
|
92 | dfd19c2d | Vassilios Karakoidas | vm.backendjobstatus = None
|
93 | dfd19c2d | Vassilios Karakoidas | vm.backendlogmsg = None
|
94 | 22e52ede | Vassilios Karakoidas | |
95 | 22e52ede | Vassilios Karakoidas | # Update the relevant flags if the VM is being suspended or destroyed
|
96 | 22e52ede | Vassilios Karakoidas | if action == "DESTROY": |
97 | 22e52ede | Vassilios Karakoidas | vm.deleted = True
|
98 | 22e52ede | Vassilios Karakoidas | elif action == "SUSPEND": |
99 | 22e52ede | Vassilios Karakoidas | vm.suspended = True
|
100 | 22e52ede | Vassilios Karakoidas | elif action == "START": |
101 | 22e52ede | Vassilios Karakoidas | vm.suspended = False
|
102 | 22e52ede | Vassilios Karakoidas | vm.save() |
103 | 529178b1 | Giorgos Verigakis | |
104 | ad2d6807 | Vangelis Koukis | |
105 | 529178b1 | Giorgos Verigakis | def create_instance(vm, flavor, password): |
106 | 529178b1 | Giorgos Verigakis | # FIXME: `password` must be passed to the Ganeti OS provider via CreateInstance()
|
107 | 64938cb0 | Giorgos Verigakis | |
108 | 64938cb0 | Giorgos Verigakis | nic = {'ip': 'pool', 'mode': 'routed', 'link': settings.GANETI_PUBLIC_LINK} |
109 | 64938cb0 | Giorgos Verigakis | |
110 | 529178b1 | Giorgos Verigakis | return rapi.CreateInstance(
|
111 | 529178b1 | Giorgos Verigakis | mode='create',
|
112 | 12fd6446 | Giorgos Verigakis | name=vm.backend_id, |
113 | 529178b1 | Giorgos Verigakis | disk_template='plain',
|
114 | 529178b1 | Giorgos Verigakis | disks=[{"size": 2000}], #FIXME: Always ask for a 2GB disk for now |
115 | 64938cb0 | Giorgos Verigakis | nics=[nic], |
116 | 529178b1 | Giorgos Verigakis | os='debootstrap+default', #TODO: select OS from imageRef |
117 | 529178b1 | Giorgos Verigakis | ip_check=False,
|
118 | 529178b1 | Giorgos Verigakis | name_check=False,
|
119 | 529178b1 | Giorgos Verigakis | pnode=rapi.GetNodes()[0], #TODO: verify if this is necessary |
120 | 529178b1 | Giorgos Verigakis | dry_run=settings.TEST, |
121 | 529178b1 | Giorgos Verigakis | beparams=dict(auto_balance=True, vcpus=flavor.cpu, memory=flavor.ram)) |
122 | 529178b1 | Giorgos Verigakis | |
123 | 529178b1 | Giorgos Verigakis | def delete_instance(vm): |
124 | 529178b1 | Giorgos Verigakis | start_action(vm, 'DESTROY')
|
125 | 64938cb0 | Giorgos Verigakis | rapi.DeleteInstance(vm.backend_id, dry_run=settings.TEST) |
126 | d44c236b | Giorgos Verigakis | vm.nics.all().delete() |
127 | 529178b1 | Giorgos Verigakis | |
128 | ad2d6807 | Vangelis Koukis | |
129 | 529178b1 | Giorgos Verigakis | def reboot_instance(vm, reboot_type): |
130 | 529178b1 | Giorgos Verigakis | assert reboot_type in ('soft', 'hard') |
131 | 64938cb0 | Giorgos Verigakis | rapi.RebootInstance(vm.backend_id, reboot_type, dry_run=settings.TEST) |
132 | 529178b1 | Giorgos Verigakis | |
133 | ad2d6807 | Vangelis Koukis | |
134 | 529178b1 | Giorgos Verigakis | def startup_instance(vm): |
135 | 529178b1 | Giorgos Verigakis | start_action(vm, 'START')
|
136 | 64938cb0 | Giorgos Verigakis | rapi.StartupInstance(vm.backend_id, dry_run=settings.TEST) |
137 | 529178b1 | Giorgos Verigakis | |
138 | ad2d6807 | Vangelis Koukis | |
139 | 529178b1 | Giorgos Verigakis | def shutdown_instance(vm): |
140 | 529178b1 | Giorgos Verigakis | start_action(vm, 'STOP')
|
141 | 64938cb0 | Giorgos Verigakis | rapi.ShutdownInstance(vm.backend_id, dry_run=settings.TEST) |
142 | 529178b1 | Giorgos Verigakis | |
143 | ad2d6807 | Vangelis Koukis | |
144 | 529178b1 | Giorgos Verigakis | def get_instance_console(vm): |
145 | 529178b1 | Giorgos Verigakis | return rapi.GetInstanceConsole(vm.backend_id)
|
146 | 64938cb0 | Giorgos Verigakis | |
147 | 64938cb0 | Giorgos Verigakis | |
148 | 64938cb0 | Giorgos Verigakis | def create_network_link(): |
149 | 64938cb0 | Giorgos Verigakis | try:
|
150 | 64938cb0 | Giorgos Verigakis | last = NetworkLink.objects.order_by('-index')[0] |
151 | 64938cb0 | Giorgos Verigakis | index = last.index + 1
|
152 | 64938cb0 | Giorgos Verigakis | except IndexError: |
153 | 64938cb0 | Giorgos Verigakis | index = 1
|
154 | 64938cb0 | Giorgos Verigakis | |
155 | 64938cb0 | Giorgos Verigakis | if index <= settings.GANETI_MAX_LINK_NUMBER:
|
156 | 64938cb0 | Giorgos Verigakis | name = '%s%d' % (settings.GANETI_LINK_PREFIX, index)
|
157 | 64938cb0 | Giorgos Verigakis | return NetworkLink.objects.create(index=index, name=name, available=True) |
158 | 64938cb0 | Giorgos Verigakis | return None # All link slots are filled |
159 | 64938cb0 | Giorgos Verigakis | |
160 | 207b70d5 | Giorgos Verigakis | @transaction.commit_on_success
|
161 | 64938cb0 | Giorgos Verigakis | def create_network(net): |
162 | 64938cb0 | Giorgos Verigakis | try:
|
163 | 64938cb0 | Giorgos Verigakis | link = NetworkLink.objects.filter(available=True)[0] |
164 | 64938cb0 | Giorgos Verigakis | except IndexError: |
165 | 64938cb0 | Giorgos Verigakis | link = create_network_link() |
166 | 64938cb0 | Giorgos Verigakis | if not link: |
167 | 64938cb0 | Giorgos Verigakis | return False |
168 | 64938cb0 | Giorgos Verigakis | link.network = net |
169 | 64938cb0 | Giorgos Verigakis | link.available = False
|
170 | 64938cb0 | Giorgos Verigakis | link.save() |
171 | 64938cb0 | Giorgos Verigakis | return True |
172 | 64938cb0 | Giorgos Verigakis | |
173 | 207b70d5 | Giorgos Verigakis | @transaction.commit_on_success
|
174 | 64938cb0 | Giorgos Verigakis | def delete_network(net): |
175 | 64938cb0 | Giorgos Verigakis | link = net.link |
176 | 64938cb0 | Giorgos Verigakis | link.available = True
|
177 | 64938cb0 | Giorgos Verigakis | link.netowrk = False
|
178 | 64938cb0 | Giorgos Verigakis | link.save() |
179 | 64938cb0 | Giorgos Verigakis | |
180 | 64938cb0 | Giorgos Verigakis | for vm in net.machines.all(): |
181 | 64938cb0 | Giorgos Verigakis | disconnect_from_network(vm, net) |
182 | 64938cb0 | Giorgos Verigakis | vm.save() |
183 | 64938cb0 | Giorgos Verigakis | net.state = 'DELETED'
|
184 | 64938cb0 | Giorgos Verigakis | net.save() |
185 | 64938cb0 | Giorgos Verigakis | |
186 | 64938cb0 | Giorgos Verigakis | def connect_to_network(vm, net): |
187 | 64938cb0 | Giorgos Verigakis | nic = {'mode': 'bridged', 'link': net.link.name} |
188 | 64938cb0 | Giorgos Verigakis | rapi.ModifyInstance(vm.backend_id, nics=[('add', nic)], dry_run=settings.TEST)
|
189 | 64938cb0 | Giorgos Verigakis | |
190 | 64938cb0 | Giorgos Verigakis | def disconnect_from_network(vm, net): |
191 | 64938cb0 | Giorgos Verigakis | nics = vm.nics.order_by('index')[1:] # Skip the public network |
192 | 64938cb0 | Giorgos Verigakis | ops = [('remove', {})] * len(nics) |
193 | 64938cb0 | Giorgos Verigakis | for nic in nics: |
194 | 64938cb0 | Giorgos Verigakis | if nic.network == net:
|
195 | 64938cb0 | Giorgos Verigakis | continue
|
196 | 64938cb0 | Giorgos Verigakis | ops.append(('add', {
|
197 | 64938cb0 | Giorgos Verigakis | 'mode': 'bridged', |
198 | 64938cb0 | Giorgos Verigakis | 'link': nic.network.link.name,
|
199 | 64938cb0 | Giorgos Verigakis | 'mac': nic.mac}))
|
200 | 64938cb0 | Giorgos Verigakis | for op in ops: |
201 | 64938cb0 | Giorgos Verigakis | rapi.ModifyInstance(vm.backend_id, nics=[op], dry_run=settings.TEST) |