Wire disk images to VM creation/ordering
This commit is contained in:
parent
a7e9f3c09d
commit
d3b7470294
5 changed files with 85 additions and 22 deletions
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 3.0.3 on 2020-03-09 12:43
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('uncloud_vm', '0003_remove_vmhost_vms'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='vmproduct',
|
||||||
|
name='primary_disk',
|
||||||
|
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='uncloud_vm.VMDiskProduct'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,25 @@
|
||||||
|
# Generated by Django 3.0.3 on 2020-03-09 12:58
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('uncloud_pay', '0001_initial'),
|
||||||
|
('uncloud_vm', '0004_vmproduct_primary_disk'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='vmdiskproduct',
|
||||||
|
name='order',
|
||||||
|
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, to='uncloud_pay.Order'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='vmdiskproduct',
|
||||||
|
name='status',
|
||||||
|
field=models.CharField(choices=[('PENDING', 'Pending'), ('AWAITING_PAYMENT', 'Awaiting payment'), ('BEING_CREATED', 'Being created'), ('ACTIVE', 'Active'), ('DELETED', 'Deleted')], default='PENDING', max_length=32),
|
||||||
|
),
|
||||||
|
]
|
|
@ -69,6 +69,7 @@ class VMProduct(Product):
|
||||||
cores = models.IntegerField()
|
cores = models.IntegerField()
|
||||||
ram_in_gb = models.FloatField()
|
ram_in_gb = models.FloatField()
|
||||||
|
|
||||||
|
primary_disk = models.ForeignKey('VMDiskProduct', on_delete=models.CASCADE, null=True)
|
||||||
|
|
||||||
def recurring_price(self, recurring_period=RecurringPeriod.PER_MONTH):
|
def recurring_price(self, recurring_period=RecurringPeriod.PER_MONTH):
|
||||||
# TODO: move magic numbers in variables
|
# TODO: move magic numbers in variables
|
||||||
|
@ -141,7 +142,7 @@ class VMDiskImageProduct(UncloudModel):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class VMDiskProduct(UncloudModel):
|
class VMDiskProduct(Product):
|
||||||
"""
|
"""
|
||||||
The VMDiskProduct is attached to a VM.
|
The VMDiskProduct is attached to a VM.
|
||||||
|
|
||||||
|
@ -150,18 +151,27 @@ class VMDiskProduct(UncloudModel):
|
||||||
It can be enlarged, but not shrinked compared to the VMDiskImageProduct.
|
It can be enlarged, but not shrinked compared to the VMDiskImageProduct.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
vm = models.ForeignKey(VMProduct, on_delete=models.CASCADE)
|
||||||
owner = models.ForeignKey(get_user_model(),
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
editable=False)
|
|
||||||
|
|
||||||
vm = models.ForeignKey(VMProduct,
|
|
||||||
related_name='disks',
|
|
||||||
on_delete=models.CASCADE)
|
|
||||||
image = models.ForeignKey(VMDiskImageProduct, on_delete=models.CASCADE)
|
image = models.ForeignKey(VMDiskImageProduct, on_delete=models.CASCADE)
|
||||||
|
|
||||||
size_in_gb = models.FloatField(blank=True)
|
size_in_gb = models.FloatField(blank=True)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def description(self):
|
||||||
|
return "Disk for VM '{}': {}GB".format(self.vm.name, self.size_in_gb)
|
||||||
|
|
||||||
|
# TODO: move magic numbers in variables
|
||||||
|
def recurring_price(self, recurring_period=RecurringPeriod.PER_MONTH):
|
||||||
|
# TODO: move magic numbers in variables
|
||||||
|
if recurring_period == RecurringPeriod.PER_MONTH:
|
||||||
|
return (self.size_in_gb / 10) * 3.5
|
||||||
|
if recurring_period == RecurringPeriod.PER_YEAR:
|
||||||
|
return recurring_price(self, recurring_period.PER_MONTH) * 12
|
||||||
|
if recurring_period == RecurringPeriod.PER_HOUR:
|
||||||
|
return recurring_price(self, recurring_period.PER_MONTH) / 25
|
||||||
|
else:
|
||||||
|
raise Exception('Invalid recurring period for VM Disk Product pricing.')
|
||||||
|
|
||||||
# Sample code for clean method
|
# Sample code for clean method
|
||||||
|
|
||||||
# Ensures that a VMDiskProduct can only be created from a VMDiskImageProduct
|
# Ensures that a VMDiskProduct can only be created from a VMDiskImageProduct
|
||||||
|
|
|
@ -31,13 +31,16 @@ class VMDiskProductSerializer(serializers.ModelSerializer):
|
||||||
model = VMDiskProduct
|
model = VMDiskProduct
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
|
class CreateVMDiskProductSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = VMDiskProduct
|
||||||
|
fields = ['size_in_gb', 'image']
|
||||||
|
|
||||||
class VMDiskImageProductSerializer(serializers.ModelSerializer):
|
class VMDiskImageProductSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VMDiskImageProduct
|
model = VMDiskImageProduct
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class DCLVMProductSerializer(serializers.HyperlinkedModelSerializer):
|
class DCLVMProductSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
"""
|
"""
|
||||||
Create an interface similar to standard DCL
|
Create an interface similar to standard DCL
|
||||||
|
@ -84,18 +87,19 @@ class VMSnapshotProductSerializer(serializers.ModelSerializer):
|
||||||
pricing['per_gb_hdd'] = 0.0006
|
pricing['per_gb_hdd'] = 0.0006
|
||||||
pricing['recurring_period'] = 'per_day'
|
pricing['recurring_period'] = 'per_day'
|
||||||
|
|
||||||
class VMProductSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = VMProduct
|
|
||||||
fields = ['uuid', 'order', 'owner', 'status', 'name',
|
|
||||||
'cores', 'ram_in_gb', 'recurring_period',
|
|
||||||
'snapshots', 'disks',
|
|
||||||
'extra_data' ]
|
|
||||||
read_only_fields = ['uuid', 'order', 'owner', 'status' ]
|
|
||||||
|
|
||||||
|
class VMProductSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
# Custom field used at creation (= ordering) only.
|
# Custom field used at creation (= ordering) only.
|
||||||
recurring_period = serializers.ChoiceField(
|
recurring_period = serializers.ChoiceField(
|
||||||
choices=VMProduct.allowed_recurring_periods())
|
choices=VMProduct.allowed_recurring_periods())
|
||||||
|
primary_disk = CreateVMDiskProductSerializer()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = VMProduct
|
||||||
|
fields = ['uuid', 'order', 'owner', 'status', 'name', \
|
||||||
|
'cores', 'ram_in_gb', 'recurring_period', 'primary_disk',
|
||||||
|
'snapshots', 'disks', 'extra_data' ]
|
||||||
|
read_only_fields = ['uuid', 'order', 'owner', 'status']
|
||||||
|
|
||||||
snapshots = VMSnapshotProductSerializer(many=True,
|
snapshots = VMSnapshotProductSerializer(many=True,
|
||||||
read_only=True)
|
read_only=True)
|
||||||
|
|
|
@ -122,10 +122,15 @@ class VMProductViewSet(ProductViewSet):
|
||||||
owner=request.user,
|
owner=request.user,
|
||||||
starting_date=timezone.now()
|
starting_date=timezone.now()
|
||||||
)
|
)
|
||||||
order.save()
|
|
||||||
|
# Create disk image.
|
||||||
|
disk = VMDiskProduct(owner=request.user, order=order,
|
||||||
|
**serializer.validated_data.pop("primary_disk"))
|
||||||
|
|
||||||
# Create VM.
|
# Create VM.
|
||||||
vm = serializer.save(owner=request.user, order=order)
|
vm = serializer.save(owner=request.user, order=order, primary_disk=disk)
|
||||||
|
disk.vm = vm
|
||||||
|
disk.save()
|
||||||
|
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue