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