uncloud/uncloud_vm/models.py

201 lines
6.3 KiB
Python
Raw Normal View History

from django.db import models
from django.contrib.auth import get_user_model
from uncloud_pay.models import Product, RecurringPeriod
2020-03-22 19:55:11 +00:00
from uncloud.models import UncloudModel, UncloudStatus
2020-03-21 10:59:04 +00:00
import uncloud_pay.models as pay_models
import uncloud_storage.models
2020-03-22 19:55:11 +00:00
class VMCluster(UncloudModel):
name = models.CharField(max_length=128, unique=True)
2020-03-21 10:59:04 +00:00
class VMHost(UncloudModel):
# 253 is the maximum DNS name length
hostname = models.CharField(max_length=253, unique=True)
2020-03-22 19:55:11 +00:00
vmcluster = models.ForeignKey(
VMCluster, on_delete=models.CASCADE, editable=False, blank=True, null=True
)
# indirectly gives a maximum number of cores / VM - f.i. 32
physical_cores = models.IntegerField(default=0)
# determines the maximum usable cores - f.i. 320 if you overbook by a factor of 10
usable_cores = models.IntegerField(default=0)
# ram that can be used of the server
usable_ram_in_gb = models.FloatField(default=0)
2020-03-02 12:20:30 +00:00
status = models.CharField(
2020-03-22 19:55:11 +00:00
max_length=32, choices=UncloudStatus.choices, default=UncloudStatus.PENDING
2020-03-02 12:20:30 +00:00
)
@property
def vms(self):
return VMProduct.objects.filter(vmhost=self)
2020-03-03 18:46:39 +00:00
2020-03-17 18:07:00 +00:00
@property
def used_ram_in_gb(self):
return sum([vm.ram_in_gb for vm in VMProduct.objects.filter(vmhost=self)])
@property
def available_ram_in_gb(self):
2020-03-22 19:55:11 +00:00
return self.usable_ram_in_gb - self.used_ram_in_gb
@property
def available_cores(self):
return self.usable_cores - sum([vm.cores for vm in self.vms ])
2020-08-01 14:29:24 +00:00
class VMProduct(Product):
2020-03-02 12:20:30 +00:00
vmhost = models.ForeignKey(
VMHost, on_delete=models.CASCADE, editable=False, blank=True, null=True
)
2020-03-22 19:55:11 +00:00
vmcluster = models.ForeignKey(
VMCluster, on_delete=models.CASCADE, editable=False, blank=True, null=True
)
# VM-specific. The name is only intended for customers: it's a pain to
# remember IDs (speaking from experience as ungleich customer)!
name = models.CharField(max_length=32, blank=True, null=True)
cores = models.IntegerField()
ram_in_gb = models.FloatField()
2020-04-18 11:51:31 +00:00
# Default recurring price is PER_MONTH, see uncloud_pay.models.Product.
2020-04-18 11:51:31 +00:00
@property
def recurring_price(self):
return self.cores * 3 + self.ram_in_gb * 4
2020-03-05 22:55:33 +00:00
def __str__(self):
2020-08-01 14:29:24 +00:00
if self.name:
name = f"{self.name} ({self.id})"
else:
name = self.id
return "VM {}: {} cores {} gb ram".format(name,
self.cores,
self.ram_in_gb)
2020-05-02 21:44:20 +00:00
2020-03-02 08:25:03 +00:00
@property
def description(self):
return "Virtual machine '{}': {} core(s), {}GB memory".format(
self.name, self.cores, self.ram_in_gb)
2020-03-03 09:51:16 +00:00
@staticmethod
def allowed_recurring_periods():
return list(filter(
lambda pair: pair[0] in [RecurringPeriod.PER_365D,
RecurringPeriod.PER_30D, RecurringPeriod.PER_HOUR],
2020-03-03 09:51:16 +00:00
RecurringPeriod.choices))
class VMWithOSProduct(VMProduct):
2020-04-18 11:51:31 +00:00
primary_disk = models.ForeignKey('VMDiskProduct', on_delete=models.CASCADE, null=True)
2020-03-21 10:59:04 +00:00
class VMDiskImageProduct(UncloudModel):
"""
Images are used for cloning/linking.
They are the base for images.
"""
owner = models.ForeignKey(
get_user_model(), on_delete=models.CASCADE, editable=False
)
name = models.CharField(max_length=256)
is_os_image = models.BooleanField(default=False)
is_public = models.BooleanField(default=False, editable=False) # only allow admins to set this
size_in_gb = models.FloatField(null=True, blank=True)
import_url = models.URLField(null=True, blank=True)
2020-03-03 18:46:39 +00:00
image_source = models.CharField(max_length=128, null=True)
image_source_type = models.CharField(max_length=128, null=True)
storage_class = models.CharField(max_length=32,
choices = uncloud_storage.models.StorageClass.choices,
default = uncloud_storage.models.StorageClass.SSD)
status = models.CharField(
2020-03-22 19:55:11 +00:00
max_length=32, choices=UncloudStatus.choices, default=UncloudStatus.PENDING
)
def __str__(self):
return "VMDiskImage {} ({}): {} gb".format(self.id,
self.name,
self.size_in_gb)
2020-08-01 14:29:24 +00:00
# See https://docs.djangoproject.com/en/dev/ref/models/fields/#field-choices-enum-types
class VMDiskType(models.TextChoices):
"""
Types of disks that can be attached to VMs
"""
CEPH_SSD = 'ceph/ssd'
CEPH_HDD = 'ceph/hdd'
LOCAL_SSD = 'local/ssd'
LOCAL_HDD = 'local/hdd'
class VMDiskProduct(Product):
"""
The VMDiskProduct is attached to a VM.
It is based on a VMDiskImageProduct that will be used as a basis.
It can be enlarged, but not shrinked compared to the VMDiskImageProduct.
"""
vm = models.ForeignKey(VMProduct, on_delete=models.CASCADE)
2020-08-01 16:30:40 +00:00
image = models.ForeignKey(VMDiskImageProduct, on_delete=models.CASCADE,
blank=True, null=True)
size_in_gb = models.FloatField(blank=True)
2020-08-01 14:29:24 +00:00
disk_type = models.CharField(
max_length=20,
choices=VMDiskType.choices,
default=VMDiskType.CEPH_SSD)
2020-08-01 16:48:51 +00:00
def __str__(self):
return "{} disk for VM '{}': {}GB".format(self.disk_type,
self.vm.name,
self.size_in_gb)
2020-04-18 11:51:31 +00:00
@property
def recurring_price(self):
2020-08-01 16:30:40 +00:00
if self.disk_type == VMDiskType.CEPH_SSD:
price_per_gb = 3.5/10
elif self.disk_type == VMDiskType.CEPH_HDD:
price_per_gb = 1.5/100
elif self.disk_type == VMDiskType.LOCAL_SSD:
price_per_gb = 3.5/10
elif self.disk_type == VMDiskType.CEPH_HDD:
price_per_gb = 1.5/100
return self.size_in_gb * price_per_gb
2020-05-02 18:31:36 +00:00
class VMNetworkCard(models.Model):
vm = models.ForeignKey(VMProduct, on_delete=models.CASCADE)
2020-03-03 18:46:39 +00:00
mac_address = models.BigIntegerField()
ip_address = models.GenericIPAddressField(blank=True,
null=True)
class VMSnapshotProduct(Product):
gb_ssd = models.FloatField(editable=False)
gb_hdd = models.FloatField(editable=False)
2020-03-18 14:19:06 +00:00
vm = models.ForeignKey(VMProduct,
related_name='snapshots',
on_delete=models.CASCADE)