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