Revision 3524241a snf-cyclades-app/synnefo/logic/backend.py
b/snf-cyclades-app/synnefo/logic/backend.py | ||
---|---|---|
33 | 33 |
|
34 | 34 |
import json |
35 | 35 |
|
36 |
from logging import getLogger |
|
37 | 36 |
from django.conf import settings |
38 | 37 |
from django.db import transaction |
39 | 38 |
from datetime import datetime |
40 | 39 |
|
41 | 40 |
from synnefo.db.models import (Backend, VirtualMachine, Network, |
42 |
BackendNetwork, BACKEND_STATUSES) |
|
41 |
BackendNetwork, BACKEND_STATUSES, |
|
42 |
pooled_rapi_client) |
|
43 | 43 |
from synnefo.logic import utils |
44 |
from synnefo.util.rapi import GanetiRapiClient |
|
45 | 44 |
|
46 |
log = getLogger('synnefo.logic') |
|
45 |
from logging import getLogger |
|
46 |
log = getLogger(__name__) |
|
47 | 47 |
|
48 | 48 |
|
49 | 49 |
_firewall_tags = { |
... | ... | |
54 | 54 |
_reverse_tags = dict((v.split(':')[3], k) for k, v in _firewall_tags.items()) |
55 | 55 |
|
56 | 56 |
|
57 |
def create_client(hostname, port=5080, username=None, password=None): |
|
58 |
return GanetiRapiClient(hostname, port, username, password) |
|
59 |
|
|
60 |
|
|
61 | 57 |
@transaction.commit_on_success |
62 | 58 |
def process_op_status(vm, etime, jobid, opcode, status, logmsg): |
63 | 59 |
"""Process a job progress notification from the backend |
... | ... | |
330 | 326 |
|
331 | 327 |
# Defined in settings.GANETI_CREATEINSTANCE_KWARGS |
332 | 328 |
# kw['hvparams'] = dict(serial_console=False) |
333 |
|
|
334 |
return vm.client.CreateInstance(**kw)
|
|
329 |
with pooled_rapi_client(vm) as client: |
|
330 |
return client.CreateInstance(**kw)
|
|
335 | 331 |
|
336 | 332 |
|
337 | 333 |
def delete_instance(vm): |
338 | 334 |
start_action(vm, 'DESTROY') |
339 |
vm.client.DeleteInstance(vm.backend_vm_id, dry_run=settings.TEST) |
|
335 |
with pooled_rapi_client(vm) as client: |
|
336 |
return client.DeleteInstance(vm.backend_vm_id, dry_run=settings.TEST) |
|
340 | 337 |
|
341 | 338 |
|
342 | 339 |
def reboot_instance(vm, reboot_type): |
343 | 340 |
assert reboot_type in ('soft', 'hard') |
344 |
vm.client.RebootInstance(vm.backend_vm_id, reboot_type, dry_run=settings.TEST)
|
|
345 |
log.info('Rebooting instance %s', vm.backend_vm_id)
|
|
341 |
with pooled_rapi_client(vm) as client:
|
|
342 |
return client.RebootInstance(vm.backend_vm_id, reboot_type, dry_run=settings.TEST)
|
|
346 | 343 |
|
347 | 344 |
|
348 | 345 |
def startup_instance(vm): |
349 | 346 |
start_action(vm, 'START') |
350 |
vm.client.StartupInstance(vm.backend_vm_id, dry_run=settings.TEST) |
|
347 |
with pooled_rapi_client(vm) as client: |
|
348 |
return client.StartupInstance(vm.backend_vm_id, dry_run=settings.TEST) |
|
351 | 349 |
|
352 | 350 |
|
353 | 351 |
def shutdown_instance(vm): |
354 | 352 |
start_action(vm, 'STOP') |
355 |
vm.client.ShutdownInstance(vm.backend_vm_id, dry_run=settings.TEST) |
|
353 |
with pooled_rapi_client(vm) as client: |
|
354 |
return client.ShutdownInstance(vm.backend_vm_id, dry_run=settings.TEST) |
|
356 | 355 |
|
357 | 356 |
|
358 | 357 |
def get_instance_console(vm): |
... | ... | |
369 | 368 |
# |
370 | 369 |
console = {} |
371 | 370 |
console['kind'] = 'vnc' |
372 |
i = vm.client.GetInstance(vm.backend_vm_id) |
|
371 |
|
|
372 |
with pooled_rapi_client(vm) as client: |
|
373 |
i = client.GetInstance(vm.backend_vm_id) |
|
374 |
|
|
373 | 375 |
if i['hvparams']['serial_console']: |
374 | 376 |
raise Exception("hv parameter serial_console cannot be true") |
375 | 377 |
console['host'] = i['pnode'] |
376 | 378 |
console['port'] = i['network_port'] |
377 | 379 |
|
378 | 380 |
return console |
379 |
# return rapi.GetInstanceConsole(vm.backend_vm_id) |
|
380 |
|
|
381 |
|
|
382 |
def request_status_update(vm): |
|
383 |
return vm.client.GetInstanceInfo(vm.backend_vm_id) |
|
384 | 381 |
|
385 | 382 |
|
386 |
def update_status(vm, status): |
|
387 |
utils.update_state(vm, status) |
|
383 |
def get_instance_info(vm): |
|
384 |
with pooled_rapi_client(vm) as client: |
|
385 |
return client.GetInstanceInfo(vm.backend_vm_id) |
|
388 | 386 |
|
389 | 387 |
|
390 |
def create_network(network, backends=None): |
|
391 |
""" Add and connect a network to backends. |
|
392 |
|
|
393 |
@param network: Network object |
|
394 |
@param backends: List of Backend objects. None defaults to all. |
|
395 |
|
|
396 |
""" |
|
397 |
backend_jobs = _create_network(network, backends) |
|
398 |
connect_network(network, backend_jobs) |
|
399 |
return network |
|
388 |
def create_network(network, backends=None, connect=True): |
|
389 |
"""Create and connect a network.""" |
|
390 |
if not backends: |
|
391 |
backends = Backend.objects.exclude(offline=True) |
|
400 | 392 |
|
393 |
for backend in backends: |
|
394 |
create_jobID = _create_network(network, backend) |
|
395 |
if connect: |
|
396 |
connect_network(network, backend, create_jobID) |
|
401 | 397 |
|
402 |
def _create_network(network, backends=None): |
|
403 |
"""Add a network to backends. |
|
404 |
@param network: Network object |
|
405 |
@param backends: List of Backend objects. None defaults to all. |
|
406 | 398 |
|
407 |
""" |
|
399 |
def _create_network(network, backend): |
|
400 |
"""Create a network.""" |
|
408 | 401 |
|
409 | 402 |
network_type = network.public and 'public' or 'private' |
410 |
if not backends: |
|
411 |
backends = Backend.objects.exclude(offline=True) |
|
412 | 403 |
|
413 | 404 |
tags = network.backend_tag |
414 | 405 |
if network.dhcp: |
415 | 406 |
tags.append('nfdhcpd') |
416 | 407 |
tags = ','.join(tags) |
417 | 408 |
|
418 |
backend_jobs = [] |
|
419 |
for backend in backends: |
|
420 |
try: |
|
421 |
backend_network = BackendNetwork.objects.get(network=network, |
|
422 |
backend=backend) |
|
423 |
except BackendNetwork.DoesNotExist: |
|
424 |
raise Exception("BackendNetwork for network '%s' in backend '%s'"\ |
|
425 |
" does not exist" % (network.id, backend.id)) |
|
426 |
job = backend.client.CreateNetwork( |
|
427 |
network_name=network.backend_id, |
|
428 |
network=network.subnet, |
|
429 |
gateway=network.gateway, |
|
430 |
network_type=network_type, |
|
431 |
mac_prefix=backend_network.mac_prefix, |
|
432 |
tags=tags) |
|
433 |
backend_jobs.append((backend, job)) |
|
434 |
|
|
435 |
return backend_jobs |
|
436 |
|
|
437 |
|
|
438 |
def connect_network(network, backend_jobs=None): |
|
439 |
"""Connect a network to all nodegroups. |
|
440 |
|
|
441 |
@param network: Network object |
|
442 |
@param backend_jobs: List of tuples of the form (Backend, jobs) which are |
|
443 |
the backends to connect the network and the jobs on |
|
444 |
which the connect job depends. |
|
445 |
|
|
446 |
""" |
|
447 |
|
|
448 |
if network.type in ('PUBLIC_ROUTED', 'CUSTOM_ROUTED'): |
|
449 |
mode = 'routed' |
|
450 |
else: |
|
451 |
mode = 'bridged' |
|
452 |
|
|
453 |
if not backend_jobs: |
|
454 |
backend_jobs = [(backend, []) for backend in |
|
455 |
Backend.objects.exclude(offline=True)] |
|
456 |
|
|
457 |
for backend, job in backend_jobs: |
|
458 |
client = backend.client |
|
459 |
for group in client.GetGroups(): |
|
409 |
try: |
|
410 |
bn = BackendNetwork.objects.get(network=network, backend=backend) |
|
411 |
mac_prefix = bn.mac_prefix |
|
412 |
except BackendNetwork.DoesNotExist: |
|
413 |
raise Exception("BackendNetwork for network '%s' in backend '%s'"\ |
|
414 |
" does not exist" % (network.id, backend.id)) |
|
415 |
|
|
416 |
with pooled_rapi_client(backend) as client: |
|
417 |
return client.CreateNetwork(network_name=network.backend_id, |
|
418 |
network=network.subnet, |
|
419 |
gateway=network.gateway, |
|
420 |
network_type=network_type, |
|
421 |
mac_prefix=mac_prefix, |
|
422 |
tags=tags) |
|
423 |
|
|
424 |
|
|
425 |
def connect_network(network, backend, depend_job=None, group=None): |
|
426 |
"""Connect a network to nodegroups.""" |
|
427 |
mode = "routed" if "ROUTED" in network.type else "bridged" |
|
428 |
|
|
429 |
with pooled_rapi_client(backend) as client: |
|
430 |
if group: |
|
460 | 431 |
client.ConnectNetwork(network.backend_id, group, mode, |
461 |
network.link, [job]) |
|
462 |
|
|
463 |
|
|
464 |
def connect_network_group(backend, network, group): |
|
465 |
"""Connect a network to a specific nodegroup of a backend. |
|
466 |
|
|
467 |
""" |
|
468 |
if network.type in ('PUBLIC_ROUTED', 'CUSTOM_ROUTED'): |
|
469 |
mode = 'routed' |
|
470 |
else: |
|
471 |
mode = 'bridged' |
|
472 |
|
|
473 |
return backend.client.ConnectNetwork(network.backend_id, group, mode, |
|
474 |
network.link) |
|
475 |
|
|
476 |
|
|
477 |
def delete_network(network, backends=None): |
|
478 |
""" Disconnect and a remove a network from backends. |
|
479 |
|
|
480 |
@param network: Network object |
|
481 |
@param backends: List of Backend objects. None defaults to all. |
|
482 |
|
|
483 |
""" |
|
484 |
backend_jobs = disconnect_network(network, backends) |
|
485 |
_delete_network(network, backend_jobs) |
|
486 |
|
|
487 |
|
|
488 |
def disconnect_network(network, backends=None): |
|
489 |
"""Disconnect a network from all nodegroups. |
|
432 |
network.link, [depend_job]) |
|
433 |
else: |
|
434 |
for group in client.GetGroups(): |
|
435 |
client.ConnectNetwork(network.backend_id, group, mode, |
|
436 |
network.link, [depend_job]) |
|
490 | 437 |
|
491 |
@param network: Network object |
|
492 |
@param backends: List of Backend objects. None defaults to all. |
|
493 |
|
|
494 |
""" |
|
495 | 438 |
|
439 |
def delete_network(network, backends=None, disconnect=True): |
|
496 | 440 |
if not backends: |
497 | 441 |
backends = Backend.objects.exclude(offline=True) |
498 | 442 |
|
499 |
backend_jobs = [] |
|
500 | 443 |
for backend in backends: |
501 |
client = backend.client |
|
502 |
jobs = [] |
|
503 |
for group in client.GetGroups(): |
|
504 |
job = client.DisconnectNetwork(network.backend_id, group) |
|
505 |
jobs.append(job) |
|
506 |
backend_jobs.append((backend, jobs)) |
|
507 |
|
|
508 |
return backend_jobs |
|
509 |
|
|
510 |
|
|
511 |
def disconnect_from_network(vm, nic): |
|
512 |
"""Disconnect a virtual machine from a network by removing it's nic. |
|
444 |
disconnect_jobIDs = [] |
|
445 |
if disconnect: |
|
446 |
disconnect_jobIDs = disconnect_network(network, backend) |
|
447 |
_delete_network(network, backend, disconnect_jobIDs) |
|
513 | 448 |
|
514 |
@param vm: VirtualMachine object |
|
515 |
@param network: Network object |
|
516 | 449 |
|
517 |
""" |
|
518 |
|
|
519 |
op = [('remove', nic.index, {})] |
|
520 |
return vm.client.ModifyInstance(vm.backend_vm_id, nics=op, |
|
521 |
hotplug=settings.GANETI_USE_HOTPLUG, |
|
522 |
dry_run=settings.TEST) |
|
450 |
def _delete_network(network, backend, depend_jobs=[]): |
|
451 |
with pooled_rapi_client(backend) as client: |
|
452 |
return client.DeleteNetwork(network.backend_id, depend_jobs) |
|
523 | 453 |
|
524 | 454 |
|
525 |
def _delete_network(network, backend_jobs=None): |
|
526 |
if not backend_jobs: |
|
527 |
backend_jobs = [(backend, []) for backend in |
|
528 |
Backend.objects.exclude(offline=True)] |
|
529 |
for backend, jobs in backend_jobs: |
|
530 |
backend.client.DeleteNetwork(network.backend_id, jobs) |
|
455 |
def disconnect_network(network, backend, group=None): |
|
456 |
with pooled_rapi_client(backend) as client: |
|
457 |
if group: |
|
458 |
return [client.DisconnectNetwork(network.backend_id, group)] |
|
459 |
else: |
|
460 |
jobs = [] |
|
461 |
for group in client.GetGroups(): |
|
462 |
job = client.DisconnectNetwork(network.backend_id, group) |
|
463 |
jobs.append(job) |
|
464 |
return jobs |
|
531 | 465 |
|
532 | 466 |
|
533 | 467 |
def connect_to_network(vm, network, address): |
534 |
"""Connect a virtual machine to a network. |
|
535 |
|
|
536 |
@param vm: VirtualMachine object |
|
537 |
@param network: Network object |
|
468 |
nic = {'ip': address, 'network': network.backend_id} |
|
538 | 469 |
|
539 |
""" |
|
470 |
with pooled_rapi_client(vm) as client: |
|
471 |
return client.ModifyInstance(vm.backend_vm_id, nics=[('add', nic)], |
|
472 |
hotplug=settings.GANETI_USE_HOTPLUG, |
|
473 |
dry_run=settings.TEST) |
|
540 | 474 |
|
541 |
# ip = network.dhcp and 'pool' or None |
|
542 | 475 |
|
543 |
nic = {'ip': address, 'network': network.backend_id} |
|
544 |
vm.client.ModifyInstance(vm.backend_vm_id, nics=[('add', nic)], |
|
545 |
hotplug=settings.GANETI_USE_HOTPLUG, |
|
546 |
dry_run=settings.TEST) |
|
476 |
def disconnect_from_network(vm, nic): |
|
477 |
op = [('remove', nic.index, {})] |
|
478 |
with pooled_rapi_client(vm) as client: |
|
479 |
return client.ModifyInstance(vm.backend_vm_id, nics=op, |
|
480 |
hotplug=settings.GANETI_USE_HOTPLUG, |
|
481 |
dry_run=settings.TEST) |
|
547 | 482 |
|
548 | 483 |
|
549 | 484 |
def set_firewall_profile(vm, profile): |
... | ... | |
552 | 487 |
except KeyError: |
553 | 488 |
raise ValueError("Unsopported Firewall Profile: %s" % profile) |
554 | 489 |
|
555 |
client = vm.client |
|
556 |
# Delete all firewall tags |
|
557 |
for t in _firewall_tags.values(): |
|
558 |
client.DeleteInstanceTags(vm.backend_vm_id, [t], dry_run=settings.TEST) |
|
490 |
with pooled_rapi_client(vm) as client: |
|
491 |
# Delete all firewall tags |
|
492 |
for t in _firewall_tags.values(): |
|
493 |
client.DeleteInstanceTags(vm.backend_vm_id, [t], |
|
494 |
dry_run=settings.TEST) |
|
559 | 495 |
|
560 |
client.AddInstanceTags(vm.backend_vm_id, [tag], dry_run=settings.TEST) |
|
496 |
client.AddInstanceTags(vm.backend_vm_id, [tag], dry_run=settings.TEST)
|
|
561 | 497 |
|
562 |
# XXX NOP ModifyInstance call to force process_net_status to run |
|
563 |
# on the dispatcher |
|
564 |
vm.client.ModifyInstance(vm.backend_vm_id,
|
|
565 |
os_name=settings.GANETI_CREATEINSTANCE_KWARGS['os']) |
|
498 |
# XXX NOP ModifyInstance call to force process_net_status to run
|
|
499 |
# on the dispatcher
|
|
500 |
client.ModifyInstance(vm.backend_vm_id,
|
|
501 |
os_name=settings.GANETI_CREATEINSTANCE_KWARGS['os'])
|
|
566 | 502 |
|
567 | 503 |
|
568 | 504 |
def get_ganeti_instances(backend=None, bulk=False): |
569 |
Instances = [c.client.GetInstances(bulk=bulk)\ |
|
570 |
for c in get_backends(backend)] |
|
571 |
return reduce(list.__add__, Instances, []) |
|
505 |
instances = [] |
|
506 |
for backend in get_backends(backend): |
|
507 |
with pooled_rapi_client(backend) as client: |
|
508 |
instances.append(client.GetInstances(bulk=bulk)) |
|
509 |
|
|
510 |
return reduce(list.__add__, instances, []) |
|
572 | 511 |
|
573 | 512 |
|
574 | 513 |
def get_ganeti_nodes(backend=None, bulk=False): |
575 |
Nodes = [c.client.GetNodes(bulk=bulk) for c in get_backends(backend)] |
|
576 |
return reduce(list.__add__, Nodes, []) |
|
514 |
nodes = [] |
|
515 |
for backend in get_backends(backend): |
|
516 |
with pooled_rapi_client(backend) as client: |
|
517 |
nodes.append(client.GetNodes(bulk=bulk)) |
|
518 |
|
|
519 |
return reduce(list.__add__, nodes, []) |
|
577 | 520 |
|
578 | 521 |
|
579 | 522 |
def get_ganeti_jobs(backend=None, bulk=False): |
580 |
Jobs = [c.client.GetJobs(bulk=bulk) for c in get_backends(backend)] |
|
581 |
return reduce(list.__add__, Jobs, []) |
|
523 |
jobs = [] |
|
524 |
for backend in get_backends(backend): |
|
525 |
with pooled_rapi_client(backend) as client: |
|
526 |
jobs.append(client.GetJobs(bulk=bulk)) |
|
527 |
return reduce(list.__add__, jobs, []) |
|
582 | 528 |
|
583 | 529 |
## |
584 | 530 |
## |
... | ... | |
637 | 583 |
the real memory used, due to kvm's memory de-duplication. |
638 | 584 |
|
639 | 585 |
""" |
640 |
instances = backend.client.GetInstances(bulk=True) |
|
586 |
with pooled_rapi_client(backend) as client: |
|
587 |
instances = client.GetInstances(bulk=True) |
|
641 | 588 |
mem = 0 |
642 | 589 |
for i in instances: |
643 | 590 |
mem += i['oper_ram'] |
... | ... | |
657 | 604 |
|
658 | 605 |
|
659 | 606 |
def _create_network_synced(network, backend): |
660 |
client = backend.client
|
|
661 |
|
|
662 |
backend_jobs = _create_network(network, [backend])
|
|
663 |
(_, job) = backend_jobs[0]
|
|
664 |
return wait_for_job(client, job)
|
|
607 |
with pooled_rapi_client(backend) as client:
|
|
608 |
backend_jobs = _create_network(network, [backend]) |
|
609 |
(_, job) = backend_jobs[0]
|
|
610 |
result = wait_for_job(client, job)
|
|
611 |
return result
|
|
665 | 612 |
|
666 | 613 |
|
667 | 614 |
def connect_network_synced(network, backend): |
... | ... | |
669 | 616 |
mode = 'routed' |
670 | 617 |
else: |
671 | 618 |
mode = 'bridged' |
672 |
client = backend.client |
|
673 |
|
|
674 |
for group in client.GetGroups(): |
|
675 |
job = client.ConnectNetwork(network.backend_id, group, mode, |
|
676 |
network.link) |
|
677 |
result = wait_for_job(client, job) |
|
678 |
if result[0] != 'success': |
|
679 |
return result |
|
619 |
with pooled_rapi_client(backend) as client: |
|
620 |
for group in client.GetGroups(): |
|
621 |
job = client.ConnectNetwork(network.backend_id, group, mode, |
|
622 |
network.link) |
|
623 |
result = wait_for_job(client, job) |
|
624 |
if result[0] != 'success': |
|
625 |
return result |
|
680 | 626 |
|
681 | 627 |
return result |
682 | 628 |
|
Also available in: Unified diff