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…
	
	Add table
		Add a link
		
	
		Reference in a new issue