Revision 1a894bfe

b/snf-cyclades-app/synnefo/api/management/commands/listservers.py
36 36
from django.core.management.base import BaseCommand, CommandError
37 37

  
38 38
from synnefo.api.util import get_image
39
from synnefo.db.models import VirtualMachine
39
from synnefo.db.models import VirtualMachine, Backend
40 40

  
41 41

  
42 42
class Command(BaseCommand):
......
53 53
            dest='build',
54 54
            default=False,
55 55
            help="List only servers in the building state"),
56
        make_option('--non-deleted', action='store_true', dest='non_deleted',
57
                    default=False,
58
                    help="List only non-deleted servers"),
59
        make_option('--backend_id', dest='backend_id',
60
                    help="List only servers of the specified backend")
56 61
        )
57 62
    
58 63
    def handle(self, *args, **options):
59 64
        if args:
60 65
            raise CommandError("Command doesn't accept any arguments")
61
        
62
        servers = VirtualMachine.objects.all()
66

  
67
        if options['backend_id']:
68
            servers = \
69
            Backend.objects.get(id=options['backend_id']).virtual_machines
70
        else:
71
            servers = VirtualMachine.objects
72

  
73
        if options['non_deleted']:
74
            servers = servers.filter(deleted=False)
75
        else:
76
            servers = servers.all()
77

  
63 78
        if options['build']:
64 79
            servers = servers.filter(operstate='BUILD')
65 80
        
66
        labels = ('id', 'name', 'owner', 'flavor', 'image', 'state')
67
        columns = (3, 12, 20, 11, 12, 9)
81
        labels = ('id', 'name', 'owner', 'flavor', 'image', 'state',
82
                  'backend')
83
        columns = (3, 12, 20, 11, 12, 9, 40)
68 84
        
69 85
        if not options['csv']:
70 86
            line = ' '.join(l.rjust(w) for l, w in zip(labels, columns))
......
83 99
                image = get_image(server.imageid, server.userid)['name']
84 100
            except:
85 101
                image = server.imageid
86
            fields = (id, name, server.userid, flavor, image, server.operstate)
102
            fields = (id, name, server.userid, flavor, image, server.operstate,
103
                      str(server.backend))
87 104
            
88 105
            if options['csv']:
89 106
                line = '|'.join(fields)
b/snf-cyclades-app/synnefo/logic/backend.py
36 36
from logging import getLogger
37 37
from django.conf import settings
38 38
from django.db import transaction
39
from datetime import datetime
39 40

  
40 41
from synnefo.db.models import (Backend, VirtualMachine, Network, NetworkLink)
41 42
from synnefo.logic import utils
......
55 56

  
56 57

  
57 58
def create_client(hostname, port=5080, username=None, password=None):
58
    return GanetiRapiClient(hostname=hostname,
59
                            port=port,
60
                            username=username,
61
                            password=password)
59
    return GanetiRapiClient(hostname, port, username, password)
62 60

  
63 61
@transaction.commit_on_success
64 62
def process_op_status(vm, etime, jobid, opcode, status, logmsg):
......
423 421

  
424 422

  
425 423
def get_ganeti_instances(backend=None, bulk=False):
426
    Instances = [c.client.GetInstances(bulk=bulk) for c in get_backends(backend)]
424
    Instances = [c.client.GetInstances(bulk=bulk)\
425
                 for c in get_backends(backend)]
427 426
    return reduce(list.__add__, Instances, [])
428 427

  
429 428

  
......
439 438
##
440 439
##
441 440
##
441

  
442

  
442 443
def get_backends(backend=None):
443 444
    if backend:
444 445
        return [backend]
445 446
    return Backend.objects.all()
446 447

  
447 448

  
449
def get_physical_resources(backend):
450
    """ Get the physical resources of a backend.
451

  
452
    Get the resources of a backend as reported by the backend (not the db).
448 453

  
454
    """
455
    nodes = get_ganeti_nodes(backend, bulk=True)
456
    attr = ['mfree', 'mtotal', 'dfree', 'dtotal', 'pinst_cnt', 'ctotal']
457
    res = {}
458
    for a in attr:
459
        res[a] = 0
460
    for n in nodes:
461
        # Filter out drained, offline and not vm_capable nodes since they will
462
        # not take part in the vm allocation process
