Revision 22ee6892 snf-cyclades-app/synnefo/logic/backend.py
b/snf-cyclades-app/synnefo/logic/backend.py | ||
---|---|---|
38 | 38 |
from django.db import transaction |
39 | 39 |
from datetime import datetime |
40 | 40 |
|
41 |
from synnefo.db.models import (Backend, VirtualMachine, Network, NetworkLink,
|
|
42 |
BACKEND_STATUSES) |
|
41 |
from synnefo.db.models import (Backend, VirtualMachine, Network, |
|
42 |
BackendNetwork, BACKEND_STATUSES)
|
|
43 | 43 |
from synnefo.logic import utils |
44 | 44 |
from synnefo.util.rapi import GanetiRapiClient |
45 | 45 |
|
46 |
|
|
47 |
|
|
48 | 46 |
log = getLogger('synnefo.logic') |
49 | 47 |
|
50 | 48 |
|
... | ... | |
59 | 57 |
def create_client(hostname, port=5080, username=None, password=None): |
60 | 58 |
return GanetiRapiClient(hostname, port, username, password) |
61 | 59 |
|
60 |
|
|
62 | 61 |
@transaction.commit_on_success |
63 | 62 |
def process_op_status(vm, etime, jobid, opcode, status, logmsg): |
64 | 63 |
"""Process a job progress notification from the backend |
... | ... | |
118 | 117 |
|
119 | 118 |
vm.nics.all().delete() |
120 | 119 |
for i, nic in enumerate(nics): |
121 |
if i == 0: |
|
120 |
network = nic.get('network', '') |
|
121 |
n = str(network) |
|
122 |
if n == settings.GANETI_PUBLIC_NETWORK: |
|
122 | 123 |
net = Network.objects.get(public=True) |
123 | 124 |
else: |
124 |
try: |
|
125 |
link = NetworkLink.objects.get(name=nic['link']) |
|
126 |
except NetworkLink.DoesNotExist: |
|
127 |
# Cannot find an instance of NetworkLink for |
|
128 |
# the link attribute specified in the notification |
|
129 |
raise NetworkLink.DoesNotExist("Cannot find a NetworkLink " |
|
130 |
"object for link='%s'" % nic['link']) |
|
131 |
net = link.network |
|
132 |
if net is None: |
|
133 |
raise Network.DoesNotExist("NetworkLink for link='%s' not " |
|
134 |
"associated with an existing Network instance." % |
|
135 |
nic['link']) |
|
125 |
pk = utils.id_from_network_name(n) |
|
126 |
net = Network.objects.get(id=pk) |
|
136 | 127 |
|
137 | 128 |
firewall = nic.get('firewall', '') |
138 | 129 |
firewall_profile = _reverse_tags.get(firewall, '') |
... | ... | |
147 | 138 |
ipv6=nic.get('ipv6', ''), |
148 | 139 |
firewall_profile=firewall_profile) |
149 | 140 |
|
150 |
# network nics modified, update network object |
|
151 |
net.save() |
|
152 |
|
|
153 | 141 |
vm.backendtime = etime |
154 | 142 |
vm.save() |
143 |
net.save() |
|
144 |
|
|
145 |
|
|
146 |
@transaction.commit_on_success |
|
147 |
def process_network_status(back_network, etime, jobid, opcode, status, logmsg): |
|
148 |
if status not in [x[0] for x in BACKEND_STATUSES]: |
|
149 |
return |
|
150 |
#raise Network.InvalidBackendMsgError(opcode, status) |
|
151 |
|
|
152 |
back_network.backendjobid = jobid |
|
153 |
back_network.backendjobstatus = status |
|
154 |
back_network.backendopcode = opcode |
|
155 |
back_network.backendlogmsg = logmsg |
|
156 |
|
|
157 |
# Notifications of success change the operating state |
|
158 |
state_for_success = BackendNetwork.OPER_STATE_FROM_OPCODE.get(opcode, None) |
|
159 |
if status == 'success' and state_for_success is not None: |
|
160 |
back_network.operstate = state_for_success |
|
161 |
if opcode == 'OP_NETWORK_REMOVE': |
|
162 |
back_network.deleted = True |
|
163 |
|
|
164 |
if status in ('canceled', 'error'): |
|
165 |
utils.update_state(back_network, 'ERROR') |
|
166 |
|
|
167 |
if (status == 'error' and opcode == 'OP_NETWORK_REMOVE' and |
|
168 |
back_network.operstate == 'ERROR'): |
|
169 |
back_network.deleted = True |
|
170 |
back_network.operstate = 'DELETED' |
|
171 |
|
|
172 |
back_network.save() |
|
155 | 173 |
|
156 | 174 |
|
157 | 175 |
@transaction.commit_on_success |
... | ... | |
336 | 354 |
utils.update_state(vm, status) |
337 | 355 |
|
338 | 356 |
|
339 |
def create_network_link(): |
|
340 |
try: |
|
341 |
last = NetworkLink.objects.order_by('-index')[0] |
|
342 |
index = last.index + 1 |
|
343 |
except IndexError: |
|
344 |
index = 1 |
|
357 |
def create_network(network, backends=None): |
|
358 |
""" Add and connect a network to backends. |
|
345 | 359 |
|
346 |
if index <= settings.GANETI_MAX_LINK_NUMBER: |
|
347 |
name = '%s%d' % (settings.GANETI_LINK_PREFIX, index) |
|
348 |
return NetworkLink.objects.create(index=index, name=name, |
|
349 |
available=True) |
|
350 |
return None # All link slots are filled |
|
360 |
@param network: Network object |
|
361 |
@param backends: List of Backend objects. None defaults to all. |
|
351 | 362 |
|
363 |
""" |
|
364 |
backend_jobs = _create_network(network, backends) |
|
365 |
connect_network(network, backend_jobs) |
|
366 |
return network |
|
352 | 367 |
|
353 |
@transaction.commit_on_success |
|
354 |
def create_network(name, user_id): |
|
355 |
try: |
|
356 |
link = NetworkLink.objects.filter(available=True)[0] |
|
357 |
except IndexError: |
|
358 |
link = create_network_link() |
|
359 |
if not link: |
|
360 |
raise NetworkLink.NotAvailable |
|
361 |
|
|
362 |
network = Network.objects.create( |
|
363 |
name=name, |
|
364 |
userid=user_id, |
|
365 |
state='ACTIVE', |
|
366 |
link=link) |
|
367 |
|
|
368 |
link.network = network |
|
369 |
link.available = False |
|
370 |
link.save() |
|
371 | 368 |
|
372 |
return network |
|
369 |
def _create_network(network, backends=None): |
|
370 |
"""Add a network to backends. |
|
371 |
@param network: Network object |
|
372 |
@param backends: List of Backend objects. None defaults to all. |
|
373 | 373 |
|
374 |
""" |
|
374 | 375 |
|
375 |
@transaction.commit_on_success |
|
376 |
def delete_network(net): |
|
377 |
link = net.link |
|
378 |
if link.name != settings.GANETI_NULL_LINK: |
|
379 |
link.available = True |
|
380 |
link.network = None |
|
381 |
link.save() |
|
382 |
|
|
383 |
for vm in net.machines.all(): |
|
384 |
disconnect_from_network(vm, net) |
|
385 |
vm.save() |
|
386 |
net.state = 'DELETED' |
|
387 |
net.save() |
|
376 |
network_type = network.public and 'public' or 'private' |
|
377 |
|
|
378 |
if not backends: |
|
379 |
backends = Backend.objects.exclude(offline=True) |
|
380 |
|
|
381 |
tags = network.backend_tag |
|
382 |
if network.dhcp: |
|
383 |
tags.append('nfdhcpd') |
|
384 |
tags = ','.join(tags) |
|
385 |
|
|
386 |
backend_jobs = [] |
|
387 |
for backend in backends: |
|
388 |
job = backend.client.CreateNetwork( |
|
389 |
network_name=network.backend_id, |
|
390 |
network=network.subnet, |
|
391 |
gateway=network.gateway, |
|
392 |
network_type=network_type, |
|
393 |
mac_prefix=network.mac_prefix, |
|
394 |
tags=tags) |
|
395 |
backend_jobs.append((backend, job)) |
|
396 |
|
|
397 |
return backend_jobs |
|
398 |
|
|
399 |
|
|
400 |
def connect_network(network, backend_jobs=None): |
|
401 |
"""Connect a network to all nodegroups. |
|
402 |
|
|
403 |
@param network: Network object |
|
404 |
@param backend_jobs: List of tuples of the form (Backend, jobs) which are |
|
405 |
the backends to connect the network and the jobs on |
|
406 |
which the connect job depends. |
|
407 |
|
|
408 |
""" |
|
388 | 409 |
|
410 |
mode = network.public and 'routed' or 'bridged' |
|
389 | 411 |
|
390 |
def connect_to_network(vm, net): |
|
391 |
nic = {'mode': 'bridged', 'link': net.link.name} |
|
392 |
vm.client.ModifyInstance(vm.backend_vm_id, nics=[('add', -1, nic)], |
|
393 |
hotplug=True, dry_run=settings.TEST) |
|
412 |
if not backend_jobs: |
|
413 |
backend_jobs = [(backend, []) for backend in |
|
414 |
Backend.objects.exclude(offline=True)] |
|
394 | 415 |
|
416 |
for backend, job in backend_jobs: |
|
417 |
client = backend.client |
|
418 |
for group in client.GetGroups(): |
|
419 |
client.ConnectNetwork(network.backend_id, group, mode, |
|
420 |
network.link, [job]) |
|
421 |
|
|
422 |
|
|
423 |
def connect_network_group(backend, network, group): |
|
424 |
"""Connect a network to a specific nodegroup of a backend. |
|
425 |
|
|
426 |
""" |
|
427 |
mode = network.public and 'routed' or 'bridged' |
|
428 |
|
|
429 |
return backend.client.ConnectNetwork(network.backend_id, group, mode, |
|
430 |
network.link) |
|
431 |
|
|
432 |
|
|
433 |
def delete_network(network, backends=None): |
|
434 |
""" Disconnect and a remove a network from backends. |
|
435 |
|
|
436 |
@param network: Network object |
|
437 |
@param backends: List of Backend objects. None defaults to all. |
|
438 |
|
|
439 |
""" |
|
440 |
backend_jobs = disconnect_network(network, backends) |
|
441 |
_delete_network(network, backend_jobs) |
|
442 |
|
|
443 |
|
|
444 |
def disconnect_network(network, backends=None): |
|
445 |
"""Disconnect a network from virtualmachines and nodegroups. |
|
446 |
|
|
447 |
@param network: Network object |
|
448 |
@param backends: List of Backend objects. None defaults to all. |
|
449 |
|
|
450 |
""" |
|
451 |
|
|
452 |
if not backends: |
|
453 |
backends = Backend.objects.exclude(offline=True) |
|
454 |
|
|
455 |
backend_jobs = [] |
|
456 |
for backend in backends: |
|
457 |
client = backend.client |
|
458 |
jobs = [] |
|
459 |
for vm in network.machines.filter(backend=backend): |
|
460 |
job = disconnect_from_network(vm, network) |
|
461 |
jobs.append(job) |
|
462 |
|
|
463 |
jobs2 = [] |
|
464 |
for group in client.GetGroups(): |
|
465 |
job = client.DisconnectNetwork(network.backend_id, group, jobs) |
|
466 |
jobs2.append(job) |
|
467 |
backend_jobs.append((backend, jobs2)) |
|
468 |
|
|
469 |
return backend_jobs |
|
470 |
|
|
471 |
|
|
472 |
def disconnect_from_network(vm, network): |
|
473 |
"""Disconnect a virtual machine from a network by removing it's nic. |
|
474 |
|
|
475 |
@param vm: VirtualMachine object |
|
476 |
@param network: Network object |
|
477 |
|
|
478 |
""" |
|
395 | 479 |
|
396 |
def disconnect_from_network(vm, net): |
|
397 | 480 |
nics = vm.nics.filter(network__public=False).order_by('index') |
398 |
ops = [('remove', nic.index, {}) for nic in nics if nic.network == net] |
|
481 |
ops = [('remove', nic.index, {}) for nic in nics if nic.network == network]
|
|
399 | 482 |
if not ops: # Vm not connected to network |
400 | 483 |
return |
401 |
vm.client.ModifyInstance(vm.backend_vm_id, nics=ops[::-1], |
|
402 |
hotplug=True, dry_run=settings.TEST) |
|
484 |
job = vm.client.ModifyInstance(vm.backend_vm_id, nics=ops[::-1], |
|
485 |
hotplug=True, dry_run=settings.TEST) |
|
486 |
|
|
487 |
return job |
|
488 |
|
|
489 |
|
|
490 |
def _delete_network(network, backend_jobs=None): |
|
491 |
if not backend_jobs: |
|
492 |
backend_jobs = [(backend, []) for backend in |
|
493 |
Backend.objects.exclude(offline=True)] |
|
494 |
for backend, jobs in backend_jobs: |
|
495 |
backend.client.DeleteNetwork(network.backend_id, jobs) |
|
496 |
|
|
497 |
|
|
498 |
def connect_to_network(vm, network): |
|
499 |
"""Connect a virtual machine to a network. |
|
500 |
|
|
501 |
@param vm: VirtualMachine object |
|
502 |
@param network: Network object |
|
503 |
|
|
504 |
""" |
|
505 |
|
|
506 |
ip = network.dhcp and 'pool' or None |
|
507 |
|
|
508 |
nic = {'ip': ip, 'network': network.backend_id} |
|
509 |
vm.client.ModifyInstance(vm.backend_vm_id, nics=[('add', nic)], |
|
510 |
hotplug=True, dry_run=settings.TEST) |
|
403 | 511 |
|
404 | 512 |
|
405 | 513 |
def set_firewall_profile(vm, profile): |
Also available in: Unified diff