Commit a4cab8dc by Szabolcs Gelencser

Add template capture, and create from template feature

parent 4e4171b6
......@@ -468,30 +468,25 @@ class VmSizeChoiceField(forms.ModelChoiceField):
obj.os_disk_size_in_mb, obj.resource_disk_size_in_mb,
obj.max_data_disk_count)
#TODO: this is terribly slow, should make 4 choicefields, and set choices
# with JS value changed event, and AJAX calls
# ONLY FOR TESTING PURPOSES
class VmTemplateChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj):
version = obj
sku = obj.sku
offer = sku.offer
pub = offer.publisher
return "%s - %s - %s - %s" % (
pub.name, offer.name, sku.name, version.name
)
class TemplateForm(forms.ModelForm):
azure_vm_size = VmSizeChoiceField(
queryset=AzureVirtualMachineSize.objects.all())
#TODO: this is terribly slow, should make 4 choicefields, and set choices
# with JS value changed event, and AJAX calls
# ONLY FOR TESTING PURPOSES
def generate_azure_template_list():
result = []
for p in AzureBuiltinPublisher.objects.all():
for o in p.azure_offer.all():
for s in o.azure_sku.all():
for v in s.azure_version.all():
result.append((
v.pk,
"%s - %s - %s - %s" % (
p.name, o.name, s.name, v.name
),
))
return result
azure_template = forms.ChoiceField(
choices=generate_azure_template_list
)
azure_template = VmTemplateChoiceField(
queryset=AzureBuiltinVersion.objects.all())
networks = forms.ModelMultipleChoiceField(
queryset=None, required=False, label=_("Networks"))
......
......@@ -144,13 +144,12 @@ class TemplateCreate(SuccessMessageMixin, CreateView):
networks = self.__create_networks(post.pop("networks"),
request.user)
post.pop("parent")
post.pop("vhd_uri")
post['max_ram_size'] = post['ram_size']
req_traits = post.pop("req_traits")
tags = post.pop("tags")
post['pw'] = User.objects.make_random_password() + "aA1"
post['is_base'] = True
post['azure_template'] = AzureBuiltinVersion.objects.get(
pk=post['azure_template'])
inst = Instance.create(params=post, disks=[],
networks=networks,
tags=tags, req_traits=req_traits)
......
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('vm', '0012_auto_20161011_1414'),
]
operations = [
migrations.AddField(
model_name='instancetemplate',
name='azure_template',
field=models.ForeignKey(default='', verbose_name='azure vm template', to='vm.AzureBuiltinVersion'),
preserve_default=False,
),
migrations.AddField(
model_name='instancetemplate',
name='azure_vm_size',
field=models.ForeignKey(default='', verbose_name='azure vm size', to='vm.AzureVirtualMachineSize'),
preserve_default=False,
),
migrations.AddField(
model_name='instancetemplate',
name='vhd_uri',
field=models.TextField(default='', verbose_name='vhd uri'),
preserve_default=False,
),
]
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('vm', '0013_auto_20161016_2121'),
]
operations = [
migrations.AlterField(
model_name='instancetemplate',
name='azure_template',
field=models.ForeignKey(verbose_name='azure vm template', blank=True, to='vm.AzureBuiltinVersion'),
),
migrations.AlterField(
model_name='instancetemplate',
name='azure_vm_size',
field=models.ForeignKey(verbose_name='azure vm size', blank=True, to='vm.AzureVirtualMachineSize'),
),
migrations.AlterField(
model_name='instancetemplate',
name='vhd_uri',
field=models.TextField(verbose_name='vhd uri', blank=True),
),
]
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('vm', '0014_auto_20161016_2124'),
]
operations = [
migrations.AlterField(
model_name='instancetemplate',
name='azure_template',
field=models.ForeignKey(verbose_name='azure vm template', to='vm.AzureBuiltinVersion', null=True),
),
migrations.AlterField(
model_name='instancetemplate',
name='azure_vm_size',
field=models.ForeignKey(verbose_name='azure vm size', to='vm.AzureVirtualMachineSize', null=True),
),
]
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('vm', '0015_auto_20161016_2125'),
]
operations = [
migrations.AlterField(
model_name='instancetemplate',
name='azure_template',
field=models.ForeignKey(verbose_name='azure vm template', blank=True, to='vm.AzureBuiltinVersion', null=True),
),
migrations.AlterField(
model_name='instancetemplate',
name='azure_vm_size',
field=models.ForeignKey(verbose_name='azure vm size', blank=True, to='vm.AzureVirtualMachineSize', null=True),
),
]
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('vm', '0016_auto_20161016_2130'),
]
operations = [
migrations.AlterField(
model_name='instancetemplate',
name='azure_template',
field=models.ForeignKey(default=8000, verbose_name='azure vm template', to='vm.AzureBuiltinVersion'),
preserve_default=False,
),
migrations.AlterField(
model_name='instancetemplate',
name='azure_vm_size',
field=models.ForeignKey(default=1, verbose_name='azure vm size', to='vm.AzureVirtualMachineSize'),
preserve_default=False,
),
]
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('vm', '0017_auto_20161016_2355'),
]
operations = [
migrations.AddField(
model_name='instance',
name='vhd_uri',
field=models.TextField(verbose_name='vhd uri', blank=True),
),
]
......@@ -119,6 +119,14 @@ class VirtualMachineDescModel(BaseResourceConfigModel):
'If the machine has agent installed, and '
'the manager should wait for its start.'))
azure_vm_size = ForeignKey(AzureVirtualMachineSize,
verbose_name=_('azure vm size'))
azure_template = ForeignKey(AzureBuiltinVersion,
verbose_name=_('azure vm template'))
vhd_uri = TextField(verbose_name=_('vhd uri'), blank=True)
class Meta:
abstract = True
......@@ -262,11 +270,6 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin,
objects = Manager()
active = QueryManager(destroyed_at=None)
azure_vm_size = ForeignKey(AzureVirtualMachineSize,
verbose_name=_('azure vm size'))
azure_template = ForeignKey(AzureBuiltinVersion,
verbose_name=_('azure vm template'))
class Meta:
app_label = 'vm'
db_table = 'vm_instance'
......@@ -441,6 +444,10 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin,
if amount > 1 and '%d' not in params['name']:
params['name'] += ' %d'
params['azure_vm_size'] = template.azure_vm_size
params['azure_template'] = template.azure_template
params['vhd_uri'] = template.vhd_uri
customized_params = (dict(params,
name=params['name'].replace('%d', str(i)))
for i in xrange(amount))
......
......@@ -51,7 +51,6 @@ from .models import (
Instance, InstanceActivity, InstanceTemplate, Interface, Node,
NodeActivity, pwgen
)
#from storage.models import DataStore
from .tasks import agent_tasks, vm_tasks
......@@ -399,7 +398,7 @@ class DeployOperation(InstanceOperation):
def _operation(self):
nics = [str(nic_id) for nic_id in
self.instance.interface_set.values_list('azure_id', flat=True)]
#storage_name = DataStore.objects.get(pk=1).name
storage_name = os.getenv("STORAGEACCOUNT")
vm_size_version = self.instance.azure_template
vm_size_sku = vm_size_version.sku
vm_size_offer = vm_size_sku.offer
......@@ -411,11 +410,12 @@ class DeployOperation(InstanceOperation):
"pw": self.instance.pw,
"vm_size": self.instance.azure_vm_size.name,
"nics": nics,
"datastore_name": "mylittledatastore", #storage_name,
"datastore_name": storage_name,
"os_publisher": vm_size_publisher.name,
"os_offer": vm_size_offer.name,
"os_sku": vm_size_sku.name,
"os_version": vm_size_version.name,
"vhd_uri": self.instance.vhd_uri,
}]
azure_id = vm_tasks.deploy.apply_async(
......@@ -703,8 +703,6 @@ class SaveAsTemplateOperation(InstanceOperation):
"with users and groups. Anyone who has access to a "
"template (and to the networks it uses) will be able to "
"start an instance of it.")
has_percentage = True
abortable = True
required_perms = ('vm.create_template', )
accept_states = ('RUNNING', 'STOPPED')
async_queue = "localhost.man.slow"
......@@ -758,27 +756,13 @@ class SaveAsTemplateOperation(InstanceOperation):
'ram_size': self.instance.ram_size,
'raw_data': self.instance.raw_data,
'system': self.instance.system,
'azure_vm_size': self.instance.azure_vm_size,
'azure_template': self.instance.azure_template
}
params.update(kwargs)
params.pop("parent_activity", None)
from storage.models import Disk
def __try_save_disk(disk):
try:
return disk.save_as(task)
except Disk.WrongDiskTypeError:
return disk
self.disks = []
for disk in self.instance.disks.all():
with activity.sub_activity(
'saving_disk',
readable_name=create_readable(
ugettext_noop("saving disk %(name)s"),
name=disk.name)
):
self.disks.append(__try_save_disk(disk))
#TODO: create data disks
# create template and do additional setup
tmpl = InstanceTemplate(**params)
......@@ -792,10 +776,22 @@ class SaveAsTemplateOperation(InstanceOperation):
tmpl.set_level(self.instance.template.owner, 'owner')
tmpl.set_level(user, 'owner')
try:
tmpl.disks.add(*self.disks)
#TODO: add data disks
# create interface templates
for i in self.instance.interface_set.all():
i.save_as_template(tmpl)
# create template in azure
try:
vhd_uri = vm_tasks.save_as_template.apply_async(
args=[self.instance.name, self.instance.pk],
queue="localhost.vm.fast"
).get(timeout=1200)
tmpl.vhd_uri = vhd_uri
tmpl.save()
#TODO: delete VM (cannot start VM in Azure after generalization)
#self.instance.destroy()
except:
raise
except:
tmpl.delete()
raise
......@@ -807,37 +803,24 @@ class SaveAsTemplateOperation(InstanceOperation):
@register_operation
class ShutdownOperation(AbortableRemoteOperationMixin,
RemoteInstanceOperation):
class ShutdownOperation(InstanceOperation):
id = 'shutdown'
name = _("shutdown")
description = _("Try to halt virtual machine by a standard ACPI signal, "
"allowing the operating system to keep a consistent "
"state. The operation will fail if the machine does not "
"turn itself off in a period.")
abortable = True
required_perms = ()
accept_states = ('RUNNING', )
resultant_state = 'STOPPED'
task = vm_tasks.shutdown
remote_queue = ("vm", "slow")
remote_timeout = 180
def _operation(self, task):
super(ShutdownOperation, self)._operation(task=task)
self.instance.yield_node()
def on_abort(self, activity, error):
if isinstance(error, TimeLimitExceeded):
activity.result = humanize_exception(ugettext_noop(
"The virtual machine did not switch off in the provided time "
"limit. Most of the time this is caused by incorrect ACPI "
"settings. You can also try to power off the machine from the "
"operating system manually."), error)
activity.resultant_state = None
else:
super(ShutdownOperation, self).on_abort(activity, error)
activity.resultant_state = 'RUNNING'
def _operation(self, task):
vm_tasks.shutdown.apply_async(
args=[self.instance.name], queue="localhost.vm.fast"
).get(timeout=1200)
@register_operation
class ShutOffOperation(InstanceOperation):
......
......@@ -61,6 +61,10 @@ def get_queues():
cache.set(key, result, 10)
return result
@celery.task(name='vmdriver.save_as_template')
def save_as_template(vm_name, vm_pk):
pass
@celery.task(name='vmdriver.attach_disk')
def attach_disk(vm, disk):
......@@ -113,7 +117,7 @@ def resume(params):
@celery.task(name='vmdriver.shutdown')
def shutdown(params):
def shutdown(vm_name):
pass
......
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 sign in to comment