463
        if n['vm_capable'] and not n['drained'] and not n['offline']\
464
           and n['cnodes']:
465
            for a in attr:
466
                res[a] += int(n[a])
467
    return res
468

  
469

  
470
def update_resources(backend, resources=None):
471
    """ Update the state of the backend resources in db.
472

  
473
    """
449 474

  
475
    if not resources:
476
        resources = get_physical_resources(backend)
450 477

  
478
    backend.mfree = resources['mfree']
479
    backend.mtotal = resources['mtotal']
480
    backend.dfree = resources['dfree']
481
    backend.dtotal = resources['dtotal']
482
    backend.pinst_cnt = resources['pinst_cnt']
483
    backend.ctotal = resources['ctotal']
484
    backend.updated = datetime.now()
485
    backend.save()
486

  
487

  
488
def get_memory_from_instances(backend):
489
    """ Get the memory that is used from instances.
490

  
491
    Get the used memory of a backend. Note: This is different for
492
    the real memory used, due to kvm's memory de-duplication.
493

  
494
    """
495
    instances = backend.client.GetInstances(bulk=True)
496
    mem = 0
497
    for i in instances:
498
        mem += i['oper_ram']
499
    return mem
b/snf-cyclades-app/synnefo/logic/management/commands/backend_create.py
1
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or without
4
# modification, are permitted provided that the following conditions
5
# are met:
6
#
7
#   1. Redistributions of source code must retain the above copyright
8
#      notice, this list of conditions and the following disclaimer.
9
#
10
#  2. Redistributions in binary form must reproduce the above copyright
11
#     notice, this list of conditions and the following disclaimer in the
12
#     documentation and/or other materials provided with the distribution.
13
#
14
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
15
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
18
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
# SUCH DAMAGE.
25
#
26
# The views and conclusions contained in the software and documentation are
27
# those of the authors and should not be interpreted as representing official
28
# policies, either expressed or implied, of GRNET S.A.
29
#
30

  
31
from optparse import make_option
32
from django.core.management.base import BaseCommand, CommandError
33

  
34
from synnefo.db.models import Backend
35
from django.db.utils import IntegrityError
36
from synnefo.logic.backend import get_physical_resources, \
37
                                  update_resources, \
38
                                  create_client
39
from synnefo.util.rapi import GanetiApiError
40

  
41

  
42
class Command(BaseCommand):
43
    can_import_settings = True
44

  
45
    help = 'Create a new backend.'
46
    output_transaction = True  # The management command runs inside
47
                               # an SQL transaction
48
    option_list = BaseCommand.option_list + (
49
        make_option('--clustername', dest='clustername'),
50
        make_option('--port', dest='port', default=5080),
51
        make_option('--username', dest='username'),
52
        make_option('--password', dest='password'),
53
        make_option('--drained', action='store_true',
54
                    dest='drained',default=False,
55
                    help="Set as drained to exclude from allocations"),
56
        make_option('--no-check', action='store_false',
57
                    dest='check', default=True,
58
                    help="Do not perform credentials check and resources update")
59
        )
60

  
61
    def handle(self, **options):
62
        clustername = options['clustername']
63
        port= options['port']
64
        username = options['username']
65
        password = options['password']
66
        drained = options['drained']
67

  
68
        if not (clustername and username and password):
69
            raise CommandError("Clustername, username and password must be supplied")
70

  
71
        # Ensure correctness of credentials
72
        if options['check']:
73
            self.stdout.write('Checking connectivity and credentials.\n')
74
            try:
75
                client = create_client(clustername, port, username, password)
76
                # This command will raise an exception if there is no write-access
77
                client.ModifyCluster()
78
            except GanetiApiError as e:
79
                self.stdout.write('Check failed:\n%s\n' %e)
80
                return
81
            else:
82
                self.stdout.write('Check passed.\n')
83

  
84
        # Create the new backend in database
85
        try:
86
            backend = Backend.objects.create(clustername=clustername,
87
                                             port=port,
88
                                             username=username,
89
                                             password=password,
90
                                             drained=drained)
91
        except IntegrityError as e:
92
            self.stdout.write("Cannot create backend: %s\n" % e)
93
        else:
94
            if options['check']:
95
                self.stdout.write('\nRetriving backend resources:\n')
96
                resources = get_physical_resources(backend)
