Commit b8de83f7 authored by Christos Stavrakakis's avatar Christos Stavrakakis
Browse files

Merge branch 'feature-ganeti-xen' into develop

parents dcc7f727 a44fc4c2
......@@ -11,22 +11,22 @@
## The following dictionary defines deployment-specific
## arguments to the RAPI CreateInstance call.
## At a minimum it should contain the
## 'disk_template', 'os_provider', and 'hvparams' keys.
## 'os' and 'hvparams' keys.
##
## More specifically:
## a) disk_template:
## The disk template to use when creating the instance.
## Suggested values: 'plain', or 'drbd'.
## b) os:
## a) os:
## The OS provider to use (customized Ganeti Instance Image)
## c) hvparams:
## Hypervisor-specific parameters (serial_console = False, see #785)
## d) If using the DRBD disk_template, you may want to include
## b) hvparams:
## Hypervisor-specific parameters (serial_console = False, see #785),
## for each hypervisor(currently 'kvm'. 'xen-pvm' and 'xen-hvm').
## c) If using the DRBD disk_template, you may want to include
## wait_for_sync = False (see #835).
##
#GANETI_CREATEINSTANCE_KWARGS = {
# 'os': 'snf-image+default',
# 'hvparams': {'serial_console': False},
# 'hvparams': {'kvm': {'serial_console': False},
# 'xen-pvm: {},
# 'xen-hvm: {}}
# 'wait_for_sync': False}
#
## If True, qemu-kvm will hotplug a NIC when connecting a vm to
......
......@@ -11,22 +11,22 @@ BACKEND_PREFIX_ID = "snf-"
# The following dictionary defines deployment-specific
# arguments to the RAPI CreateInstance call.
# At a minimum it should contain the
# 'disk_template', 'os_provider', and 'hvparams' keys.
# 'os' and 'hvparams' keys.
#
# More specifically:
# a) disk_template:
# The disk template to use when creating the instance.
# Suggested values: 'plain', or 'drbd'.
# b) os:
# a) os:
# The OS provider to use (customized Ganeti Instance Image)
# c) hvparams:
# Hypervisor-specific parameters (serial_console = False, see #785)
# d) If using the DRBD disk_template, you may want to include
# b) hvparams:
# Hypervisor-specific parameters (serial_console = False, see #785),
# for each hypervisor(currently 'kvm', 'xen-pvm' and 'xen-hvm').
# c) If using the DRBD disk_template, you may want to include
# wait_for_sync = False (see #835).
#
GANETI_CREATEINSTANCE_KWARGS = {
'os': 'snf-image+default',
'hvparams': {'serial_console': False},
'hvparams': {"kvm": {'serial_console': False},
"xen-pvm": {},
"xen-hvm": {}},
'wait_for_sync': False}
# If True, qemu-kvm will hotplug a NIC when connecting a vm to
......
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'Backend.hypervisor'
db.add_column('db_backend', 'hypervisor', self.gf('django.db.models.fields.CharField')(default='kvm', max_length=32), keep_default=False)
def backwards(self, orm):
# Deleting field 'Backend.hypervisor'
db.delete_column('db_backend', 'hypervisor')
models = {
'db.backend': {
'Meta': {'object_name': 'Backend'},
'clustername': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'}),
'ctotal': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'dfree': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'drained': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'dtotal': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'hash': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
'hypervisor': ('django.db.models.fields.CharField', [], {'default': "'kvm'", 'max_length': '32'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'index': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'unique': 'True'}),
'mfree': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'mtotal': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'offline': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'password_hash': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}),
'pinst_cnt': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'port': ('django.db.models.fields.PositiveIntegerField', [], {'default': '5080'}),
'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'})
},
'db.backendnetwork': {
'Meta': {'unique_together': "(('network', 'backend'),)", 'object_name': 'BackendNetwork'},
'backend': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'networks'", 'to': "orm['db.Backend']"}),
'backendjobid': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
'backendjobstatus': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
'backendlogmsg': ('django.db.models.fields.TextField', [], {'null': 'True'}),
'backendopcode': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
'backendtime': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(1, 1, 1, 0, 0)'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'mac_prefix': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
'network': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'backend_networks'", 'to': "orm['db.Network']"}),
'operstate': ('django.db.models.fields.CharField', [], {'default': "'PENDING'", 'max_length': '30'}),
'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
},
'db.bridgepooltable': {
'Meta': {'object_name': 'BridgePoolTable'},
'available_map': ('django.db.models.fields.TextField', [], {'default': "''"}),
'base': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'offset': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
'reserved_map': ('django.db.models.fields.TextField', [], {'default': "''"}),
'size': ('django.db.models.fields.IntegerField', [], {})
},
'db.flavor': {
'Meta': {'unique_together': "(('cpu', 'ram', 'disk', 'disk_template'),)", 'object_name': 'Flavor'},
'cpu': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'disk': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'disk_template': ('django.db.models.fields.CharField', [], {'default': "'plain'", 'max_length': '32'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'ram': ('django.db.models.fields.IntegerField', [], {'default': '0'})
},
'db.ippooltable': {
'Meta': {'object_name': 'IPPoolTable'},
'available_map': ('django.db.models.fields.TextField', [], {'default': "''"}),
'base': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'offset': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
'reserved_map': ('django.db.models.fields.TextField', [], {'default': "''"}),
'size': ('django.db.models.fields.IntegerField', [], {})
},
'db.macprefixpooltable': {
'Meta': {'object_name': 'MacPrefixPoolTable'},
'available_map': ('django.db.models.fields.TextField', [], {'default': "''"}),
'base': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'offset': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
'reserved_map': ('django.db.models.fields.TextField', [], {'default': "''"}),
'size': ('django.db.models.fields.IntegerField', [], {})
},
'db.network': {
'Meta': {'object_name': 'Network'},
'action': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '32', 'null': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True', 'blank': 'True'}),
'dhcp': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
'flavor': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
'gateway': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
'gateway6': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'link': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
'mac_prefix': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
'machines': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['db.VirtualMachine']", 'through': "orm['db.NetworkInterface']", 'symmetrical': 'False'}),
'mode': ('django.db.models.fields.CharField', [], {'max_length': '16', 'null': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'pool': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'network'", 'unique': 'True', 'null': 'True', 'to': "orm['db.IPPoolTable']"}),
'public': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True', 'blank': 'True'}),
'serial': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'network'", 'null': 'True', 'to': "orm['db.QuotaHolderSerial']"}),
'state': ('django.db.models.fields.CharField', [], {'default': "'PENDING'", 'max_length': '32'}),
'subnet': ('django.db.models.fields.CharField', [], {'default': "'10.0.0.0/24'", 'max_length': '32'}),
'subnet6': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True'}),
'tags': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'userid': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'db_index': 'True'})
},
'db.networkinterface': {
'Meta': {'object_name': 'NetworkInterface'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'dirty': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'firewall_profile': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'index': ('django.db.models.fields.IntegerField', [], {}),
'ipv4': ('django.db.models.fields.CharField', [], {'max_length': '15', 'null': 'True'}),
'ipv6': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
'mac': ('django.db.models.fields.CharField', [], {'max_length': '32', 'unique': 'True', 'null': 'True'}),
'machine': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nics'", 'to': "orm['db.VirtualMachine']"}),
'network': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'nics'", 'to': "orm['db.Network']"}),
'state': ('django.db.models.fields.CharField', [], {'default': "'ACTIVE'", 'max_length': '32'}),
'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
},
'db.quotaholderserial': {
'Meta': {'object_name': 'QuotaHolderSerial'},
'accept': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'pending': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True', 'blank': 'True'}),
'resolved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'serial': ('django.db.models.fields.BigIntegerField', [], {'primary_key': 'True', 'db_index': 'True'})
},
'db.virtualmachine': {
'Meta': {'object_name': 'VirtualMachine'},
'action': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
'backend': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'virtual_machines'", 'null': 'True', 'to': "orm['db.Backend']"}),
'backend_hash': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
'backendjobid': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
'backendjobstatus': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
'backendlogmsg': ('django.db.models.fields.TextField', [], {'null': 'True'}),
'backendopcode': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
'backendtime': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(1, 1, 1, 0, 0)'}),
'buildpercentage': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True', 'blank': 'True'}),
'flavor': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['db.Flavor']"}),
'hostid': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'imageid': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'operstate': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True'}),
'serial': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'virtual_machine'", 'null': 'True', 'to': "orm['db.QuotaHolderSerial']"}),
'suspended': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'userid': ('django.db.models.fields.CharField', [], {'max_length': '100', 'db_index': 'True'})
},
'db.virtualmachinediagnostic': {
'Meta': {'object_name': 'VirtualMachineDiagnostic'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'details': ('django.db.models.fields.TextField', [], {'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'level': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
'machine': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'diagnostics'", 'to': "orm['db.VirtualMachine']"}),
'message': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'source': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'source_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'})
},
'db.virtualmachinemetadata': {
'Meta': {'unique_together': "(('meta_key', 'vm'),)", 'object_name': 'VirtualMachineMetadata'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'meta_key': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'meta_value': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
'vm': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'metadata'", 'to': "orm['db.VirtualMachine']"})
}
}
complete_apps = ['db']
......@@ -29,6 +29,7 @@
import datetime
from copy import deepcopy
from django.conf import settings
from django.db import models
from django.db import IntegrityError
......@@ -87,6 +88,9 @@ class Backend(models.Model):
default=0)
drained = models.BooleanField('Drained', default=False, null=False)
offline = models.BooleanField('Offline', default=False, null=False)
# Type of hypervisor
hypervisor = models.CharField('Hypervisor', max_length=32, default="kvm",
null=False)
# Last refresh of backend resources
updated = models.DateTimeField(auto_now_add=True)
# Backend resources
......@@ -101,6 +105,12 @@ class Backend(models.Model):
# Custom object manager to protect from cascade delete
objects = ProtectedDeleteManager()
HYPERVISORS = (
("kvm", "Linux KVM hypervisor"),
("xen-pvm", "Xen PVM hypervisor"),
("xen-hvm", "Xen KVM hypervisor"),
)
class Meta:
verbose_name = u'Backend'
ordering = ["clustername"]
......@@ -179,6 +189,15 @@ class Backend(models.Model):
except IndexError:
raise Exception("Can not create more than 16 backends")
def use_hotplug(self):
return self.hypervisor == "kvm" and snf_settings.GANETI_USE_HOTPLUG
def get_create_params(self):
params = deepcopy(snf_settings.GANETI_CREATEINSTANCE_KWARGS)
params["hvparams"] = params.get("hvparams", {})\
.get(self.hypervisor, {})
return params
# A backend job may be in one of the following possible states
BACKEND_STATUSES = (
......
......@@ -33,6 +33,7 @@
from django.test import TestCase
from synnefo import settings
# Import pool tests
from synnefo.db.pools.tests import *
......@@ -42,6 +43,7 @@ from synnefo.db.pools import IPPool, EmptyPool
from django.db import IntegrityError
from django.core.exceptions import MultipleObjectsReturned
from snf_django.utils.testing import override_settings
from mock import patch
......@@ -120,6 +122,37 @@ class BackendTest(TestCase):
self.assertNotEqual(self.backend.password_hash, password_hash)
self.assertEqual(self.backend.password, '123')
def test_hypervisor(self):
from synnefo.db.models import snf_settings
kvm_backend = mfact.BackendFactory(hypervisor="kvm")
xen_pvm_backend = mfact.BackendFactory(hypervisor="xen-pvm")
xen_hvm_backend = mfact.BackendFactory(hypervisor="xen-hvm")
with override_settings(snf_settings, GANETI_USE_HOTPLUG=True):
self.assertTrue(kvm_backend.use_hotplug())
self.assertFalse(xen_pvm_backend.use_hotplug())
self.assertFalse(xen_hvm_backend.use_hotplug())
with override_settings(snf_settings, GANETI_USE_HOTPLUG=False):
self.assertFalse(kvm_backend.use_hotplug())
self.assertFalse(xen_pvm_backend.use_hotplug())
self.assertFalse(xen_hvm_backend.use_hotplug())
kwargs = {"os": "snf-image+default",
"hvparams": {"kvm": {"foo1": "mpaz1"},
"xen-pvm": {"foo2": "mpaz2"},
"xen-hvm": {"foo3": "mpaz3"}}}
with override_settings(snf_settings,
GANETI_CREATEINSTANCE_KWARGS=kwargs):
self.assertEqual(kvm_backend.get_create_params(),
{"os": "snf-image+default",
"hvparams": {"foo1": "mpaz1"}})
self.assertEqual(xen_pvm_backend.get_create_params(),
{"os": "snf-image+default",
"hvparams": {"foo2": "mpaz2"}})
self.assertEqual(xen_hvm_backend.get_create_params(),
{"os": "snf-image+default",
"hvparams": {"foo3": "mpaz3"}})
with override_settings(snf_settings, GANETI_CREATEINSTANCE_KWARGS={}):
self.assertEqual(kvm_backend.get_create_params(), {"hvparams": {}})
class VirtualMachineTest(TestCase):
def setUp(self):
......
......@@ -386,7 +386,7 @@ def create_instance(vm, public_nic, flavor, image):
# arguments, such as the disk template to use, name of os provider
# and hypervisor-specific parameters at will (see Synnefo #785, #835).
#
kw = settings.GANETI_CREATEINSTANCE_KWARGS
kw = vm.backend.get_create_params()
kw['mode'] = 'create'
kw['name'] = vm.backend_vm_id
# Defined in settings.GANETI_CREATEINSTANCE_KWARGS
......@@ -401,7 +401,7 @@ def create_instance(vm, public_nic, flavor, image):
kw['disks'][0]['origin'] = flavor.disk_origin
kw['nics'] = [public_nic]
if settings.GANETI_USE_HOTPLUG:
if vm.backend.use_hotplug():
kw['hotplug'] = True
# Defined in settings.GANETI_CREATEINSTANCE_KWARGS
# kw['os'] = settings.GANETI_OS_PROVIDER
......@@ -475,7 +475,7 @@ def get_instance_console(vm):
with pooled_rapi_client(vm) as client:
i = client.GetInstance(vm.backend_vm_id)
if i['hvparams']['serial_console']:
if vm.backend.hypervisor == "kvm" and i['hvparams']['serial_console']:
raise Exception("hv parameter serial_console cannot be true")
console['host'] = i['pnode']
console['port'] = i['network_port']
......@@ -600,7 +600,7 @@ def connect_to_network(vm, network, address=None):
with pooled_rapi_client(vm) as client:
return client.ModifyInstance(vm.backend_vm_id, nics=[('add', nic)],
hotplug=settings.GANETI_USE_HOTPLUG,
hotplug=vm.backend.use_hotplug(),
depends=depends,
dry_run=settings.TEST)
......@@ -612,7 +612,7 @@ def disconnect_from_network(vm, nic):
with pooled_rapi_client(vm) as client:
return client.ModifyInstance(vm.backend_vm_id, nics=op,
hotplug=settings.GANETI_USE_HOTPLUG,
hotplug=vm.backend.use_hotplug(),
dry_run=settings.TEST)
......
......@@ -41,6 +41,9 @@ from synnefo.management.common import check_backend_credentials
from synnefo.webproject.management.utils import pprint_table
HYPERVISORS = [h[0] for h in Backend.HYPERVISORS]
class Command(BaseCommand):
can_import_settings = True
......@@ -54,6 +57,12 @@ class Command(BaseCommand):
'--no-check', action='store_false',
dest='check', default=True,
help="Do not perform credentials check and resources update"),
make_option('--hypervisor',
dest='hypervisor',
default=None,
choices=HYPERVISORS,
metavar="|".join(HYPERVISORS),
help="The hypervisor that the Ganeti backend uses"),
)
def handle(self, *args, **options):
......@@ -64,6 +73,7 @@ class Command(BaseCommand):
port = options['port']
username = options['username']
password = options['password']
hypervisor = options["hypervisor"]
if not (clustername and username and password):
raise CommandError("Clustername, user and pass must be supplied")
......@@ -72,13 +82,17 @@ class Command(BaseCommand):
if options['check']:
check_backend_credentials(clustername, port, username, password)
kw = {"clustername": clustername,
"port": port,
"username": username,
"password": password,
"drained": True}
if hypervisor:
kw["hypervisor"] = hypervisor
# Create the new backend in database
try:
backend = Backend.objects.create(clustername=clustername,
port=port,
username=username,
password=password,
drained=True)
backend = Backend.objects.create(**kw)
except IntegrityError as e:
raise CommandError("Cannot create backend: %s\n" % e)
......
......@@ -33,9 +33,12 @@
from optparse import make_option
from django.core.management.base import BaseCommand, CommandError
from synnefo.db.models import Backend
from synnefo.webproject.management.utils import parse_bool
from synnefo.management.common import (get_backend, check_backend_credentials)
HYPERVISORS = [h[0] for h in Backend.HYPERVISORS]
class Command(BaseCommand):
output_transaction = True
......@@ -61,6 +64,12 @@ class Command(BaseCommand):
metavar="True|False",
help="Set the backend as drained to exclude from"
" allocation operations"),
make_option('--hypervisor',
dest='hypervisor',
default=None,
choices=HYPERVISORS,
metavar="|".join(HYPERVISORS),
help="The hypervisor that the Ganeti backend uses"),
make_option('--offline',
dest='offline',
choices=["True", "False"],
......@@ -92,5 +101,8 @@ class Command(BaseCommand):
backend.drained = parse_bool(options['drained'], strict=True)
if options['offline']:
backend.offline = parse_bool(options['offline'], strict=True)
hypervisor = options["hypervisor"]
if hypervisor:
backend.hypervisor = hypervisor
backend.save()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment