Make VM order-able again

This commit is contained in:
fnux 2020-04-18 13:51:31 +02:00
parent df059fb00d
commit d794b24c86
5 changed files with 70 additions and 34 deletions

View file

@ -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,

View 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'),
),
]

View file

@ -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):

View file

@ -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

View file

@ -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.