97
                attr = ['mfree', 'mtotal', 'dfree', 'dtotal', 'pinst_cnt', 'ctotal']
98
                for a in attr:
99
                    self.stdout.write(a + ' : ' + str(resources[a])+'\n')
100
                update_resources(backend, resources)
101

  
102
            self.stdout.write('\nSuccessfully created backend with id %d\n' %
103
                              backend.id)
104

  
b/snf-cyclades-app/synnefo/logic/management/commands/backend_list.py
1
# Copyright 2012 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

  
34
from optparse import make_option
35
from django.core.management.base import BaseCommand, CommandError
36

  
37
from synnefo.db.models import Backend
38

  
39

  
40
class Command(BaseCommand):
41
    help = "List backends"
42

  
43
    option_list = BaseCommand.option_list + (
44
        make_option('-c',
45
            action='store_true',
46
            dest='csv',
47
            default=False,
48
            help="Use pipes to separate values"),
49
        )
50

  
51
    def handle(self, *args, **options):
52
        if args:
53
            raise CommandError("Command doesn't accept any arguments")
54

  
55
        backends = Backend.objects.order_by('id')
56

  
57
        labels = ('id', 'clustername', 'port', 'username', "vm's", 'drained',
58
                  'offline')
59
        columns = (3, 50, 5, 10, 4, 6, 6)
60

  
61
        if not options['csv']:
62
            line = ' '.join(l.rjust(w) for l, w in zip(labels, columns))
63
            sep = '-' * len(line)
64
            self.stdout.write(sep + '\n')
65
            self.stdout.write(line + '\n')
66
            self.stdout.write(sep + '\n')
67

  
68
        for backend in backends:
69
            id = str(backend.id)
70
            vms = str(backend.virtual_machines.filter(deleted=False).count())
71
            fields = (id, backend.clustername, str(backend.port),
72
                      backend.username, vms, str(backend.drained),
73
                      str(backend.offline))
74

  
75
            if options['csv']:
76
                line = '|'.join(fields)
77
            else:
78
                line = ' '.join(f.rjust(w) for f, w in zip(fields, columns))
79

  
80
            self.stdout.write(line.encode('utf8') + '\n')
b/snf-cyclades-app/synnefo/logic/management/commands/backend_modify.py
1
# Copyright 2012 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

  
34
from optparse import make_option
35
from django.core.management.base import BaseCommand, CommandError
36

  
37
from synnefo.db.models import Backend
38

  
39

  
40
class Command(BaseCommand):
41
    args = "<backend ID>"
42
    help = "Modify a backend"
43

  
44
    option_list = BaseCommand.option_list + (
45
        make_option('--clustername',
46
            dest='clustername',
47
            help="Set backend's clustername"),
48
        make_option('--port',
49
            dest='port',
50
            help="Set backend's port"),
51
        make_option('--username',
52
            dest='username',
53
            help="Set backend'username"),
54
        make_option('--password',
55
            dest='password',
56
            help="Set backend's password"),
57
        make_option('--drained',
58
            dest='drained',
59
            action='store_true',
60
            default=False,
61
            help="Set the backend as drained to exclude from allocation "\
62
                 "operations"),
63
        make_option('--no-drained',
64
            dest='drained',
65
            action='store_false'),
66
        make_option('--offline',
67
            dest='offline',
68
            action='store_true',
69
            default=False,
70
            help="Set the backend as offline to not communicate in order "\
71
                 "to avoid delays"),
72
        make_option('--no-offline',
73
            dest='offline',
74
            action='store_false')
75
        )
76

  
77
    def handle(self, *args, **options):
78
        if len(args) != 1:
79
            raise CommandError("Please provide a backend ID")
80

  
81
        try:
82
            backend_id = int(args[0])
83
            backend = Backend.objects.get(id=backend_id)
84
        except ValueError:
85
            raise CommandError("Invalid backend ID")
86
        except Backend.DoesNotExist:
87
            raise CommandError("Backend not found in DB")
88

  
89
        # Ensure fields correspondence with options and Backend model
90
        fields = ('clustername', 'port', 'username', 'password', 'drained',
91
                  'offline')
92
        for field in fields:
93
            value = options.get(field)
94
            if value is not None:
95
                backend.__setattr__(field, value)
96

  
97
        backend.save()

Also available in: Unified diff