Commit 42fb490c by Dudás Ádám

vm: model classes for instance and node activity

parent a14ce987
...@@ -5,13 +5,10 @@ import logging ...@@ -5,13 +5,10 @@ import logging
from . import tasks from . import tasks
# from django.conf.settings import CLOUD_URL
from django.contrib.auth.models import User from django.contrib.auth.models import User
# from django.core import signing
from django.db import models from django.db import models
from django.db.models.signals import pre_delete from django.db.models.signals import pre_delete
from django.dispatch import receiver from django.dispatch import receiver
# from django.template.defaultfilters import escape
from django.utils import timezone from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
...@@ -19,6 +16,7 @@ from model_utils.models import TimeStampedModel ...@@ -19,6 +16,7 @@ from model_utils.models import TimeStampedModel
from firewall.models import Vlan, Host from firewall.models import Vlan, Host
from storage.models import Disk from storage.models import Disk
import manager
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
pwgen = User.objects.make_random_password pwgen = User.objects.make_random_password
...@@ -33,7 +31,6 @@ ACCESS_METHODS = [(k, ap[0]) for k, ap in ACCESS_PROTOCOLS.iteritems()] ...@@ -33,7 +31,6 @@ ACCESS_METHODS = [(k, ap[0]) for k, ap in ACCESS_PROTOCOLS.iteritems()]
class BaseResourceConfigModel(models.Model): class BaseResourceConfigModel(models.Model):
"""Abstract base class for models with base resource configuration """Abstract base class for models with base resource configuration
parameters. parameters.
""" """
...@@ -43,15 +40,14 @@ class BaseResourceConfigModel(models.Model): ...@@ -43,15 +40,14 @@ class BaseResourceConfigModel(models.Model):
'for balloning.')) 'for balloning.'))
arch = models.CharField(max_length=10, verbose_name=_('architecture')) arch = models.CharField(max_length=10, verbose_name=_('architecture'))
priority = models.IntegerField(help_text=_('instance priority')) priority = models.IntegerField(help_text=_('instance priority'))
boot_menu = models.BooleanField() boot_menu = models.BooleanField(default=False)
raw_data = models.TextField() raw_data = models.TextField(blank=True, null=True)
class Meta: class Meta:
abstract = True abstract = True
class NamedBaseResourceConfig(BaseResourceConfigModel, TimeStampedModel): class NamedBaseResourceConfig(BaseResourceConfigModel, TimeStampedModel):
"""Pre-created, named base resource configurations. """Pre-created, named base resource configurations.
""" """
name = models.CharField(max_length=50, unique=True, name = models.CharField(max_length=50, unique=True,
...@@ -62,6 +58,8 @@ class NamedBaseResourceConfig(BaseResourceConfigModel, TimeStampedModel): ...@@ -62,6 +58,8 @@ class NamedBaseResourceConfig(BaseResourceConfigModel, TimeStampedModel):
class Node(TimeStampedModel): class Node(TimeStampedModel):
"""A VM host machine.
"""
name = models.CharField(max_length=50, unique=True, name = models.CharField(max_length=50, unique=True,
verbose_name=_('name')) verbose_name=_('name'))
num_cores = models.IntegerField(help_text=_('Number of CPU cores.')) num_cores = models.IntegerField(help_text=_('Number of CPU cores.'))
...@@ -82,8 +80,18 @@ class Node(TimeStampedModel): ...@@ -82,8 +80,18 @@ class Node(TimeStampedModel):
pass # TODO implement check pass # TODO implement check
class Lease(models.Model): class NodeActivity(TimeStampedModel):
activity_code = models.CharField(max_length=100)
task_uuid = models.CharField(max_length=50, unique=True)
node = models.ForeignKey(Node, related_name='activity_log')
user = models.ForeignKey(User, blank=True, null=True)
started = models.DateTimeField(blank=True, null=True)
finished = models.DateTimeField(blank=True, null=True)
result = models.TextField(blank=True, null=True)
status = models.CharField(default='PENDING', max_length=50)
class Lease(models.Model):
"""Lease times for VM instances. """Lease times for VM instances.
Specifies a time duration until suspension and deletion of a VM Specifies a time duration until suspension and deletion of a VM
...@@ -94,6 +102,9 @@ class Lease(models.Model): ...@@ -94,6 +102,9 @@ class Lease(models.Model):
suspend_interval_seconds = models.IntegerField() suspend_interval_seconds = models.IntegerField()
delete_interval_seconds = models.IntegerField() delete_interval_seconds = models.IntegerField()
class Meta:
ordering = ['name', ]
@property @property
def suspend_interval(self): def suspend_interval(self):
return timedelta(seconds=self.suspend_interval_seconds) return timedelta(seconds=self.suspend_interval_seconds)
...@@ -112,7 +123,6 @@ class Lease(models.Model): ...@@ -112,7 +123,6 @@ class Lease(models.Model):
class InstanceTemplate(BaseResourceConfigModel, TimeStampedModel): class InstanceTemplate(BaseResourceConfigModel, TimeStampedModel):
"""Virtual machine template. """Virtual machine template.
Every template has: Every template has:
...@@ -126,7 +136,6 @@ class InstanceTemplate(BaseResourceConfigModel, TimeStampedModel): ...@@ -126,7 +136,6 @@ class InstanceTemplate(BaseResourceConfigModel, TimeStampedModel):
* set of interfaces * set of interfaces
* lease times (suspension & deletion) * lease times (suspension & deletion)
* time of creation and last modification * time of creation and last modification
* ownership information
""" """
STATES = [('NEW', _('new')), # template has just been created STATES = [('NEW', _('new')), # template has just been created
('SAVING', _('saving')), # changes are being saved ('SAVING', _('saving')), # changes are being saved
...@@ -169,13 +178,12 @@ class InstanceTemplate(BaseResourceConfigModel, TimeStampedModel): ...@@ -169,13 +178,12 @@ class InstanceTemplate(BaseResourceConfigModel, TimeStampedModel):
"""Get the type of the template's operating system. """Get the type of the template's operating system.
""" """
if self.access_method == 'rdp': if self.access_method == 'rdp':
return "win" return 'win'
else: else:
return "linux" return 'linux'
class InterfaceTemplate(models.Model): class InterfaceTemplate(models.Model):
"""Network interface template for an instance template. """Network interface template for an instance template.
If the interface is managed, a host will be created for it. If the interface is managed, a host will be created for it.
...@@ -192,7 +200,6 @@ class InterfaceTemplate(models.Model): ...@@ -192,7 +200,6 @@ class InterfaceTemplate(models.Model):
class Instance(BaseResourceConfigModel, TimeStampedModel): class Instance(BaseResourceConfigModel, TimeStampedModel):
"""Virtual machine instance. """Virtual machine instance.
Every instance has: Every instance has:
...@@ -204,10 +211,10 @@ class Instance(BaseResourceConfigModel, TimeStampedModel): ...@@ -204,10 +211,10 @@ class Instance(BaseResourceConfigModel, TimeStampedModel):
* lease times (suspension & deletion) * lease times (suspension & deletion)
* last boot timestamp * last boot timestamp
* host node * host node
* current state (libvirt domain state) and operation (Celery job UUID) * current state (libvirt domain state)
* time of creation and last modification * time of creation and last modification
* base resource configuration values * base resource configuration values
* ownership information * owner and privilege information
""" """
STATES = [('NOSTATE', _('nostate')), STATES = [('NOSTATE', _('nostate')),
('RUNNING', _('running')), ('RUNNING', _('running')),
...@@ -236,8 +243,6 @@ class Instance(BaseResourceConfigModel, TimeStampedModel): ...@@ -236,8 +243,6 @@ class Instance(BaseResourceConfigModel, TimeStampedModel):
related_name='instance_set', related_name='instance_set',
verbose_name=_('host nose')) verbose_name=_('host nose'))
state = models.CharField(choices=STATES, default='NOSTATE', max_length=20) state = models.CharField(choices=STATES, default='NOSTATE', max_length=20)
operation = models.CharField(blank=True, max_length=100, null=True,
verbose_name=_('operation'))
disks = models.ManyToManyField(Disk, related_name='instance_set', disks = models.ManyToManyField(Disk, related_name='instance_set',
verbose_name=_('disks')) verbose_name=_('disks'))
lease = models.ForeignKey(Lease) lease = models.ForeignKey(Lease)
...@@ -255,7 +260,7 @@ class Instance(BaseResourceConfigModel, TimeStampedModel): ...@@ -255,7 +260,7 @@ class Instance(BaseResourceConfigModel, TimeStampedModel):
return self.name return self.name
@classmethod @classmethod
def create_from_template(cls, template, **kwargs): def create_from_template(cls, template, owner, **kwargs):
"""Create a new instance based on an InstanceTemplate. """Create a new instance based on an InstanceTemplate.
Can also specify parameters as keyword arguments which should override Can also specify parameters as keyword arguments which should override
...@@ -263,6 +268,7 @@ class Instance(BaseResourceConfigModel, TimeStampedModel): ...@@ -263,6 +268,7 @@ class Instance(BaseResourceConfigModel, TimeStampedModel):
""" """
# prepare parameters # prepare parameters
kwargs['template'] = template kwargs['template'] = template
kwargs['owner'] = owner
kwargs.setdefault('name', template.name) kwargs.setdefault('name', template.name)
kwargs.setdefault('description', template.description) kwargs.setdefault('description', template.description)
kwargs.setdefault('pw', pwgen()) kwargs.setdefault('pw', pwgen())
...@@ -289,9 +295,9 @@ class Instance(BaseResourceConfigModel, TimeStampedModel): ...@@ -289,9 +295,9 @@ class Instance(BaseResourceConfigModel, TimeStampedModel):
return inst return inst
# TODO is this obsolete?
@models.permalink @models.permalink
def get_absolute_url(self): def get_absolute_url(self):
# TODO is this obsolete?
return ('one.views.vm_show', None, {'iid': self.id}) return ('one.views.vm_show', None, {'iid': self.id})
@property @property
...@@ -310,17 +316,20 @@ class Instance(BaseResourceConfigModel, TimeStampedModel): ...@@ -310,17 +316,20 @@ class Instance(BaseResourceConfigModel, TimeStampedModel):
@property @property
def ipv4(self): def ipv4(self):
"""Primary IPv4 address of the instance.""" """Primary IPv4 address of the instance.
"""
return self.primary_host.ipv4 if self.primary_host else None return self.primary_host.ipv4 if self.primary_host else None
@property @property
def ipv6(self): def ipv6(self):
"""Primary IPv6 address of the instance.""" """Primary IPv6 address of the instance.
"""
return self.primary_host.ipv6 if self.primary_host else None return self.primary_host.ipv6 if self.primary_host else None
@property @property
def mac(self): def mac(self):
"""Primary MAC address of the instance.""" """Primary MAC address of the instance.
"""
return self.primary_host.mac if self.primary_host else None return self.primary_host.mac if self.primary_host else None
@property @property
...@@ -343,7 +352,7 @@ class Instance(BaseResourceConfigModel, TimeStampedModel): ...@@ -343,7 +352,7 @@ class Instance(BaseResourceConfigModel, TimeStampedModel):
def waiting(self): def waiting(self):
"""Indicates whether the instance's waiting for an operation to finish. """Indicates whether the instance's waiting for an operation to finish.
""" """
return self.operation is not None return self.activity_log.filter(finished__isnull=True).exists()
def get_connect_port(self, use_ipv6=False): def get_connect_port(self, use_ipv6=False):
"""Get public port number for default access method. """Get public port number for default access method.
...@@ -373,9 +382,9 @@ class Instance(BaseResourceConfigModel, TimeStampedModel): ...@@ -373,9 +382,9 @@ class Instance(BaseResourceConfigModel, TimeStampedModel):
proto = self.access_method proto = self.access_method
if proto == 'ssh': if proto == 'ssh':
proto = 'sshterm' proto = 'sshterm'
return ("%(proto)s:cloud:%(pw)s:%(host)s:%(port)d" % return ('%(proto)s:cloud:%(pw)s:%(host)s:%(port)d' %
{"port": port, "proto": proto, "pw": self.pw, {'port': port, 'proto': proto, 'pw': self.pw,
"host": host}) 'host': host})
except: except:
return return
...@@ -459,12 +468,23 @@ class Instance(BaseResourceConfigModel, TimeStampedModel): ...@@ -459,12 +468,23 @@ class Instance(BaseResourceConfigModel, TimeStampedModel):
return True return True
@receiver(pre_delete, sender=Instance, dispatch_uid="delete_instance_pre") @receiver(pre_delete, sender=Instance, dispatch_uid='delete_instance_pre')
def delete_instance_pre(sender, instance, using, **kwargs): def delete_instance_pre(sender, instance, using, **kwargs):
# TODO implement # TODO implement
pass pass
class InstanceActivity(TimeStampedModel):
activity_code = models.CharField(max_length=100)
task_uuid = models.CharField(max_length=50, unique=True)
instance = models.ForeignKey(Instance, related_name='activity_log')
user = models.ForeignKey(User, blank=True, null=True)
started = models.DateTimeField(blank=True, null=True)
finished = models.DateTimeField(blank=True, null=True)
result = models.TextField(blank=True, null=True)
status = models.CharField(default='PENDING', max_length=50)
class Interface(models.Model): class Interface(models.Model):
"""Network interface for an instance. """Network interface for an instance.
......
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