Commit b8797058 by Dudás Ádám

vm: refactor instance deploying code and implement related TODOs

parent a412fb7e
...@@ -4,10 +4,10 @@ from mancelery import celery ...@@ -4,10 +4,10 @@ from mancelery import celery
@celery.task @celery.task
def deploy(instance): def deploy(instance, user):
'''Create new virtual machine from VM class. '''Create new virtual machine from VM class.
''' '''
instance.deploy(task_uuid=deploy.request.id) instance.deploy(task_uuid=deploy.request.id, user=user)
def delete(): def delete():
......
...@@ -2,10 +2,7 @@ ...@@ -2,10 +2,7 @@
from datetime import timedelta from datetime import timedelta
import logging import logging
from netaddr import EUI
from . import tasks
from manager import manager, scheduler
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.db import models from django.db import models
...@@ -17,7 +14,10 @@ from django.utils.translation import ugettext_lazy as _ ...@@ -17,7 +14,10 @@ from django.utils.translation import ugettext_lazy as _
from model_utils.models import TimeStampedModel from model_utils.models import TimeStampedModel
from firewall.models import Vlan, Host from firewall.models import Vlan, Host
from manager import manager, scheduler
from storage.models import Disk from storage.models import Disk
from . import tasks
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
pwgen = User.objects.make_random_password pwgen = User.objects.make_random_password
...@@ -310,6 +310,15 @@ class Instance(BaseResourceConfigModel, TimeStampedModel): ...@@ -310,6 +310,15 @@ class Instance(BaseResourceConfigModel, TimeStampedModel):
return ('one.views.vm_show', None, {'iid': self.id}) return ('one.views.vm_show', None, {'iid': self.id})
@property @property
def vm_name(self):
"""Name of the VM instance.
This is a unique identifier as opposed to the 'name' attribute, which
is just for display.
"""
return 'cloud-' + str(self.id)
@property
def primary_host(self): def primary_host(self):
interfaces = self.interface_set.select_related('host') interfaces = self.interface_set.select_related('host')
hosts = [i.host for i in interfaces if i.host] hosts = [i.host for i in interfaces if i.host]
...@@ -399,7 +408,7 @@ class Instance(BaseResourceConfigModel, TimeStampedModel): ...@@ -399,7 +408,7 @@ class Instance(BaseResourceConfigModel, TimeStampedModel):
def get_vm_desc(self): def get_vm_desc(self):
return { return {
'name': 'cloud-' + self.id, 'name': self.vm_name,
'vcpu': self.num_cores, 'vcpu': self.num_cores,
'memory': self.ram_size, 'memory': self.ram_size,
'memory_max': self.max_ram_size, 'memory_max': self.max_ram_size,
...@@ -408,37 +417,44 @@ class Instance(BaseResourceConfigModel, TimeStampedModel): ...@@ -408,37 +417,44 @@ class Instance(BaseResourceConfigModel, TimeStampedModel):
'boot_menu': self.boot_menu, 'boot_menu': self.boot_menu,
'network_list': [n.get_vmnetwork_desc() 'network_list': [n.get_vmnetwork_desc()
for n in self.interface_set.all()], for n in self.interface_set.all()],
'disk_list': [n.get_vmdisk_desc() for n in self.disks.all()], 'disk_list': [d.get_vmdisk_desc() for d in self.disks.all()],
'graphics': {'type': 'vnc', 'graphics': {
'type': 'vnc',
'listen': '0.0.0.0', 'listen': '0.0.0.0',
'passwd': '', 'passwd': '',
'port': self.get_vnc_port()}, 'port': self.get_vnc_port()
},
'raw_data': self.raw_data 'raw_data': self.raw_data
} }
def deploy_async(self): def deploy_async(self, user=None):
''' Launch celery task to handle asyncron jobs. """ Launch celery task to handle the job asynchronously.
''' """
manager.deploy.apply_async(self) manager.deploy.apply_async(self, user)
def deploy(self, user, task_uuid=None): def deploy(self, user=None, task_uuid=None):
''' Deploy new virtual machine with network """ Deploy new virtual machine with network
1. Schedule 1. Schedule
''' """
act = InstanceActivity(user=user, task_uuid=task_uuid) act = InstanceActivity(activity_code='vm.Instance.deploy',
instance=self, user=user,
started=timezone.now(), task_uuid=task_uuid)
act.save()
# Schedule # Schedule
act.update_state("PENDING") act.update_state("PENDING")
self.node = scheduler.get_node() self.node = scheduler.get_node()
self.save()
# Create virtual images # Create virtual images
act.update_state("PREPARING DISKS") act.update_state("PREPARING DISKS")
for disk in self.disks: for disk in self.disks.all():
disk.deploy() disk.deploy()
# Deploy VM on remote machine # Deploy VM on remote machine
act.update_state("DEPLOYING VM") act.update_state("DEPLOYING VM")
tasks.create.apply_async( tasks.create.apply_async(self.get_vm_desc,
self.get_vm_desc, queue=self.node + ".vm").get() queue=self.node + ".vm").get()
# Estabilish network connection (vmdriver) # Estabilish network connection (vmdriver)
act.update_state("DEPLOYING NET") act.update_state("DEPLOYING NET")
...@@ -447,10 +463,9 @@ class Instance(BaseResourceConfigModel, TimeStampedModel): ...@@ -447,10 +463,9 @@ class Instance(BaseResourceConfigModel, TimeStampedModel):
# Resume vm # Resume vm
act.update_state("BOOTING") act.update_state("BOOTING")
tasks.resume.apply_async( tasks.resume.apply_async(self.vm_name, queue=self.node + ".vm").get()
"cloud-" + self.id, queue=self.node + ".vm").get()
act.finish() act.finish(result='SUCCESS')
def stop(self): def stop(self):
# TODO implement # TODO implement
...@@ -513,26 +528,24 @@ def delete_instance_pre(sender, instance, using, **kwargs): ...@@ -513,26 +528,24 @@ def delete_instance_pre(sender, instance, using, **kwargs):
class InstanceActivity(TimeStampedModel): class InstanceActivity(TimeStampedModel):
activity_code = models.CharField(max_length=100) activity_code = models.CharField(max_length=100)
task_uuid = models.CharField( task_uuid = models.CharField(blank=True, max_length=50, null=True,
max_length=50, unique=True, null=True, blank=True) unique=True)
instance = models.ForeignKey(Instance, related_name='activity_log') instance = models.ForeignKey(Instance, related_name='activity_log')
user = models.ForeignKey(User, blank=True, null=True) user = models.ForeignKey(User, blank=True, null=True)
started = models.DateTimeField(blank=True, null=True) started = models.DateTimeField(blank=True, null=True)
finished = models.DateTimeField(blank=True, null=True) finished = models.DateTimeField(blank=True, null=True)
result = models.TextField(blank=True, null=True) result = models.TextField(blank=True, null=True)
status = models.CharField(default='PENDING', max_length=50) state = models.CharField(default='PENDING', max_length=50)
def __init__(self):
# TODO
pass
def update_state(self): def update_state(self, new_state):
# TODO self.state = new_state
pass self.save()
def finish(self): def finish(self, result=None):
# TODO if not self.finished:
pass self.finished = timezone.now()
self.result = result
self.save()
class Interface(models.Model): class Interface(models.Model):
...@@ -543,15 +556,30 @@ class Interface(models.Model): ...@@ -543,15 +556,30 @@ class Interface(models.Model):
host = models.ForeignKey(Host, blank=True, null=True) host = models.ForeignKey(Host, blank=True, null=True)
instance = models.ForeignKey(Instance, related_name='interface_set') instance = models.ForeignKey(Instance, related_name='interface_set')
def mac_generator(self): @property
# MAC 02:XX:XX:X:VID def mac(self):
pass try:
return self.host.mac
except:
return Interface.generate_mac(self.instance, self.vlan)
@classmethod
def generate_mac(cls, instance, vlan):
"""Generate MAC address for a VM instance on a VLAN.
"""
# MAC 02:XX:XX:XX:XX:XX
# \________/\__/
# VM ID VLAN ID
i = instance.id & 0xfffffff
v = vlan.vid & 0xfff
m = (0x02 << 40) | (i << 12) | v
return EUI(m)
def get_vmnetwork_desc(self): def get_vmnetwork_desc(self):
return { return {
'name': 'cloud-' + self.instance.id + '-' + self.vlan.vid, 'name': 'cloud-' + self.instance.id + '-' + self.vlan.vid,
'bridge': 'cloud', 'bridge': 'cloud',
'mac': self.mac_generator(), 'mac': self.mac,
'ipv4': self.host.ipv4 if self.host is not None else None, 'ipv4': self.host.ipv4 if self.host is not None else None,
'ipv6': self.host.ipv6 if self.host is not None else None, 'ipv6': self.host.ipv6 if self.host is not None else None,
'vlan': self.vlan.vid, 'vlan': self.vlan.vid,
...@@ -563,7 +591,9 @@ class Interface(models.Model): ...@@ -563,7 +591,9 @@ class Interface(models.Model):
"""Create a new interface for an instance based on an """Create a new interface for an instance based on an
InterfaceTemplate. InterfaceTemplate.
""" """
host = Host(vlan=template.vlan) if template.managed else None host = (Host(vlan=template.vlan, mac=cls.generate_mac(instance,
template.vlan))
if template.managed else None)
iface = cls(vlan=template.vlan, host=host, instance=instance) iface = cls(vlan=template.vlan, host=host, instance=instance)
iface.save() iface.save()
return iface return iface
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