Make VM order-able again
This commit is contained in:
parent
df059fb00d
commit
d794b24c86
5 changed files with 70 additions and 34 deletions
|
@ -636,6 +636,20 @@ class Order(models.Model):
|
||||||
def bills(self):
|
def bills(self):
|
||||||
return Bill.objects.filter(order=self)
|
return Bill.objects.filter(order=self)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_product(product, **kwargs):
|
||||||
|
# FIXME: this is only a workaround.
|
||||||
|
billing_address = BillingAddress.get_preferred_address_for(product.owner)
|
||||||
|
if billing_address == None:
|
||||||
|
raise Exception("Owner does not have a billing address!")
|
||||||
|
|
||||||
|
return Order(description=product.description,
|
||||||
|
one_time_price=product.one_time_price,
|
||||||
|
recurring_price=product.recurring_price,
|
||||||
|
billing_address=billing_address,
|
||||||
|
owner=product.owner,
|
||||||
|
**kwargs)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "Order {} created at {}, {}->{}, recurring period {}. One time price {}, recurring price {}".format(
|
return "Order {} created at {}, {}->{}, recurring period {}. One time price {}, recurring price {}".format(
|
||||||
self.uuid, self.creation_date,
|
self.uuid, self.creation_date,
|
||||||
|
|
19
uncloud_vm/migrations/0014_vmwithosproduct_primary_disk.py
Normal file
19
uncloud_vm/migrations/0014_vmwithosproduct_primary_disk.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 3.0.6 on 2020-05-08 14:01
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('uncloud_vm', '0013_remove_vmproduct_primary_disk'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='vmwithosproduct',
|
||||||
|
name='primary_disk',
|
||||||
|
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='uncloud_vm.VMDiskProduct'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -69,7 +69,7 @@ class VMProduct(Product):
|
||||||
cores = models.IntegerField()
|
cores = models.IntegerField()
|
||||||
ram_in_gb = models.FloatField()
|
ram_in_gb = models.FloatField()
|
||||||
|
|
||||||
|
# Default recurring price is PER_MONTH, see uncloud_pay.models.Product.
|
||||||
@property
|
@property
|
||||||
def recurring_price(self):
|
def recurring_price(self):
|
||||||
return self.cores * 3 + self.ram_in_gb * 4
|
return self.cores * 3 + self.ram_in_gb * 4
|
||||||
|
@ -99,7 +99,7 @@ class VMProduct(Product):
|
||||||
|
|
||||||
|
|
||||||
class VMWithOSProduct(VMProduct):
|
class VMWithOSProduct(VMProduct):
|
||||||
pass
|
primary_disk = models.ForeignKey('VMDiskProduct', on_delete=models.CASCADE, null=True)
|
||||||
|
|
||||||
|
|
||||||
class VMDiskImageProduct(UncloudModel):
|
class VMDiskImageProduct(UncloudModel):
|
||||||
|
|
|
@ -2,7 +2,7 @@ from django.contrib.auth import get_user_model
|
||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from .models import VMHost, VMProduct, VMSnapshotProduct, VMDiskProduct, VMDiskImageProduct, VMCluster
|
from .models import *
|
||||||
from uncloud_pay.models import RecurringPeriod, BillingAddress
|
from uncloud_pay.models import RecurringPeriod, BillingAddress
|
||||||
|
|
||||||
# XXX: does not seem to be used?
|
# XXX: does not seem to be used?
|
||||||
|
@ -86,40 +86,33 @@ class ManagedVMProductSerializer(serializers.ModelSerializer):
|
||||||
"""
|
"""
|
||||||
primary_disk = CreateManagedVMDiskProductSerializer()
|
primary_disk = CreateManagedVMDiskProductSerializer()
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VMProduct
|
model = VMWithOSProduct
|
||||||
fields = [ 'cores', 'ram_in_gb', 'primary_disk']
|
fields = [ 'cores', 'ram_in_gb', 'primary_disk']
|
||||||
|
|
||||||
class VMProductSerializer(serializers.HyperlinkedModelSerializer):
|
class VMProductSerializer(serializers.ModelSerializer):
|
||||||
primary_disk = CreateVMDiskProductSerializer()
|
primary_disk = CreateVMDiskProductSerializer()
|
||||||
snapshots = VMSnapshotProductSerializer(many=True, read_only=True)
|
snapshots = VMSnapshotProductSerializer(many=True, read_only=True)
|
||||||
disks = VMDiskProductSerializer(many=True, read_only=True)
|
disks = VMDiskProductSerializer(many=True, read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VMProduct
|
model = VMWithOSProduct
|
||||||
fields = ['uuid', 'order', 'owner', 'status', 'name', 'cores',
|
fields = ['uuid', 'order', 'owner', 'status', 'name', 'cores',
|
||||||
'ram_in_gb', 'primary_disk', 'snapshots', 'disks', 'extra_data']
|
'ram_in_gb', 'primary_disk', 'snapshots', 'disks', 'extra_data']
|
||||||
read_only_fields = ['uuid', 'order', 'owner', 'status']
|
read_only_fields = ['uuid', 'order', 'owner', 'status']
|
||||||
|
|
||||||
class OrderVMProductSerializer(VMProductSerializer):
|
class OrderVMProductSerializer(VMProductSerializer):
|
||||||
recurring_period = serializers.ChoiceField(
|
recurring_period = serializers.ChoiceField(
|
||||||
choices=VMProduct.allowed_recurring_periods())
|
choices=VMWithOSProduct.allowed_recurring_periods())
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(VMProductSerializer, self).__init__(*args, **kwargs)
|
super(VMProductSerializer, self).__init__(*args, **kwargs)
|
||||||
self.fields['billing_address'] = serializers.ChoiceField(
|
|
||||||
choices=BillingAddress.get_addresses_for(
|
|
||||||
self.context['request'].user)
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VMProductSerializer.Meta.model
|
model = VMProductSerializer.Meta.model
|
||||||
fields = VMProductSerializer.Meta.fields + [
|
fields = VMProductSerializer.Meta.fields + [ 'recurring_period' ]
|
||||||
'recurring_period', 'billing_address'
|
|
||||||
]
|
|
||||||
read_only_fields = VMProductSerializer.Meta.read_only_fields
|
read_only_fields = VMProductSerializer.Meta.read_only_fields
|
||||||
|
|
||||||
# Nico's playground.
|
# Nico's playground.
|
||||||
|
|
||||||
class NicoVMProductSerializer(serializers.ModelSerializer):
|
class NicoVMProductSerializer(serializers.ModelSerializer):
|
||||||
snapshots = VMSnapshotProductSerializer(many=True, read_only=True)
|
snapshots = VMSnapshotProductSerializer(many=True, read_only=True)
|
||||||
order = serializers.StringRelatedField()
|
order = serializers.StringRelatedField()
|
||||||
|
@ -134,7 +127,6 @@ class NicoVMProductSerializer(serializers.ModelSerializer):
|
||||||
'ram_in_gb'
|
'ram_in_gb'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class DCLVMProductSerializer(serializers.HyperlinkedModelSerializer):
|
class DCLVMProductSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
"""
|
"""
|
||||||
Create an interface similar to standard DCL
|
Create an interface similar to standard DCL
|
||||||
|
|
|
@ -10,7 +10,7 @@ from rest_framework.response import Response
|
||||||
from rest_framework.exceptions import ValidationError
|
from rest_framework.exceptions import ValidationError
|
||||||
|
|
||||||
from .models import VMHost, VMProduct, VMSnapshotProduct, VMDiskProduct, VMDiskImageProduct, VMCluster
|
from .models import VMHost, VMProduct, VMSnapshotProduct, VMDiskProduct, VMDiskImageProduct, VMCluster
|
||||||
from uncloud_pay.models import Order
|
from uncloud_pay.models import Order, BillingAddress
|
||||||
|
|
||||||
from .serializers import *
|
from .serializers import *
|
||||||
from uncloud_pay.helpers import ProductViewSet
|
from uncloud_pay.helpers import ProductViewSet
|
||||||
|
@ -136,9 +136,9 @@ class VMProductViewSet(ProductViewSet):
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
if self.request.user.is_superuser:
|
if self.request.user.is_superuser:
|
||||||
obj = VMProduct.objects.all()
|
obj = VMWithOSProduct.objects.all()
|
||||||
else:
|
else:
|
||||||
obj = VMProduct.objects.filter(owner=self.request.user)
|
obj = VMWithOSProduct.objects.filter(owner=self.request.user)
|
||||||
|
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
@ -156,29 +156,39 @@ class VMProductViewSet(ProductViewSet):
|
||||||
serializer = self.get_serializer(data=request.data)
|
serializer = self.get_serializer(data=request.data)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
order_recurring_period = serializer.validated_data.pop("recurring_period")
|
order_recurring_period = serializer.validated_data.pop("recurring_period")
|
||||||
order_billing_address = serializer.validated_data.pop("billing_address")
|
|
||||||
|
|
||||||
# Create base order.
|
|
||||||
order = Order(
|
|
||||||
recurring_period=order_recurring_period,
|
|
||||||
billing_address=order_billing_address,
|
|
||||||
owner=request.user,
|
|
||||||
starting_date=timezone.now()
|
|
||||||
)
|
|
||||||
order.save()
|
|
||||||
|
|
||||||
# Create disk image.
|
# Create disk image.
|
||||||
disk = VMDiskProduct(owner=request.user, order=order,
|
disk = VMDiskProduct(owner=request.user,
|
||||||
**serializer.validated_data.pop("primary_disk"))
|
**serializer.validated_data.pop("primary_disk"))
|
||||||
|
vm = VMWithOSProduct(owner=request.user, primary_disk=disk,
|
||||||
|
**serializer.validated_data)
|
||||||
|
disk.vm = vm # XXX: Is this really needed?
|
||||||
|
|
||||||
# Create VM.
|
# Create VM and Disk orders.
|
||||||
vm = serializer.save(owner=request.user, order=order, primary_disk=disk)
|
vm_order = Order.from_product(
|
||||||
disk.vm = vm
|
vm,
|
||||||
|
recurring_period=order_recurring_period,
|
||||||
|
starting_date=timezone.now()
|
||||||
|
)
|
||||||
|
|
||||||
|
disk_order = Order.from_product(
|
||||||
|
disk,
|
||||||
|
recurring_period=order_recurring_period,
|
||||||
|
starting_date=timezone.now()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Commit to DB.
|
||||||
|
vm.order = vm_order
|
||||||
|
vm.save()
|
||||||
|
vm_order.save()
|
||||||
|
|
||||||
|
disk.order = disk_order
|
||||||
|
disk_order.save()
|
||||||
disk.save()
|
disk.save()
|
||||||
|
|
||||||
return Response(VMProductSerializer(vm, context={'request': request}).data)
|
return Response(VMProductSerializer(vm, context={'request': request}).data)
|
||||||
|
|
||||||
|
|
||||||
class NicoVMProductViewSet(ProductViewSet):
|
class NicoVMProductViewSet(ProductViewSet):
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
permission_classes = [permissions.IsAuthenticated]
|
||||||
serializer_class = NicoVMProductSerializer
|
serializer_class = NicoVMProductSerializer
|
||||||
|
@ -194,6 +204,7 @@ class NicoVMProductViewSet(ProductViewSet):
|
||||||
|
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
|
|
||||||
|
|
||||||
###
|
###
|
||||||
# Admin stuff.
|
# Admin stuff.
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue