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 @@ ...@@ -11,22 +11,22 @@
## The following dictionary defines deployment-specific ## The following dictionary defines deployment-specific
## arguments to the RAPI CreateInstance call. ## arguments to the RAPI CreateInstance call.
## At a minimum it should contain the ## At a minimum it should contain the
## 'disk_template', 'os_provider', and 'hvparams' keys. ## 'os' and 'hvparams' keys.
## ##
## More specifically: ## More specifically:
## a) disk_template: ## a) os:
## The disk template to use when creating the instance.
## Suggested values: 'plain', or 'drbd'.
## b) os:
## The OS provider to use (customized Ganeti Instance Image) ## The OS provider to use (customized Ganeti Instance Image)
## c) hvparams: ## b) hvparams:
## Hypervisor-specific parameters (serial_console = False, see #785) ## Hypervisor-specific parameters (serial_console = False, see #785),
## d) If using the DRBD disk_template, you may want to include ## 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). ## wait_for_sync = False (see #835).
## ##
#GANETI_CREATEINSTANCE_KWARGS = { #GANETI_CREATEINSTANCE_KWARGS = {
# 'os': 'snf-image+default', # 'os': 'snf-image+default',
# 'hvparams': {'serial_console': False}, # 'hvparams': {'kvm': {'serial_console': False},
# 'xen-pvm: {},
# 'xen-hvm: {}}
# 'wait_for_sync': False} # 'wait_for_sync': False}
# #
## If True, qemu-kvm will hotplug a NIC when connecting a vm to ## If True, qemu-kvm will hotplug a NIC when connecting a vm to
......
...@@ -11,22 +11,22 @@ BACKEND_PREFIX_ID = "snf-" ...@@ -11,22 +11,22 @@ BACKEND_PREFIX_ID = "snf-"
# The following dictionary defines deployment-specific # The following dictionary defines deployment-specific
# arguments to the RAPI CreateInstance call. # arguments to the RAPI CreateInstance call.
# At a minimum it should contain the # At a minimum it should contain the
# 'disk_template', 'os_provider', and 'hvparams' keys. # 'os' and 'hvparams' keys.
# #
# More specifically: # More specifically:
# a) disk_template: # a) os:
# The disk template to use when creating the instance.
# Suggested values: 'plain', or 'drbd'.
# b) os:
# The OS provider to use (customized Ganeti Instance Image) # The OS provider to use (customized Ganeti Instance Image)
# c) hvparams: # b) hvparams:
# Hypervisor-specific parameters (serial_console = False, see #785) # Hypervisor-specific parameters (serial_console = False, see #785),
# d) If using the DRBD disk_template, you may want to include # 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). # wait_for_sync = False (see #835).
# #
GANETI_CREATEINSTANCE_KWARGS = { GANETI_CREATEINSTANCE_KWARGS = {
'os': 'snf-image+default', 'os': 'snf-image+default',
'hvparams': {'serial_console': False}, 'hvparams': {"kvm": {'serial_console': False},
"xen-pvm": {},
"xen-hvm": {}},
'wait_for_sync': False} 'wait_for_sync': False}
# If True, qemu-kvm will hotplug a NIC when connecting a vm to # 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 @@ ...@@ -29,6 +29,7 @@
import datetime import datetime
from copy import deepcopy
from django.conf import settings from django.conf import settings
from django.db import models from django.db import models
from django.db import IntegrityError from django.db import IntegrityError
...@@ -87,6 +88,9 @@ class Backend(models.Model): ...@@ -87,6 +88,9 @@ class Backend(models.Model):
default=0) default=0)
drained = models.BooleanField('Drained', default=False, null=False) drained = models.BooleanField('Drained', default=False, null=False)
offline = models.BooleanField('Offline', 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 # Last refresh of backend resources
updated = models.DateTimeField(auto_now_add=True) updated = models.DateTimeField(auto_now_add=True)
# Backend resources # Backend resources
...@@ -101,6 +105,12 @@ class Backend(models.Model): ...@@ -101,6 +105,12 @@ class Backend(models.Model):
# Custom object manager to protect from cascade delete # Custom object manager to protect from cascade delete
objects = ProtectedDeleteManager() objects = ProtectedDeleteManager()
HYPERVISORS = (
("kvm", "Linux KVM hypervisor"),
("xen-pvm", "Xen PVM hypervisor"),
("xen-hvm", "Xen KVM hypervisor"),
)
class Meta: class Meta:
verbose_name = u'Backend' verbose_name = u'Backend'
ordering = ["clustername"] ordering = ["clustername"]
...@@ -179,6 +189,15 @@ class Backend(models.Model): ...@@ -179,6 +189,15 @@ class Backend(models.Model):
except IndexError: except IndexError:
raise Exception("Can not create more than 16 backends") 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 # A backend job may be in one of the following possible states
BACKEND_STATUSES = ( BACKEND_STATUSES = (
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
from django.test import TestCase from django.test import TestCase
from synnefo import settings
# Import pool tests # Import pool tests
from synnefo.db.pools.tests import * from synnefo.db.pools.tests import *
...@@ -42,6 +43,7 @@ from synnefo.db.pools import IPPool, EmptyPool ...@@ -42,6 +43,7 @@ from synnefo.db.pools import IPPool, EmptyPool
from django.db import IntegrityError from django.db import IntegrityError
from django.core.exceptions import MultipleObjectsReturned from django.core.exceptions import MultipleObjectsReturned
from snf_django.utils.testing import override_settings
from mock import patch from mock import patch
...@@ -120,6 +122,37 @@ class BackendTest(TestCase): ...@@ -120,6 +122,37 @@ class BackendTest(TestCase):
self.assertNotEqual(self.backend.password_hash, password_hash) self.assertNotEqual(self.backend.password_hash, password_hash)
self.assertEqual(self.backend.password, '123') 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): class VirtualMachineTest(TestCase):
def setUp(self): def setUp(self):
......
...@@ -386,7 +386,7 @@ def create_instance(vm, public_nic, flavor, image): ...@@ -386,7 +386,7 @@ def create_instance(vm, public_nic, flavor, image):
# arguments, such as the disk template to use, name of os provider # arguments, such as the disk template to use, name of os provider
# and hypervisor-specific parameters at will (see Synnefo #785, #835). # 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['mode'] = 'create'
kw['name'] = vm.backend_vm_id kw['name'] = vm.backend_vm_id
# Defined in settings.GANETI_CREATEINSTANCE_KWARGS # Defined in settings.GANETI_CREATEINSTANCE_KWARGS
...@@ -401,7 +401,7 @@ def create_instance(vm, public_nic, flavor, image): ...@@ -401,7 +401,7 @@ def create_instance(vm, public_nic, flavor, image):
kw['disks'][0]['origin'] = flavor.disk_origin kw['disks'][0]['origin'] = flavor.disk_origin
kw['nics'] = [public_nic] kw['nics'] = [public_nic]
if settings.GANETI_USE_HOTPLUG: if vm.backend.use_hotplug():
kw['hotplug'] = True kw['hotplug'] = True
# Defined in settings.GANETI_CREATEINSTANCE_KWARGS # Defined in settings.GANETI_CREATEINSTANCE_KWARGS
# kw['os'] = settings.GANETI_OS_PROVIDER # kw['os'] = settings.GANETI_OS_PROVIDER
...@@ -475,7 +475,7 @@ def get_instance_console(vm): ...@@ -475,7 +475,7 @@ def get_instance_console(vm):
with pooled_rapi_client(vm) as client: with pooled_rapi_client(vm) as client:
i = client.GetInstance(vm.backend_vm_id) 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") raise Exception("hv parameter serial_console cannot be true")
console['host'] = i['pnode'] console['host'] = i['pnode']
console['port'] = i['network_port'] console['port'] = i['network_port']
...@@ -600,7 +600,7 @@ def connect_to_network(vm, network, address=None): ...@@ -600,7 +600,7 @@ def connect_to_network(vm, network, address=None):
with pooled_rapi_client(vm) as client: with pooled_rapi_client(vm) as client:
return client.ModifyInstance(vm.backend_vm_id, nics=[('add', nic)], return client.ModifyInstance(vm.backend_vm_id, nics=[('add', nic)],
hotplug=settings.GANETI_USE_HOTPLUG, hotplug=vm.backend.use_hotplug(),
depends=depends, depends=depends,
dry_run=settings.TEST) dry_run=settings.TEST)
...@@ -612,7 +612,7 @@ def disconnect_from_network(vm, nic): ...@@ -612,7 +612,7 @@ def disconnect_from_network(vm, nic):
with pooled_rapi_client(vm) as client: with pooled_rapi_client(vm) as client:
return client.ModifyInstance(vm.backend_vm_id, nics=op, return client.ModifyInstance(vm.backend_vm_id, nics=op,
hotplug=settings.GANETI_USE_HOTPLUG, hotplug=vm.backend.use_hotplug(),
dry_run=settings.TEST) dry_run=settings.TEST)
......
...@@ -41,6 +41,9 @@ from synnefo.management.common import check_backend_credentials ...@@ -41,6 +41,9 @@ from synnefo.management.common import check_backend_credentials
from synnefo.webproject.management.utils import pprint_table from synnefo.webproject.management.utils import pprint_table
HYPERVISORS = [h[0] for h in Backend.HYPERVISORS]
class Command(BaseCommand): class Command(BaseCommand):
can_import_settings = True can_import_settings = True
...@@ -54,6 +57,12 @@ class Command(BaseCommand): ...@@ -54,6 +57,12 @@ class Command(BaseCommand):
'--no-check', action='store_false', '--no-check', action='store_false',
dest='check', default=True, dest='check', default=True,
help="Do not perform credentials check and resources update"), 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): def handle(self, *args, **options):
...@@ -64,6 +73,7 @@ class Command(BaseCommand): ...@@ -64,6 +73,7 @@ class Command(BaseCommand):
port = options['port'] port = options['port']
username = options['username'] username = options['username']
password = options['password'] password = options['password']
hypervisor = options["hypervisor"]
if not (clustername and username and password): if not (clustername and username and password):
raise CommandError("Clustername, user and pass must be supplied") raise CommandError("Clustername, user and pass must be supplied")
...@@ -72,13 +82,17 @@ class Command(BaseCommand): ...@@ -72,13 +82,17 @@ class Command(BaseCommand):
if options['check']: if options['check']:
check_backend_credentials(clustername, port, username, password) 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 # Create the new backend in database
try: try:
backend = Backend.objects.create(clustername=clustername, backend = Backend.objects.create(**kw)
port=port,
username=username,
password=password,
drained=True)
except IntegrityError as e: except IntegrityError as e:
raise CommandError("Cannot create backend: %s\n" % e) raise CommandError("Cannot create backend: %s\n" % e)
......
...@@ -33,9 +33,12 @@ ...@@ -33,9 +33,12 @@
from optparse import make_option from optparse import make_option
from django.core.management.base import BaseCommand, CommandError from django.core.management.base import BaseCommand, CommandError
from synnefo.db.models import Backend
from synnefo.webproject.management.utils import parse_bool from synnefo.webproject.management.utils import parse_bool
from synnefo.management.common import (get_backend, check_backend_credentials) from synnefo.management.common import (get_backend, check_backend_credentials)
HYPERVISORS = [h[0] for h in Backend.HYPERVISORS]
class Command(BaseCommand): class Command(BaseCommand):
output_transaction = True output_transaction = True
...@@ -61,6 +64,12 @@ class Command(BaseCommand): ...@@ -61,6 +64,12 @@ class Command(BaseCommand):
metavar="True|False", metavar="True|False",
help="Set the backend as drained to exclude from" help="Set the backend as drained to exclude from"
" allocation operations"), " allocation operations"),
make_option('--hypervisor',