forked from uncloud/uncloud
Move snapshot to _pay and _vm
This commit is contained in:
parent
1ca247148c
commit
a58a361254
8 changed files with 140 additions and 192 deletions
|
@ -51,6 +51,12 @@ Installing the postgresql service is os dependent, but some hints:
|
||||||
* Alpine: `apk add postgresql-server && rc-update add postgresql && rc-service postgresql start`
|
* Alpine: `apk add postgresql-server && rc-update add postgresql && rc-service postgresql start`
|
||||||
* Debian/Devuan: `apt install postgresql`
|
* Debian/Devuan: `apt install postgresql`
|
||||||
|
|
||||||
|
After postresql is started, apply the migrations:
|
||||||
|
|
||||||
|
```
|
||||||
|
python manage.py migrate
|
||||||
|
```
|
||||||
|
|
||||||
### Secrets
|
### Secrets
|
||||||
|
|
||||||
cp `uncloud/secrets_sample.py` to `uncloud/secrets.py` and replace the
|
cp `uncloud/secrets_sample.py` to `uncloud/secrets.py` and replace the
|
||||||
|
|
|
@ -1,139 +0,0 @@
|
||||||
import uuid
|
|
||||||
|
|
||||||
from django.db import models
|
|
||||||
from django.contrib.auth import get_user_model
|
|
||||||
|
|
||||||
# Product in DB vs. product in code
|
|
||||||
# DB:
|
|
||||||
# - need to define params (+param types) in db -> messy?
|
|
||||||
# - get /products/ is easy / automatic
|
|
||||||
#
|
|
||||||
# code
|
|
||||||
# - can have serializer/verification of fields easily in DRF
|
|
||||||
# - can have per product side effects / extra code running
|
|
||||||
# - might (??) make features easier??
|
|
||||||
# - how to setup / query the recurring period (?)
|
|
||||||
# - could get products list via getattr() + re ...Product() classes
|
|
||||||
# -> this could include the url for ordering => /order/vm_snapshot (params)
|
|
||||||
# ---> this would work with urlpatterns
|
|
||||||
|
|
||||||
# Combination: create specific product in DB (?)
|
|
||||||
# - a table per product (?) with 1 entry?
|
|
||||||
|
|
||||||
# Orders
|
|
||||||
# define state in DB
|
|
||||||
# select a price from a product => product might change, order stays
|
|
||||||
# params:
|
|
||||||
# - the product uuid or name (?) => productuuid
|
|
||||||
# - the product parameters => for each feature
|
|
||||||
#
|
|
||||||
|
|
||||||
# logs
|
|
||||||
# Should have a log = ... => 1:n field for most models!
|
|
||||||
|
|
||||||
class Product(models.Model):
|
|
||||||
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
|
||||||
owner = models.ForeignKey(get_user_model(),
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
editable=False)
|
|
||||||
|
|
||||||
# override these fields by default
|
|
||||||
|
|
||||||
description = ""
|
|
||||||
recurring_period = "not_recurring"
|
|
||||||
|
|
||||||
status = models.CharField(max_length=256,
|
|
||||||
choices = (
|
|
||||||
('pending', 'Pending'),
|
|
||||||
('being_created', 'Being created'),
|
|
||||||
('active', 'Active'),
|
|
||||||
('deleted', 'Deleted')
|
|
||||||
),
|
|
||||||
default='pending'
|
|
||||||
)
|
|
||||||
|
|
||||||
# This is calculated by each product and saved in the DB
|
|
||||||
recurring_price = models.FloatField(editable=False)
|
|
||||||
one_time_price = models.FloatField(editable=False)
|
|
||||||
|
|
||||||
# FIXME: need recurring_time_frame
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
abstract = True
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "{}".format(self.name)
|
|
||||||
|
|
||||||
|
|
||||||
class VMSnapshotProduct(Product):
|
|
||||||
price_per_gb_ssd = 0.35
|
|
||||||
price_per_gb_hdd = 1.5/100
|
|
||||||
|
|
||||||
# This we need to get from the VM
|
|
||||||
gb_ssd = models.FloatField(editable=False)
|
|
||||||
gb_hdd = models.FloatField(editable=False)
|
|
||||||
|
|
||||||
vm_uuid = models.UUIDField()
|
|
||||||
|
|
||||||
# Need to setup recurring_price and one_time_price and recurring period
|
|
||||||
|
|
||||||
sample_ssd = 10
|
|
||||||
sample_hdd = 100
|
|
||||||
|
|
||||||
def recurring_price(self):
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def one_time_price(self):
|
|
||||||
return 0
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def sample_price(cls):
|
|
||||||
return cls.sample_ssd * cls.price_per_gb_ssd + cls.sample_hdd * cls.price_per_gb_hdd
|
|
||||||
|
|
||||||
description = "Create snapshot of a VM"
|
|
||||||
recurring_period = "monthly"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def pricing_model(cls):
|
|
||||||
return """
|
|
||||||
Pricing is on monthly basis and storage prices are equivalent to the storage
|
|
||||||
price in the VM.
|
|
||||||
|
|
||||||
Price per GB SSD is: {}
|
|
||||||
Price per GB HDD is: {}
|
|
||||||
|
|
||||||
|
|
||||||
Sample price for a VM with {} GB SSD and {} GB HDD VM is: {}.
|
|
||||||
""".format(cls.price_per_gb_ssd, cls.price_per_gb_hdd,
|
|
||||||
cls.sample_ssd, cls.sample_hdd, cls.sample_price())
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Feature(models.Model):
|
|
||||||
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
|
||||||
name = models.CharField(max_length=256)
|
|
||||||
|
|
||||||
recurring_price = models.FloatField(default=0)
|
|
||||||
one_time_price = models.FloatField()
|
|
||||||
|
|
||||||
product = models.ForeignKey(Product, on_delete=models.CASCADE)
|
|
||||||
|
|
||||||
# params for "cpu": cpu_count -> int
|
|
||||||
# each feature can only have one parameters
|
|
||||||
# could call this "value" and set whether it is user usable
|
|
||||||
# has_value = True/False
|
|
||||||
# value = string -> int (?)
|
|
||||||
# value_int
|
|
||||||
# value_str
|
|
||||||
# value_float
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
abstract = True
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "'{}' - '{}'".format(self.product, self.name)
|
|
|
@ -3,8 +3,6 @@ from django.contrib.auth import get_user_model
|
||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from .models import VMSnapshotProduct
|
|
||||||
|
|
||||||
class UserSerializer(serializers.ModelSerializer):
|
class UserSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = get_user_model()
|
model = get_user_model()
|
||||||
|
@ -14,13 +12,3 @@ class GroupSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Group
|
model = Group
|
||||||
fields = ['url', 'name']
|
fields = ['url', 'name']
|
||||||
|
|
||||||
class VMSnapshotSerializer(serializers.HyperlinkedModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = VMSnapshotProduct
|
|
||||||
fields = ['uuid', 'status', 'recurring_price', 'one_time_price' ]
|
|
||||||
|
|
||||||
class VMSnapshotCreateSerializer(serializers.HyperlinkedModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = VMSnapshotProduct
|
|
||||||
fields = '__all__'
|
|
||||||
|
|
|
@ -17,46 +17,6 @@ import sys
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
||||||
# POST /vm/snapshot/ vmuuid=... => create snapshot, returns snapshot uuid
|
|
||||||
# GET /vm/snapshot => list
|
|
||||||
# DEL /vm/snapshot/<uuid:uuid> => delete
|
|
||||||
# create-list -> get, post => ListCreateAPIView
|
|
||||||
# del on other!
|
|
||||||
class VMSnapshotView(viewsets.ViewSet):
|
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
|
||||||
|
|
||||||
def list(self, request):
|
|
||||||
queryset = VMSnapshotProduct.objects.filter(owner=request.user)
|
|
||||||
serializer = VMSnapshotSerializer(queryset, many=True, context={'request': request})
|
|
||||||
return Response(serializer.data)
|
|
||||||
|
|
||||||
def retrieve(self, request, pk=None):
|
|
||||||
queryset = VMSnapshotProduct.objects.filter(owner=request.user)
|
|
||||||
vm = get_object_or_404(queryset, pk=pk)
|
|
||||||
serializer = VMSnapshotSerializer(vm, context={'request': request})
|
|
||||||
return Response(serializer.data)
|
|
||||||
|
|
||||||
def create(self, request):
|
|
||||||
print(request.data)
|
|
||||||
serializer = VMSnapshotCreateSerializer(data=request.data)
|
|
||||||
|
|
||||||
serializer.gb_ssd = 12
|
|
||||||
serializer.gb_hdd = 120
|
|
||||||
print("F")
|
|
||||||
serializer.is_valid(raise_exception=True)
|
|
||||||
|
|
||||||
print(serializer)
|
|
||||||
print("A")
|
|
||||||
serializer.save()
|
|
||||||
print("B")
|
|
||||||
|
|
||||||
|
|
||||||
# snapshot = VMSnapshotProduct(owner=request.user,
|
|
||||||
# **serialzer.data)
|
|
||||||
|
|
||||||
return Response(serializer.data)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# maybe drop or not --- we need something to guide the user!
|
# maybe drop or not --- we need something to guide the user!
|
||||||
# class ProductsViewSet(viewsets.ViewSet):
|
# class ProductsViewSet(viewsets.ViewSet):
|
||||||
|
@ -91,4 +51,4 @@ class UserViewSet(viewsets.ModelViewSet):
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
permission_classes = [permissions.IsAuthenticated]
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return self.request.user
|
return self.request.user
|
|
@ -89,3 +89,31 @@ class Payment(models.Model):
|
||||||
),
|
),
|
||||||
default='unknown')
|
default='unknown')
|
||||||
timestamp = models.DateTimeField(editable=False)
|
timestamp = models.DateTimeField(editable=False)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Product(models.Model):
|
||||||
|
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||||
|
owner = models.ForeignKey(get_user_model(),
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
editable=False)
|
||||||
|
|
||||||
|
description = ""
|
||||||
|
|
||||||
|
status = models.CharField(max_length=256,
|
||||||
|
choices = (
|
||||||
|
('pending', 'Pending'),
|
||||||
|
('being_created', 'Being created'),
|
||||||
|
('active', 'Active'),
|
||||||
|
('deleted', 'Deleted')
|
||||||
|
),
|
||||||
|
default='pending'
|
||||||
|
)
|
||||||
|
|
||||||
|
order = models.ForeignKey(Order,
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
editable=False)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
|
@ -2,6 +2,8 @@ from django.db import models
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
from uncloud_pay.models import Product
|
||||||
|
|
||||||
|
|
||||||
class VMHost(models.Model):
|
class VMHost(models.Model):
|
||||||
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||||
|
@ -71,3 +73,46 @@ class OperatingSystemDisk(VMDiskProduct):
|
||||||
class VMNetworkCard(models.Model):
|
class VMNetworkCard(models.Model):
|
||||||
vm = models.ForeignKey(VMProduct, on_delete=models.CASCADE)
|
vm = models.ForeignKey(VMProduct, on_delete=models.CASCADE)
|
||||||
mac_address = models.IntegerField()
|
mac_address = models.IntegerField()
|
||||||
|
|
||||||
|
|
||||||
|
class VMSnapshotProduct(Product):
|
||||||
|
price_per_gb_ssd = 0.35
|
||||||
|
price_per_gb_hdd = 1.5/100
|
||||||
|
|
||||||
|
# This we need to get from the VM
|
||||||
|
gb_ssd = models.FloatField(editable=False)
|
||||||
|
gb_hdd = models.FloatField(editable=False)
|
||||||
|
|
||||||
|
vm_uuid = models.UUIDField()
|
||||||
|
|
||||||
|
# Need to setup recurring_price and one_time_price and recurring period
|
||||||
|
|
||||||
|
sample_ssd = 10
|
||||||
|
sample_hdd = 100
|
||||||
|
|
||||||
|
def recurring_price(self):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def one_time_price(self):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def sample_price(cls):
|
||||||
|
return cls.sample_ssd * cls.price_per_gb_ssd + cls.sample_hdd * cls.price_per_gb_hdd
|
||||||
|
|
||||||
|
description = "Create snapshot of a VM"
|
||||||
|
recurring_period = "monthly"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def pricing_model(cls):
|
||||||
|
return """
|
||||||
|
Pricing is on monthly basis and storage prices are equivalent to the storage
|
||||||
|
price in the VM.
|
||||||
|
|
||||||
|
Price per GB SSD is: {}
|
||||||
|
Price per GB HDD is: {}
|
||||||
|
|
||||||
|
|
||||||
|
Sample price for a VM with {} GB SSD and {} GB HDD VM is: {}.
|
||||||
|
""".format(cls.price_per_gb_ssd, cls.price_per_gb_hdd,
|
||||||
|
cls.sample_ssd, cls.sample_hdd, cls.sample_price())
|
||||||
|
|
|
@ -13,3 +13,13 @@ class VMProductSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VMProduct
|
model = VMProduct
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
|
class VMSnapshotProductSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = VMSnapshotProduct
|
||||||
|
fields = ['uuid', 'status', 'recurring_price', 'one_time_price' ]
|
||||||
|
|
||||||
|
class VMSnapshotProductCreateSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = VMSnapshotProduct
|
||||||
|
fields = '__all__'
|
||||||
|
|
|
@ -27,3 +27,53 @@ class VMProductViewSet(viewsets.ModelViewSet):
|
||||||
serializer.save(owner=request.user)
|
serializer.save(owner=request.user)
|
||||||
|
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
|
|
||||||
|
|
||||||
|
class VMSnapshotProductViewSet(viewsets.ModelViewSet):
|
||||||
|
permission_classes = [permissions.IsAuthenticated]
|
||||||
|
serializer_class = VMSnapshotProductSerializer
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return VMSnapshotProduct.objects.filter(owner=self.request.user)
|
||||||
|
|
||||||
|
def create(self, request):
|
||||||
|
serializer = VMProductSerializer(data=request.data, context={'request': request})
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
serializer.save(owner=request.user)
|
||||||
|
|
||||||
|
return Response(serializer.data)
|
||||||
|
|
||||||
|
|
||||||
|
class VMSnapshotProductView(viewsets.ViewSet):
|
||||||
|
permission_classes = [permissions.IsAuthenticated]
|
||||||
|
|
||||||
|
def list(self, request):
|
||||||
|
queryset = VMSnapshotProduct.objects.filter(owner=request.user)
|
||||||
|
serializer = VMSnapshotSerializer(queryset, many=True, context={'request': request})
|
||||||
|
return Response(serializer.data)
|
||||||
|
|
||||||
|
def retrieve(self, request, pk=None):
|
||||||
|
queryset = VMSnapshotProduct.objects.filter(owner=request.user)
|
||||||
|
vm = get_object_or_404(queryset, pk=pk)
|
||||||
|
serializer = VMSnapshotSerializer(vm, context={'request': request})
|
||||||
|
return Response(serializer.data)
|
||||||
|
|
||||||
|
def create(self, request):
|
||||||
|
print(request.data)
|
||||||
|
serializer = VMSnapshotCreateSerializer(data=request.data)
|
||||||
|
|
||||||
|
serializer.gb_ssd = 12
|
||||||
|
serializer.gb_hdd = 120
|
||||||
|
print("F")
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
|
||||||
|
print(serializer)
|
||||||
|
print("A")
|
||||||
|
serializer.save()
|
||||||
|
print("B")
|
||||||
|
|
||||||
|
|
||||||
|
# snapshot = VMSnapshotProduct(owner=request.user,
|
||||||
|
# **serialzer.data)
|
||||||
|
|
||||||
|
return Response(serializer.data)
|
||||||
|
|
Loading…
Reference in a new issue