From a7e9f3c09d809a223d32974aeb487adbfab6b6f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Mon, 9 Mar 2020 17:25:02 +0100 Subject: [PATCH 01/10] Move Order.add_record to save hook in abstract Product --- .../uncloud/uncloud_pay/models.py | 21 ++++++++++++------- .../uncloud/uncloud_vm/views.py | 10 --------- .../uncloud/ungleich_service/views.py | 14 ------------- 3 files changed, 14 insertions(+), 31 deletions(-) diff --git a/uncloud_django_based/uncloud/uncloud_pay/models.py b/uncloud_django_based/uncloud/uncloud_pay/models.py index d4e46b2..6e075a9 100644 --- a/uncloud_django_based/uncloud/uncloud_pay/models.py +++ b/uncloud_django_based/uncloud/uncloud_pay/models.py @@ -476,13 +476,6 @@ class Order(models.Model): def recurring_price(self): return reduce(lambda acc, record: acc + record.recurring_price, self.records, 0) - def add_record(self, one_time_price, recurring_price, description): - OrderRecord.objects.create(order=self, - one_time_price=one_time_price, - recurring_price=recurring_price, - description=description) - - class OrderRecord(models.Model): """ Order records store billing informations for products: the actual product @@ -543,6 +536,20 @@ class Product(UncloudModel): # Default period for all products default_recurring_period = RecurringPeriod.PER_MONTH + # Used to save records. + def save(self, *args, **kwargs): + # _state.adding is switched to false after super(...) call. + being_created = self._state.adding + + super(Product, self).save(*args, **kwargs) + + # Make sure we only create records on creation. + if being_created: + record = OrderRecord( + one_time_price=self.one_time_price, + recurring_price=self.recurring_price(self.recurring_period), + description=self.description) + self.order.orderrecord_set.add(record, bulk=False) @property def recurring_price(self, recurring_period=RecurringPeriod.PER_MONTH): diff --git a/uncloud_django_based/uncloud/uncloud_vm/views.py b/uncloud_django_based/uncloud/uncloud_vm/views.py index a29ecd7..c601c5b 100644 --- a/uncloud_django_based/uncloud/uncloud_vm/views.py +++ b/uncloud_django_based/uncloud/uncloud_vm/views.py @@ -127,11 +127,6 @@ class VMProductViewSet(ProductViewSet): # Create VM. vm = serializer.save(owner=request.user, order=order) - # Add Product record to order (VM is mutable, allows to keep history in order). - # XXX: Move this to some kind of on_create hook in parent Product class? - order.add_record(vm.one_time_price, - vm.recurring_price(order.recurring_period), vm.description) - return Response(serializer.data) @@ -215,9 +210,4 @@ class DCLCreateVMProductViewSet(ProductViewSet): # Create VM. vm = serializer.save(owner=request.user, order=order) - # Add Product record to order (VM is mutable, allows to keep history in order). - # XXX: Move this to some kind of on_create hook in parent Product class? - order.add_record(vm.one_time_price, - vm.recurring_price(order.recurring_period), vm.description) - return Response(serializer.data) diff --git a/uncloud_django_based/uncloud/ungleich_service/views.py b/uncloud_django_based/uncloud/ungleich_service/views.py index 47c15e2..9a7ff28 100644 --- a/uncloud_django_based/uncloud/ungleich_service/views.py +++ b/uncloud_django_based/uncloud/ungleich_service/views.py @@ -38,24 +38,10 @@ class MatrixServiceProductViewSet(ProductViewSet): vm_data['order'] = order vm = VMProduct.objects.create(**vm_data) - # XXX: Move this to some kind of on_create hook in parent - # Product class? - order.add_record( - vm.one_time_price, - vm.recurring_price(order.recurring_period), - vm.description) - # Create service. service = serializer.save( order=order, owner=self.request.user, vm=vm) - # XXX: Move this to some kind of on_create hook in parent - # Product class? - order.add_record( - service.one_time_price, - service.recurring_price(order.recurring_period), - service.description) - return Response(serializer.data) From d3b747029446a0088fcf6f550e1d00fd38f6c0c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Mon, 9 Mar 2020 14:18:07 +0100 Subject: [PATCH 02/10] Wire disk images to VM creation/ordering --- .../migrations/0004_vmproduct_primary_disk.py | 19 +++++++++++++ .../migrations/0005_auto_20200309_1258.py | 25 +++++++++++++++++ .../uncloud/uncloud_vm/models.py | 28 +++++++++++++------ .../uncloud/uncloud_vm/serializers.py | 26 +++++++++-------- .../uncloud/uncloud_vm/views.py | 9 ++++-- 5 files changed, 85 insertions(+), 22 deletions(-) create mode 100644 uncloud_django_based/uncloud/uncloud_vm/migrations/0004_vmproduct_primary_disk.py create mode 100644 uncloud_django_based/uncloud/uncloud_vm/migrations/0005_auto_20200309_1258.py diff --git a/uncloud_django_based/uncloud/uncloud_vm/migrations/0004_vmproduct_primary_disk.py b/uncloud_django_based/uncloud/uncloud_vm/migrations/0004_vmproduct_primary_disk.py new file mode 100644 index 0000000..90c4e33 --- /dev/null +++ b/uncloud_django_based/uncloud/uncloud_vm/migrations/0004_vmproduct_primary_disk.py @@ -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'), + ), + ] diff --git a/uncloud_django_based/uncloud/uncloud_vm/migrations/0005_auto_20200309_1258.py b/uncloud_django_based/uncloud/uncloud_vm/migrations/0005_auto_20200309_1258.py new file mode 100644 index 0000000..0356558 --- /dev/null +++ b/uncloud_django_based/uncloud/uncloud_vm/migrations/0005_auto_20200309_1258.py @@ -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), + ), + ] diff --git a/uncloud_django_based/uncloud/uncloud_vm/models.py b/uncloud_django_based/uncloud/uncloud_vm/models.py index 5b80b8f..ee8eed1 100644 --- a/uncloud_django_based/uncloud/uncloud_vm/models.py +++ b/uncloud_django_based/uncloud/uncloud_vm/models.py @@ -69,6 +69,7 @@ class VMProduct(Product): cores = models.IntegerField() 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): # 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. @@ -150,18 +151,27 @@ class VMDiskProduct(UncloudModel): It can be enlarged, but not shrinked compared to the VMDiskImageProduct. """ - uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) - owner = models.ForeignKey(get_user_model(), - on_delete=models.CASCADE, - editable=False) - - vm = models.ForeignKey(VMProduct, - related_name='disks', - on_delete=models.CASCADE) + vm = models.ForeignKey(VMProduct, on_delete=models.CASCADE) image = models.ForeignKey(VMDiskImageProduct, on_delete=models.CASCADE) 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 # Ensures that a VMDiskProduct can only be created from a VMDiskImageProduct diff --git a/uncloud_django_based/uncloud/uncloud_vm/serializers.py b/uncloud_django_based/uncloud/uncloud_vm/serializers.py index c0cca48..dbc9692 100644 --- a/uncloud_django_based/uncloud/uncloud_vm/serializers.py +++ b/uncloud_django_based/uncloud/uncloud_vm/serializers.py @@ -31,13 +31,16 @@ class VMDiskProductSerializer(serializers.ModelSerializer): model = VMDiskProduct fields = '__all__' +class CreateVMDiskProductSerializer(serializers.ModelSerializer): + class Meta: + model = VMDiskProduct + fields = ['size_in_gb', 'image'] + class VMDiskImageProductSerializer(serializers.ModelSerializer): class Meta: model = VMDiskImageProduct fields = '__all__' - - class DCLVMProductSerializer(serializers.HyperlinkedModelSerializer): """ Create an interface similar to standard DCL @@ -84,18 +87,19 @@ class VMSnapshotProductSerializer(serializers.ModelSerializer): pricing['per_gb_hdd'] = 0.0006 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. 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, read_only=True) diff --git a/uncloud_django_based/uncloud/uncloud_vm/views.py b/uncloud_django_based/uncloud/uncloud_vm/views.py index c601c5b..4efb013 100644 --- a/uncloud_django_based/uncloud/uncloud_vm/views.py +++ b/uncloud_django_based/uncloud/uncloud_vm/views.py @@ -122,10 +122,15 @@ class VMProductViewSet(ProductViewSet): owner=request.user, starting_date=timezone.now() ) - order.save() + + # Create disk image. + disk = VMDiskProduct(owner=request.user, order=order, + **serializer.validated_data.pop("primary_disk")) # 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) From a4cc4304f9566e79c70b82eae707c8106fa5c173 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Mon, 9 Mar 2020 16:37:56 +0100 Subject: [PATCH 03/10] Adapt managed service to create VMDiskProduct --- .../uncloud/uncloud_vm/serializers.py | 8 +++- .../uncloud/uncloud_vm/views.py | 1 - .../uncloud/ungleich_service/models.py | 7 ++- .../uncloud/ungleich_service/views.py | 44 ++++++++++++++----- 4 files changed, 45 insertions(+), 15 deletions(-) diff --git a/uncloud_django_based/uncloud/uncloud_vm/serializers.py b/uncloud_django_based/uncloud/uncloud_vm/serializers.py index dbc9692..9435de2 100644 --- a/uncloud_django_based/uncloud/uncloud_vm/serializers.py +++ b/uncloud_django_based/uncloud/uncloud_vm/serializers.py @@ -36,6 +36,11 @@ class CreateVMDiskProductSerializer(serializers.ModelSerializer): model = VMDiskProduct fields = ['size_in_gb', 'image'] +class CreateManagedVMDiskProductSerializer(serializers.ModelSerializer): + class Meta: + model = VMDiskProduct + fields = ['size_in_gb'] + class VMDiskImageProductSerializer(serializers.ModelSerializer): class Meta: model = VMDiskImageProduct @@ -60,9 +65,10 @@ class ManagedVMProductSerializer(serializers.ModelSerializer): """ Managed VM serializer used in ungleich_service app. """ + primary_disk = CreateManagedVMDiskProductSerializer() class Meta: model = VMProduct - fields = [ 'cores', 'ram_in_gb'] + fields = [ 'cores', 'ram_in_gb', 'primary_disk'] class VMSnapshotProductSerializer(serializers.ModelSerializer): class Meta: diff --git a/uncloud_django_based/uncloud/uncloud_vm/views.py b/uncloud_django_based/uncloud/uncloud_vm/views.py index 4efb013..50e2e66 100644 --- a/uncloud_django_based/uncloud/uncloud_vm/views.py +++ b/uncloud_django_based/uncloud/uncloud_vm/views.py @@ -89,7 +89,6 @@ class VMDiskProductViewSet(viewsets.ModelViewSet): if size_in_gb < serializer.validated_data['image'].size_in_gb: raise ValidationError(detail={ 'error_mesage': 'Size is smaller than original image' }) - serializer.save(owner=request.user, size_in_gb=size_in_gb) return Response(serializer.data) diff --git a/uncloud_django_based/uncloud/ungleich_service/models.py b/uncloud_django_based/uncloud/ungleich_service/models.py index 9d6a8ac..4f26a99 100644 --- a/uncloud_django_based/uncloud/ungleich_service/models.py +++ b/uncloud_django_based/uncloud/ungleich_service/models.py @@ -2,7 +2,7 @@ import uuid from django.db import models from uncloud_pay.models import Product, RecurringPeriod -from uncloud_vm.models import VMProduct +from uncloud_vm.models import VMProduct, VMDiskImageProduct class MatrixServiceProduct(Product): monthly_managment_fee = 20 @@ -21,6 +21,11 @@ class MatrixServiceProduct(Product): else: raise Exception('Invalid recurring period for VM Product pricing.') + @staticmethod + def base_image(): + # TODO: find a way to safely reference debian 10 image. + return VMDiskImageProduct.objects.get(uuid="93e564c5-adb3-4741-941f-718f76075f02") + @staticmethod def allowed_recurring_periods(): return list(filter( diff --git a/uncloud_django_based/uncloud/ungleich_service/views.py b/uncloud_django_based/uncloud/ungleich_service/views.py index 9a7ff28..e25f3a5 100644 --- a/uncloud_django_based/uncloud/ungleich_service/views.py +++ b/uncloud_django_based/uncloud/ungleich_service/views.py @@ -7,7 +7,28 @@ from .serializers import MatrixServiceProductSerializer from uncloud_pay.helpers import ProductViewSet from uncloud_pay.models import Order -from uncloud_vm.models import VMProduct +from uncloud_vm.models import VMProduct, VMDiskProduct + +def create_managed_vm(cores, ram, disk_size, image, order): + # Create VM + disk = VMDiskProduct( + owner=order.owner, + order=order, + size_in_gb=disk_size, + image=image) + vm = VMProduct( + name="Managed Service Host", + owner=order.owner, + cores=cores, + ram_in_gb=ram, + primary_disk=disk) + disk.vm = vm + + vm.save() + disk.save() + + return vm + class MatrixServiceProductViewSet(ProductViewSet): permission_classes = [permissions.IsAuthenticated] @@ -23,25 +44,24 @@ class MatrixServiceProductViewSet(ProductViewSet): serializer.is_valid(raise_exception=True) order_recurring_period = serializer.validated_data.pop("recurring_period") - # Create base order. + # Create base order.) order = Order.objects.create( recurring_period=order_recurring_period, - owner=request.user - ) - order.save() + owner=request.user) # Create unerderlying VM. - # TODO: move this logic to a method for use with other - # products. - vm_data = serializer.validated_data.pop('vm') - vm_data['owner'] = request.user - vm_data['order'] = order - vm = VMProduct.objects.create(**vm_data) + data = serializer.validated_data.pop('vm') + vm = create_managed_vm( + order=order, + cores=data['cores'], + ram=data['ram_in_gb'], + disk_size=data['primary_disk']['size_in_gb'], + image=MatrixServiceProduct.base_image()) # Create service. service = serializer.save( order=order, - owner=self.request.user, + owner=request.user, vm=vm) return Response(serializer.data) From e67bd039977b6633943cd01fbf075d7e690043ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Mon, 13 Apr 2020 11:18:24 +0200 Subject: [PATCH 04/10] Migration fix after rebase --- .../migrations/0005_auto_20200321_1058.py | 2 +- .../migrations/0009_merge_20200413_0857.py | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 uncloud_django_based/uncloud/uncloud_vm/migrations/0009_merge_20200413_0857.py diff --git a/uncloud_django_based/uncloud/uncloud_vm/migrations/0005_auto_20200321_1058.py b/uncloud_django_based/uncloud/uncloud_vm/migrations/0005_auto_20200321_1058.py index 3799e6a..40eface 100644 --- a/uncloud_django_based/uncloud/uncloud_vm/migrations/0005_auto_20200321_1058.py +++ b/uncloud_django_based/uncloud/uncloud_vm/migrations/0005_auto_20200321_1058.py @@ -8,7 +8,7 @@ import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ('uncloud_vm', '0004_remove_vmproduct_vmid'), + ('uncloud_vm', '0005_auto_20200309_1258'), ] operations = [ diff --git a/uncloud_django_based/uncloud/uncloud_vm/migrations/0009_merge_20200413_0857.py b/uncloud_django_based/uncloud/uncloud_vm/migrations/0009_merge_20200413_0857.py new file mode 100644 index 0000000..2a9d70c --- /dev/null +++ b/uncloud_django_based/uncloud/uncloud_vm/migrations/0009_merge_20200413_0857.py @@ -0,0 +1,14 @@ +# Generated by Django 3.0.5 on 2020-04-13 08:57 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('uncloud_vm', '0004_remove_vmproduct_vmid'), + ('uncloud_vm', '0008_auto_20200403_1727'), + ] + + operations = [ + ] From 1a58508f8b57bc70a3ac05960c54259ac913d1d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Mon, 13 Apr 2020 11:39:49 +0200 Subject: [PATCH 05/10] Rename ungleich_service into uncloud_service --- .../uncloud/uncloud/settings.py | 2 +- uncloud_django_based/uncloud/uncloud/urls.py | 2 +- .../__init__.py | 0 .../admin.py | 0 .../apps.py | 0 .../migrations/0001_initial.py | 10 ++++++---- .../migrations/__init__.py | 0 .../models.py | 0 .../serializers.py | 0 .../tests.py | 0 .../views.py | 0 .../0002_matrixserviceproduct_extra_data.py | 19 ------------------- .../migrations/0003_auto_20200322_1758.py | 18 ------------------ .../migrations/0004_auto_20200403_1727.py | 18 ------------------ 14 files changed, 8 insertions(+), 61 deletions(-) rename uncloud_django_based/uncloud/{ungleich_service => uncloud_service}/__init__.py (100%) rename uncloud_django_based/uncloud/{ungleich_service => uncloud_service}/admin.py (100%) rename uncloud_django_based/uncloud/{ungleich_service => uncloud_service}/apps.py (100%) rename uncloud_django_based/uncloud/{ungleich_service => uncloud_service}/migrations/0001_initial.py (69%) rename uncloud_django_based/uncloud/{ungleich_service => uncloud_service}/migrations/__init__.py (100%) rename uncloud_django_based/uncloud/{ungleich_service => uncloud_service}/models.py (100%) rename uncloud_django_based/uncloud/{ungleich_service => uncloud_service}/serializers.py (100%) rename uncloud_django_based/uncloud/{ungleich_service => uncloud_service}/tests.py (100%) rename uncloud_django_based/uncloud/{ungleich_service => uncloud_service}/views.py (100%) delete mode 100644 uncloud_django_based/uncloud/ungleich_service/migrations/0002_matrixserviceproduct_extra_data.py delete mode 100644 uncloud_django_based/uncloud/ungleich_service/migrations/0003_auto_20200322_1758.py delete mode 100644 uncloud_django_based/uncloud/ungleich_service/migrations/0004_auto_20200403_1727.py diff --git a/uncloud_django_based/uncloud/uncloud/settings.py b/uncloud_django_based/uncloud/uncloud/settings.py index c1eaab2..b525073 100644 --- a/uncloud_django_based/uncloud/uncloud/settings.py +++ b/uncloud_django_based/uncloud/uncloud/settings.py @@ -67,7 +67,7 @@ INSTALLED_APPS = [ 'uncloud_net', 'uncloud_storage', 'uncloud_vm', - 'ungleich_service', + 'uncloud_service', 'opennebula' ] diff --git a/uncloud_django_based/uncloud/uncloud/urls.py b/uncloud_django_based/uncloud/uncloud/urls.py index e65bb4e..00eaf16 100644 --- a/uncloud_django_based/uncloud/uncloud/urls.py +++ b/uncloud_django_based/uncloud/uncloud/urls.py @@ -27,7 +27,7 @@ from uncloud_auth import views as authviews from uncloud_net import views as netviews from uncloud_pay import views as payviews from uncloud_vm import views as vmviews -from ungleich_service import views as serviceviews +from uncloud_service import views as serviceviews router = routers.DefaultRouter() diff --git a/uncloud_django_based/uncloud/ungleich_service/__init__.py b/uncloud_django_based/uncloud/uncloud_service/__init__.py similarity index 100% rename from uncloud_django_based/uncloud/ungleich_service/__init__.py rename to uncloud_django_based/uncloud/uncloud_service/__init__.py diff --git a/uncloud_django_based/uncloud/ungleich_service/admin.py b/uncloud_django_based/uncloud/uncloud_service/admin.py similarity index 100% rename from uncloud_django_based/uncloud/ungleich_service/admin.py rename to uncloud_django_based/uncloud/uncloud_service/admin.py diff --git a/uncloud_django_based/uncloud/ungleich_service/apps.py b/uncloud_django_based/uncloud/uncloud_service/apps.py similarity index 100% rename from uncloud_django_based/uncloud/ungleich_service/apps.py rename to uncloud_django_based/uncloud/uncloud_service/apps.py diff --git a/uncloud_django_based/uncloud/ungleich_service/migrations/0001_initial.py b/uncloud_django_based/uncloud/uncloud_service/migrations/0001_initial.py similarity index 69% rename from uncloud_django_based/uncloud/ungleich_service/migrations/0001_initial.py rename to uncloud_django_based/uncloud/uncloud_service/migrations/0001_initial.py index ea3646d..f0f5535 100644 --- a/uncloud_django_based/uncloud/ungleich_service/migrations/0001_initial.py +++ b/uncloud_django_based/uncloud/uncloud_service/migrations/0001_initial.py @@ -1,6 +1,7 @@ -# Generated by Django 3.0.3 on 2020-03-09 07:57 +# Generated by Django 3.0.5 on 2020-04-13 09:38 from django.conf import settings +import django.contrib.postgres.fields.jsonb from django.db import migrations, models import django.db.models.deletion import uuid @@ -11,8 +12,8 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('uncloud_vm', '0003_remove_vmhost_vms'), - ('uncloud_pay', '0002_auto_20200305_1524'), + ('uncloud_pay', '0005_auto_20200413_0924'), + ('uncloud_vm', '0010_auto_20200413_0924'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] @@ -20,8 +21,9 @@ class Migration(migrations.Migration): migrations.CreateModel( name='MatrixServiceProduct', fields=[ + ('extra_data', django.contrib.postgres.fields.jsonb.JSONField(blank=True, editable=False, null=True)), ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), - ('status', models.CharField(choices=[('PENDING', 'Pending'), ('AWAITING_PAYMENT', 'Awaiting payment'), ('BEING_CREATED', 'Being created'), ('ACTIVE', 'Active'), ('DELETED', 'Deleted')], default='PENDING', max_length=32)), + ('status', models.CharField(choices=[('PENDING', 'Pending'), ('AWAITING_PAYMENT', 'Awaiting payment'), ('BEING_CREATED', 'Being created'), ('SCHEDULED', 'Scheduled'), ('ACTIVE', 'Active'), ('MODIFYING', 'Modifying'), ('DELETED', 'Deleted'), ('DISABLED', 'Disabled'), ('UNUSABLE', 'Unusable')], default='PENDING', max_length=32)), ('domain', models.CharField(default='domain.tld', max_length=255)), ('order', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, to='uncloud_pay.Order')), ('owner', models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), diff --git a/uncloud_django_based/uncloud/ungleich_service/migrations/__init__.py b/uncloud_django_based/uncloud/uncloud_service/migrations/__init__.py similarity index 100% rename from uncloud_django_based/uncloud/ungleich_service/migrations/__init__.py rename to uncloud_django_based/uncloud/uncloud_service/migrations/__init__.py diff --git a/uncloud_django_based/uncloud/ungleich_service/models.py b/uncloud_django_based/uncloud/uncloud_service/models.py similarity index 100% rename from uncloud_django_based/uncloud/ungleich_service/models.py rename to uncloud_django_based/uncloud/uncloud_service/models.py diff --git a/uncloud_django_based/uncloud/ungleich_service/serializers.py b/uncloud_django_based/uncloud/uncloud_service/serializers.py similarity index 100% rename from uncloud_django_based/uncloud/ungleich_service/serializers.py rename to uncloud_django_based/uncloud/uncloud_service/serializers.py diff --git a/uncloud_django_based/uncloud/ungleich_service/tests.py b/uncloud_django_based/uncloud/uncloud_service/tests.py similarity index 100% rename from uncloud_django_based/uncloud/ungleich_service/tests.py rename to uncloud_django_based/uncloud/uncloud_service/tests.py diff --git a/uncloud_django_based/uncloud/ungleich_service/views.py b/uncloud_django_based/uncloud/uncloud_service/views.py similarity index 100% rename from uncloud_django_based/uncloud/ungleich_service/views.py rename to uncloud_django_based/uncloud/uncloud_service/views.py diff --git a/uncloud_django_based/uncloud/ungleich_service/migrations/0002_matrixserviceproduct_extra_data.py b/uncloud_django_based/uncloud/ungleich_service/migrations/0002_matrixserviceproduct_extra_data.py deleted file mode 100644 index f755ddb..0000000 --- a/uncloud_django_based/uncloud/ungleich_service/migrations/0002_matrixserviceproduct_extra_data.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 3.0.3 on 2020-03-21 10:58 - -import django.contrib.postgres.fields.jsonb -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('ungleich_service', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='matrixserviceproduct', - name='extra_data', - field=django.contrib.postgres.fields.jsonb.JSONField(blank=True, editable=False, null=True), - ), - ] diff --git a/uncloud_django_based/uncloud/ungleich_service/migrations/0003_auto_20200322_1758.py b/uncloud_django_based/uncloud/ungleich_service/migrations/0003_auto_20200322_1758.py deleted file mode 100644 index 73dbd6a..0000000 --- a/uncloud_django_based/uncloud/ungleich_service/migrations/0003_auto_20200322_1758.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 3.0.3 on 2020-03-22 17:58 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('ungleich_service', '0002_matrixserviceproduct_extra_data'), - ] - - operations = [ - migrations.AlterField( - model_name='matrixserviceproduct', - name='status', - field=models.CharField(choices=[('PENDING', 'Pending'), ('AWAITING_PAYMENT', 'Awaiting payment'), ('BEING_CREATED', 'Being created'), ('ACTIVE', 'Active'), ('DELETED', 'Deleted'), ('DISABLED', 'Disabled'), ('UNUSABLE', 'Unusable')], default='PENDING', max_length=32), - ), - ] diff --git a/uncloud_django_based/uncloud/ungleich_service/migrations/0004_auto_20200403_1727.py b/uncloud_django_based/uncloud/ungleich_service/migrations/0004_auto_20200403_1727.py deleted file mode 100644 index eed8d33..0000000 --- a/uncloud_django_based/uncloud/ungleich_service/migrations/0004_auto_20200403_1727.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 3.0.5 on 2020-04-03 17:27 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('ungleich_service', '0003_auto_20200322_1758'), - ] - - operations = [ - migrations.AlterField( - model_name='matrixserviceproduct', - name='status', - field=models.CharField(choices=[('PENDING', 'Pending'), ('AWAITING_PAYMENT', 'Awaiting payment'), ('BEING_CREATED', 'Being created'), ('SCHEDULED', 'Scheduled'), ('ACTIVE', 'Active'), ('MODIFYING', 'Modifying'), ('DELETED', 'Deleted'), ('DISABLED', 'Disabled'), ('UNUSABLE', 'Unusable')], default='PENDING', max_length=32), - ), - ] From 05f8f1f6c0a7a75321864bb30fa53ee4ac261d6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Mon, 13 Apr 2020 11:40:19 +0200 Subject: [PATCH 06/10] Fix dependency issue in CI job --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 758f435..54e5bd1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -13,7 +13,7 @@ run-tests: POSTGRES_HOST_AUTH_METHOD: trust coverage: /^TOTAL.+?(\d+\%)$/ before_script: - - dnf install -y python3-devel python3-pip libpq-devel openldap-devel gcc + - dnf install -y python3-devel python3-pip python3-coverage libpq-devel openldap-devel gcc script: - cd uncloud_django_based/uncloud - pip install -r requirements.txt From 14f59430bb779467dc2b0194a948958700b713bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Mon, 13 Apr 2020 11:54:41 +0200 Subject: [PATCH 07/10] Restore Order.add_record, used by uncloud_pay tests --- uncloud_django_based/uncloud/uncloud_pay/models.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/uncloud_django_based/uncloud/uncloud_pay/models.py b/uncloud_django_based/uncloud/uncloud_pay/models.py index 6e075a9..59a149c 100644 --- a/uncloud_django_based/uncloud/uncloud_pay/models.py +++ b/uncloud_django_based/uncloud/uncloud_pay/models.py @@ -476,6 +476,15 @@ class Order(models.Model): def recurring_price(self): return reduce(lambda acc, record: acc + record.recurring_price, self.records, 0) + # Used by uncloud_pay tests. + def add_record(self, one_time_price, recurring_price, description): + OrderRecord.objects.create(order=self, + one_time_price=one_time_price, + recurring_price=recurring_price, + description=description) + + + class OrderRecord(models.Model): """ Order records store billing informations for products: the actual product From f5897ed4b13f19e44553d63c621b9c54c7f5b5e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Mon, 13 Apr 2020 12:00:59 +0200 Subject: [PATCH 08/10] Adapt recurring price of VM and Matrix to new scheme --- .../uncloud/uncloud_service/models.py | 8 +++----- uncloud_django_based/uncloud/uncloud_vm/models.py | 13 +++---------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/uncloud_django_based/uncloud/uncloud_service/models.py b/uncloud_django_based/uncloud/uncloud_service/models.py index 4f26a99..fb1af50 100644 --- a/uncloud_django_based/uncloud/uncloud_service/models.py +++ b/uncloud_django_based/uncloud/uncloud_service/models.py @@ -15,11 +15,9 @@ class MatrixServiceProduct(Product): ) domain = models.CharField(max_length=255, default='domain.tld') - def recurring_price(self, recurring_period=RecurringPeriod.PER_MONTH): - if recurring_period == RecurringPeriod.PER_MONTH: - return self.monthly_managment_fee - else: - raise Exception('Invalid recurring period for VM Product pricing.') + # Default recurring price is PER_MONT, see Product class. + def recurring_price(self): + return self.monthly_managment_fee @staticmethod def base_image(): diff --git a/uncloud_django_based/uncloud/uncloud_vm/models.py b/uncloud_django_based/uncloud/uncloud_vm/models.py index ee8eed1..f56ed0d 100644 --- a/uncloud_django_based/uncloud/uncloud_vm/models.py +++ b/uncloud_django_based/uncloud/uncloud_vm/models.py @@ -71,16 +71,9 @@ class VMProduct(Product): primary_disk = models.ForeignKey('VMDiskProduct', on_delete=models.CASCADE, null=True) - def recurring_price(self, recurring_period=RecurringPeriod.PER_MONTH): - # TODO: move magic numbers in variables - if recurring_period == RecurringPeriod.PER_MONTH: - return self.cores * 3 + self.ram_in_gb * 4 - elif recurring_period == RecurringPeriod.PER_HOUR: - return self.cores * 4.0/(30 * 24) + self.ram_in_gb * 4.5/(30* 24) - elif recurring_period == RecurringPeriod.PER_YEAR: - return (self.cores * 2.5 + self.ram_in_gb * 3.5) * 12 - else: - raise Exception('Invalid recurring period for VM Product pricing.') + # Default recurring price is PER_MONTH, see uncloud_pay.models.Product. + def recurring_price(self): + return self.cores * 3 + self.ram_in_gb * 4 def __str__(self): return "VM {} ({}): {} cores {} gb ram".format(self.uuid, From 9a57153c4edc3e737ed87451e5166752748156f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Mon, 13 Apr 2020 12:02:49 +0200 Subject: [PATCH 09/10] Commit missing migrations --- .../migrations/0005_auto_20200413_0924.py | 18 ++++++++++++++ .../migrations/0010_auto_20200413_0924.py | 24 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 uncloud_django_based/uncloud/uncloud_pay/migrations/0005_auto_20200413_0924.py create mode 100644 uncloud_django_based/uncloud/uncloud_vm/migrations/0010_auto_20200413_0924.py diff --git a/uncloud_django_based/uncloud/uncloud_pay/migrations/0005_auto_20200413_0924.py b/uncloud_django_based/uncloud/uncloud_pay/migrations/0005_auto_20200413_0924.py new file mode 100644 index 0000000..3f6a646 --- /dev/null +++ b/uncloud_django_based/uncloud/uncloud_pay/migrations/0005_auto_20200413_0924.py @@ -0,0 +1,18 @@ +# Generated by Django 3.0.5 on 2020-04-13 09:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('uncloud_pay', '0004_auto_20200409_1225'), + ] + + operations = [ + migrations.AlterField( + model_name='order', + name='recurring_period', + field=models.CharField(choices=[('ONCE', 'Onetime'), ('YEAR', 'Per Year'), ('MONTH', 'Per Month'), ('WEEK', 'Per Week'), ('DAY', 'Per Day'), ('HOUR', 'Per Hour'), ('MINUTE', 'Per Minute'), ('SECOND', 'Per Second')], default='MONTH', max_length=32), + ), + ] diff --git a/uncloud_django_based/uncloud/uncloud_vm/migrations/0010_auto_20200413_0924.py b/uncloud_django_based/uncloud/uncloud_vm/migrations/0010_auto_20200413_0924.py new file mode 100644 index 0000000..8883277 --- /dev/null +++ b/uncloud_django_based/uncloud/uncloud_vm/migrations/0010_auto_20200413_0924.py @@ -0,0 +1,24 @@ +# Generated by Django 3.0.5 on 2020-04-13 09:24 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('uncloud_vm', '0009_merge_20200413_0857'), + ] + + operations = [ + migrations.AlterField( + model_name='vmdiskproduct', + name='status', + field=models.CharField(choices=[('PENDING', 'Pending'), ('AWAITING_PAYMENT', 'Awaiting payment'), ('BEING_CREATED', 'Being created'), ('SCHEDULED', 'Scheduled'), ('ACTIVE', 'Active'), ('MODIFYING', 'Modifying'), ('DELETED', 'Deleted'), ('DISABLED', 'Disabled'), ('UNUSABLE', 'Unusable')], default='PENDING', max_length=32), + ), + migrations.AlterField( + model_name='vmdiskproduct', + name='vm', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='uncloud_vm.VMProduct'), + ), + ] From aa0702faba274eb942245954f19fa3fc37011695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Mon, 13 Apr 2020 12:06:03 +0200 Subject: [PATCH 10/10] Add chromium to path on CI environment --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 54e5bd1..afdc4a1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -13,7 +13,7 @@ run-tests: POSTGRES_HOST_AUTH_METHOD: trust coverage: /^TOTAL.+?(\d+\%)$/ before_script: - - dnf install -y python3-devel python3-pip python3-coverage libpq-devel openldap-devel gcc + - dnf install -y python3-devel python3-pip python3-coverage libpq-devel openldap-devel gcc chromium script: - cd uncloud_django_based/uncloud - pip install -r requirements.txt