From caf7f7a2c2d2522940b8d30d9d2b5dab505ba248 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Sun, 19 Apr 2020 14:54:28 +0200 Subject: [PATCH 001/174] Move pay views under /user/username/{bill, address, order, ...} --- uncloud_django_based/uncloud/requirements.txt | 2 + uncloud_django_based/uncloud/uncloud/urls.py | 23 +++---- .../uncloud/uncloud_auth/helpers.py | 24 +++++++ .../uncloud/uncloud_auth/models.py | 1 + .../uncloud/uncloud_auth/serializers.py | 37 ++++++++++- .../uncloud/uncloud_auth/views.py | 19 ++++-- .../uncloud/uncloud_pay/views.py | 64 +++++++++---------- 7 files changed, 118 insertions(+), 52 deletions(-) create mode 100644 uncloud_django_based/uncloud/uncloud_auth/helpers.py diff --git a/uncloud_django_based/uncloud/requirements.txt b/uncloud_django_based/uncloud/requirements.txt index a7fc9f2..8de6786 100644 --- a/uncloud_django_based/uncloud/requirements.txt +++ b/uncloud_django_based/uncloud/requirements.txt @@ -22,3 +22,5 @@ uritemplate # Comprehensive interface to validate VAT numbers, making use of the VIES # service for European countries. vat-validator + +drf-nested-routers diff --git a/uncloud_django_based/uncloud/uncloud/urls.py b/uncloud_django_based/uncloud/uncloud/urls.py index 4d0ada1..64edd47 100644 --- a/uncloud_django_based/uncloud/uncloud/urls.py +++ b/uncloud_django_based/uncloud/uncloud/urls.py @@ -19,7 +19,7 @@ from django.urls import path, include from django.conf import settings from django.conf.urls.static import static -from rest_framework import routers +from rest_framework_nested import routers from rest_framework.schemas import get_schema_view from opennebula import views as oneviews @@ -51,15 +51,6 @@ router.register(r'service/generic', serviceviews.GenericServiceProductViewSet, b router.register(r'net/vpn', netviews.VPNNetworkViewSet, basename='vpnnet') router.register(r'net/vpnreservation', netviews.VPNNetworkReservationViewSet, basename='vpnnetreservation') - -# Pay -router.register(r'address', payviews.BillingAddressViewSet, basename='address') -router.register(r'bill', payviews.BillViewSet, basename='bill') -router.register(r'order', payviews.OrderViewSet, basename='order') -router.register(r'payment', payviews.PaymentViewSet, basename='payment') -router.register(r'payment-method', payviews.PaymentMethodViewSet, basename='payment-method') - - # admin/staff urls router.register(r'admin/bill', payviews.AdminBillViewSet, basename='admin/bill') router.register(r'admin/payment', payviews.AdminPaymentViewSet, basename='admin/payment') @@ -70,11 +61,21 @@ router.register(r'admin/vpnpool', netviews.VPNPoolViewSet) router.register(r'admin/opennebula', oneviews.VMViewSet, basename='opennebula') # User/Account +router.register(r'self', authviews.SelfViewSet, basename='self') router.register(r'user', authviews.UserViewSet, basename='user') -router.register(r'admin/user', authviews.AdminUserViewSet, basename='useradmin') + +users_router = routers.NestedSimpleRouter(router, r'user', lookup='user') +users_router.register(r'bill', payviews.BillViewSet, basename='user-bill') +users_router.register(r'address', payviews.BillingAddressViewSet, basename='user-address') +users_router.register(r'order', payviews.OrderViewSet, basename='user-order') +users_router.register(r'payment', payviews.PaymentViewSet, basename='user-payment') +users_router.register(r'payment-method', payviews.PaymentMethodViewSet, basename='user-payment-method') + + urlpatterns = [ path('', include(router.urls)), + path('', include(users_router.urls)), # web/ = stuff to view in the browser path('web/pdf/', payviews.MyPDFView.as_view(), name='pdf'), diff --git a/uncloud_django_based/uncloud/uncloud_auth/helpers.py b/uncloud_django_based/uncloud/uncloud_auth/helpers.py new file mode 100644 index 0000000..67cfc0a --- /dev/null +++ b/uncloud_django_based/uncloud/uncloud_auth/helpers.py @@ -0,0 +1,24 @@ +from rest_framework import permissions +from django.contrib.auth import get_user_model + +class IsOwnerOrAdmin(permissions.BasePermission): + """ + Object-level permission to only allow owner or admin to edit an object. + Assumes the model instance has an `owner` attribute. + """ + + def has_permission(self, request, view): + if request.user.is_staff: + return True + + try: + target_user = get_user_model().objects.get( + username=view.kwargs['user_pk']) + return target_user == request.user + except: + return False + + def has_object_permission(self, request, view, obj): + return (obj.owner == request.user) or request.user.is_staff + + diff --git a/uncloud_django_based/uncloud/uncloud_auth/models.py b/uncloud_django_based/uncloud/uncloud_auth/models.py index c3a0912..fbb8f22 100644 --- a/uncloud_django_based/uncloud/uncloud_auth/models.py +++ b/uncloud_django_based/uncloud/uncloud_auth/models.py @@ -1,6 +1,7 @@ from django.contrib.auth.models import AbstractUser from django.db import models from django.core.validators import MinValueValidator +from rest_framework.reverse import reverse from uncloud import AMOUNT_DECIMALS, AMOUNT_MAX_DIGITS diff --git a/uncloud_django_based/uncloud/uncloud_auth/serializers.py b/uncloud_django_based/uncloud/uncloud_auth/serializers.py index 71aeb03..14c90a9 100644 --- a/uncloud_django_based/uncloud/uncloud_auth/serializers.py +++ b/uncloud_django_based/uncloud/uncloud_auth/serializers.py @@ -1,16 +1,49 @@ from django.contrib.auth import get_user_model from rest_framework import serializers +from rest_framework_nested.relations import NestedHyperlinkedRelatedField from uncloud import AMOUNT_DECIMALS, AMOUNT_MAX_DIGITS -class UserSerializer(serializers.ModelSerializer): +class UserSerializer(serializers.HyperlinkedModelSerializer): balance = serializers.DecimalField(max_digits=AMOUNT_MAX_DIGITS, decimal_places=AMOUNT_DECIMALS) + bill_endpoint = serializers.HyperlinkedIdentityField( + view_name='user-bill-list', + lookup_field='username', + lookup_url_kwarg='user_pk' + ) + + order_endpoint = serializers.HyperlinkedIdentityField( + view_name='user-order-list', + lookup_field='username', + lookup_url_kwarg='user_pk' + ) + + address_endpoint = serializers.HyperlinkedIdentityField( + view_name='user-address-list', + lookup_field='username', + lookup_url_kwarg='user_pk' + ) + + payment_method_endpoint = serializers.HyperlinkedIdentityField( + view_name='user-payment-method-list', + lookup_field='username', + lookup_url_kwarg='user_pk' + ) + + payment_endpoint = serializers.HyperlinkedIdentityField( + view_name='user-payment-list', + lookup_field='username', + lookup_url_kwarg='user_pk' + ) + class Meta: model = get_user_model() - fields = ['username', 'email', 'balance', 'maximum_credit' ] + fields = ['username', 'email', 'balance', 'maximum_credit', + 'bill_endpoint', 'order_endpoint', 'address_endpoint', + 'payment_method_endpoint', 'payment_endpoint'] class ImportUserSerializer(serializers.Serializer): username = serializers.CharField() diff --git a/uncloud_django_based/uncloud/uncloud_auth/views.py b/uncloud_django_based/uncloud/uncloud_auth/views.py index 9c5bd1f..6b2800d 100644 --- a/uncloud_django_based/uncloud/uncloud_auth/views.py +++ b/uncloud_django_based/uncloud/uncloud_auth/views.py @@ -3,9 +3,11 @@ from .serializers import * from django_auth_ldap.backend import LDAPBackend from rest_framework.decorators import action from rest_framework.response import Response +from rest_framework.generics import get_object_or_404 from rest_framework import mixins +from .models import * -class UserViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): +class SelfViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): permission_classes = [permissions.IsAuthenticated] serializer_class = UserSerializer @@ -18,9 +20,8 @@ class UserViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): serializer = self.get_serializer(user, context = {'request': request}) return Response(serializer.data) -class AdminUserViewSet(viewsets.ReadOnlyModelViewSet): - # FIXME: make this admin - permission_classes = [permissions.IsAuthenticated] +class UserViewSet(viewsets.ReadOnlyModelViewSet): + permission_classes = [permissions.IsAdminUser] def get_serializer_class(self): if self.action == 'import_from_ldap': @@ -29,7 +30,15 @@ class AdminUserViewSet(viewsets.ReadOnlyModelViewSet): return UserSerializer def get_queryset(self): - return get_user_model().objects.all() + return User.objects.all() + + # Override default implementation to search by username instead of ID. + def retrieve(self, request, pk): + queryset = self.filter_queryset(self.get_queryset()) + instance = get_object_or_404(queryset, username=pk) + serializer = self.get_serializer(instance) + + return Response(serializer.data) @action(detail=False, methods=['post'], url_path='import_from_ldap') def import_from_ldap(self, request, pk=None): diff --git a/uncloud_django_based/uncloud/uncloud_pay/views.py b/uncloud_django_based/uncloud/uncloud_pay/views.py index aaf90e2..a4d4387 100644 --- a/uncloud_django_based/uncloud/uncloud_pay/views.py +++ b/uncloud_django_based/uncloud/uncloud_pay/views.py @@ -18,28 +18,25 @@ from .serializers import * from datetime import datetime from vat_validator import sanitize_vat import uncloud_pay.stripe as uncloud_stripe +from uncloud_auth.helpers import IsOwnerOrAdmin logger = logging.getLogger(__name__) +# FIXME: user resolution from user_pk field might fail if queried for +# non-existing username by an admin. It should return 404 instead. + ### # Payments and Payment Methods. class PaymentViewSet(viewsets.ReadOnlyModelViewSet): serializer_class = PaymentSerializer - permission_classes = [permissions.IsAuthenticated] + permission_classes = [permissions.IsAuthenticated, IsOwnerOrAdmin] def get_queryset(self): - return Payment.objects.filter(owner=self.request.user) - -class OrderViewSet(viewsets.ReadOnlyModelViewSet): - serializer_class = OrderSerializer - permission_classes = [permissions.IsAuthenticated] - - def get_queryset(self): - return Order.objects.filter(owner=self.request.user) + return Payment.objects.filter(owner__username=self.kwargs['user_pk']) class PaymentMethodViewSet(viewsets.ModelViewSet): - permission_classes = [permissions.IsAuthenticated] + permission_classes = [permissions.IsAuthenticated, IsOwnerOrAdmin] def get_serializer_class(self): if self.action == 'create': @@ -52,21 +49,22 @@ class PaymentMethodViewSet(viewsets.ModelViewSet): return PaymentMethodSerializer def get_queryset(self): - return PaymentMethod.objects.filter(owner=self.request.user) + return PaymentMethod.objects.filter(owner__username=self.kwargs['user_pk']) # XXX: Handling of errors is far from great down there. @transaction.atomic - def create(self, request): + def create(self, request, user_pk): + user = get_user_model().objects.get(user_pk) serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) # Set newly created method as primary if no other method is. - if PaymentMethod.get_primary_for(request.user) == None: + if PaymentMethod.get_primary_for(user) == None: serializer.validated_data['primary'] = True if serializer.validated_data['source'] == "stripe": # Retrieve Stripe customer ID for user. - customer_id = uncloud_stripe.get_customer_id_for(request.user) + customer_id = uncloud_stripe.get_customer_id_for(user) if customer_id == None: return Response( {'error': 'Could not resolve customer stripe ID.'}, @@ -79,7 +77,7 @@ class PaymentMethodViewSet(viewsets.ModelViewSet): status=status.HTTP_500_INTERNAL_SERVER_ERROR) payment_method = PaymentMethod.objects.create( - owner=request.user, + owner=user, stripe_setup_intent_id=setup_intent.id, **serializer.validated_data) @@ -90,11 +88,11 @@ class PaymentMethodViewSet(viewsets.ModelViewSet): stripe_registration_url = reverse('api-root', request=request) + path return Response({'please_visit': stripe_registration_url}) else: - serializer.save(owner=request.user, **serializer.validated_data) + serializer.save(owner=user, **serializer.validated_data) return Response(serializer.data) @action(detail=True, methods=['post']) - def charge(self, request, pk=None): + def charge(self, request, pk=None, user_pk=None): payment_method = self.get_object() serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) @@ -107,7 +105,7 @@ class PaymentMethodViewSet(viewsets.ModelViewSet): return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) @action(detail=True, methods=['get'], url_path='register-stripe-cc', renderer_classes=[TemplateHTMLRenderer]) - def register_stripe_cc(self, request, pk=None): + def register_stripe_cc(self, request, pk=None, user_pk=None): payment_method = self.get_object() if payment_method.source != 'stripe': @@ -143,7 +141,7 @@ class PaymentMethodViewSet(viewsets.ModelViewSet): return Response(template_args, template_name='stripe-payment.html.j2') @action(detail=True, methods=['post'], url_path='activate-stripe-cc') - def activate_stripe_cc(self, request, pk=None): + def activate_stripe_cc(self, request, pk=None, user_pk=None): payment_method = self.get_object() try: setup_intent = uncloud_stripe.get_setup_intent( @@ -165,9 +163,10 @@ class PaymentMethodViewSet(viewsets.ModelViewSet): return Response({'error': error}) @action(detail=True, methods=['post'], url_path='set-as-primary') - def set_as_primary(self, request, pk=None): + def set_as_primary(self, request, pk=None, user_pk=None): + user = get_user_model().objects.get(user_pk) payment_method = self.get_object() - payment_method.set_as_primary_for(request.user) + payment_method.set_as_primary_for(user) serializer = self.get_serializer(payment_method) return Response(serializer.data) @@ -177,28 +176,24 @@ class PaymentMethodViewSet(viewsets.ModelViewSet): class BillViewSet(viewsets.ReadOnlyModelViewSet): serializer_class = BillSerializer - permission_classes = [permissions.IsAuthenticated] + permission_classes = [permissions.IsAuthenticated, IsOwnerOrAdmin] def get_queryset(self): - return Bill.objects.filter(owner=self.request.user) - - def unpaid(self, request): - return Bill.objects.filter(owner=self.request.user, paid=False) - + return Bill.objects.filter(owner__username=self.kwargs['user_pk']) class OrderViewSet(viewsets.ReadOnlyModelViewSet): serializer_class = OrderSerializer - permission_classes = [permissions.IsAuthenticated] + permission_classes = [permissions.IsAuthenticated, IsOwnerOrAdmin] def get_queryset(self): - return Order.objects.filter(owner=self.request.user) + return Order.objects.filter(owner__username=self.kwargs['user_pk']) class BillingAddressViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet): - permission_classes = [permissions.IsAuthenticated] + permission_classes = [permissions.IsAuthenticated, IsOwnerOrAdmin] def get_serializer_class(self): if self.action == 'update': @@ -207,16 +202,17 @@ class BillingAddressViewSet(mixins.CreateModelMixin, return BillingAddressSerializer def get_queryset(self): - return self.request.user.billingaddress_set.all() + return BillingAddress.objects.filter(owner__username=self.kwargs['user_pk']) + + def create(self, request, user_pk): + user = get_user_model().objects.get(username=user_pk) - def create(self, request): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) # Validate VAT numbers. country = serializer.validated_data["country"] vat_number = serializer.validated_data["vat_number"] - # We ignore empty VAT numbers. if vat_number != "": if not validate_vat(country, vat_number): @@ -238,7 +234,7 @@ class BillingAddressViewSet(mixins.CreateModelMixin, status=status.HTTP_500_INTERNAL_SERVER_ERROR) - serializer.save(owner=request.user) + serializer.save(owner=user) return Response(serializer.data) ### From 1cf20a2cb6c84b2db79d2e45e49d5fbb81b392e7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 27 Apr 2020 18:25:27 +0200 Subject: [PATCH 002/174] Disable vat validator to get project back running --- uncloud_django_based/uncloud/uncloud_pay/views.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/uncloud_django_based/uncloud/uncloud_pay/views.py b/uncloud_django_based/uncloud/uncloud_pay/views.py index aaf90e2..82b5787 100644 --- a/uncloud_django_based/uncloud/uncloud_pay/views.py +++ b/uncloud_django_based/uncloud/uncloud_pay/views.py @@ -7,8 +7,8 @@ from rest_framework.response import Response from rest_framework.decorators import action from rest_framework.reverse import reverse from rest_framework.decorators import renderer_classes -from vat_validator import validate_vat, vies -from vat_validator.countries import EU_COUNTRY_CODES +#from vat_validator import validate_vat, vies +#from vat_validator.countries import EU_COUNTRY_CODES import json import logging @@ -16,7 +16,7 @@ import logging from .models import * from .serializers import * from datetime import datetime -from vat_validator import sanitize_vat +#from vat_validator import sanitize_vat import uncloud_pay.stripe as uncloud_stripe logger = logging.getLogger(__name__) From 62d9ccbbef06706dcb7467d693ba31d732c882a7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 27 Apr 2020 18:25:44 +0200 Subject: [PATCH 003/174] [vpn] begin to introduce save() method The save() and delete() method will create/manage the orders --- uncloud_django_based/uncloud/uncloud_net/models.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/uncloud_django_based/uncloud/uncloud_net/models.py b/uncloud_django_based/uncloud/uncloud_net/models.py index 26a6eb8..8dfff05 100644 --- a/uncloud_django_based/uncloud/uncloud_net/models.py +++ b/uncloud_django_based/uncloud/uncloud_net/models.py @@ -173,11 +173,11 @@ class VPNNetwork(Product): wireguard_public_key = models.CharField(max_length=48) + def save(self, *args, **kwargs): + super().save(*args, **kwargs) + def delete(self, *args, **kwargs): self.network.status = 'free' self.network.save() super().save(*args, **kwargs) print("deleted {}".format(self)) - -# managing deletion -# - record free network (?) From 2cda6441f41776d4605bf141b97c67b4baa767a7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 2 May 2020 00:16:29 +0200 Subject: [PATCH 004/174] Refactor secret / local settings handling --- .../uncloud/uncloud/secrets_sample.py | 21 ------ .../uncloud/uncloud/settings.py | 73 +++++++++++-------- .../uncloud/uncloud_net/models.py | 3 - .../uncloud/uncloud_pay/models.py | 15 +++- .../uncloud/uncloud_pay/stripe.py | 8 +- 5 files changed, 60 insertions(+), 60 deletions(-) delete mode 100644 uncloud_django_based/uncloud/uncloud/secrets_sample.py diff --git a/uncloud_django_based/uncloud/uncloud/secrets_sample.py b/uncloud_django_based/uncloud/uncloud/secrets_sample.py deleted file mode 100644 index 150fefb..0000000 --- a/uncloud_django_based/uncloud/uncloud/secrets_sample.py +++ /dev/null @@ -1,21 +0,0 @@ -from django.core.management.utils import get_random_secret_key - -# XML-RPC interface of opennebula -OPENNEBULA_URL = 'https://opennebula.ungleich.ch:2634/RPC2' - -# user:pass for accessing opennebula -OPENNEBULA_USER_PASS = 'user:password' - -POSTGRESQL_DB_NAME="uncloud" - -# See https://django-auth-ldap.readthedocs.io/en/latest/authentication.html -LDAP_ADMIN_DN="" -LDAP_ADMIN_PASSWORD="" -LDAP_SERVER_URI = "" - -# Stripe (Credit Card payments) -STRIPE_KEY="" -STRIPE_PUBLIC_KEY="" - -# The django secret key -SECRET_KEY=get_random_secret_key() diff --git a/uncloud_django_based/uncloud/uncloud/settings.py b/uncloud_django_based/uncloud/uncloud/settings.py index b525073..527749d 100644 --- a/uncloud_django_based/uncloud/uncloud/settings.py +++ b/uncloud_django_based/uncloud/uncloud/settings.py @@ -13,41 +13,32 @@ https://docs.djangoproject.com/en/3.0/ref/settings/ import os import ldap -# Uncommitted file with secrets -import uncloud.secrets - +from django.core.management.utils import get_random_secret_key from django_auth_ldap.config import LDAPSearch, LDAPSearchUnion -# Uncommitted file with local settings i.e logging -try: - from uncloud.local_settings import LOGGING, DATABASES -except ModuleNotFoundError: - LOGGING = {} - # https://docs.djangoproject.com/en/3.0/ref/settings/#databases - DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.postgresql', - 'NAME': uncloud.secrets.POSTGRESQL_DB_NAME, - 'HOST': os.environ.get('DATABASE_HOST', '::1'), - 'USER': os.environ.get('DATABASE_USER', 'postgres'), - } - } + +LOGGING = {} + # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +# https://docs.djangoproject.com/en/3.0/ref/settings/#databases +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + } +} + # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/ -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = uncloud.secrets.SECRET_KEY - # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = [] # Application definition @@ -123,7 +114,12 @@ AUTH_PASSWORD_VALIDATORS = [ ################################################################################ # AUTH/LDAP -AUTH_LDAP_SERVER_URI = uncloud.secrets.LDAP_SERVER_URI +AUTH_LDAP_SERVER_URI = "" +AUTH_LDAP_BIND_DN = "" +AUTH_LDAP_BIND_PASSWORD = "" +AUTH_LDAP_USER_SEARCH = LDAPSearch("dc=example,dc=com", + ldap.SCOPE_SUBTREE, + "(uid=%(user)s)") AUTH_LDAP_USER_ATTR_MAP = { "first_name": "givenName", @@ -131,13 +127,6 @@ AUTH_LDAP_USER_ATTR_MAP = { "email": "mail" } - -AUTH_LDAP_BIND_DN = uncloud.secrets.LDAP_ADMIN_DN -AUTH_LDAP_BIND_PASSWORD = uncloud.secrets.LDAP_ADMIN_PASSWORD - -AUTH_LDAP_USER_SEARCH = LDAPSearch("dc=ungleich,dc=ch", ldap.SCOPE_SUBTREE, "(uid=%(user)s)") - - ################################################################################ # AUTH/Django AUTHENTICATION_BACKENDS = [ @@ -158,7 +147,6 @@ REST_FRAMEWORK = { } - # Internationalization # https://docs.djangoproject.com/en/3.0/topics/i18n/ @@ -177,3 +165,28 @@ USE_TZ = True # https://docs.djangoproject.com/en/3.0/howto/static-files/ STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, "static") ] + +# XML-RPC interface of opennebula +OPENNEBULA_URL = 'https://opennebula.example.com:2634/RPC2' + +# user:pass for accessing opennebula +OPENNEBULA_USER_PASS = 'user:password' + +# See https://django-auth-ldap.readthedocs.io/en/latest/authentication.html +LDAP_ADMIN_DN="" +LDAP_ADMIN_PASSWORD="" +LDAP_SERVER_URI = "" + +# Stripe (Credit Card payments) +STRIPE_KEY="" +STRIPE_PUBLIC_KEY="" + +# The django secret key +SECRET_KEY=get_random_secret_key() + + +# Overwrite settings with local settings, if existing +try: + from uncloud.local_settings import * +except (ModuleNotFoundError, ImportError): + pass diff --git a/uncloud_django_based/uncloud/uncloud_net/models.py b/uncloud_django_based/uncloud/uncloud_net/models.py index 8dfff05..e56b79c 100644 --- a/uncloud_django_based/uncloud/uncloud_net/models.py +++ b/uncloud_django_based/uncloud/uncloud_net/models.py @@ -173,9 +173,6 @@ class VPNNetwork(Product): wireguard_public_key = models.CharField(max_length=48) - def save(self, *args, **kwargs): - super().save(*args, **kwargs) - def delete(self, *args, **kwargs): self.network.status = 'free' self.network.save() diff --git a/uncloud_django_based/uncloud/uncloud_pay/models.py b/uncloud_django_based/uncloud/uncloud_pay/models.py index bcce598..55cf1ea 100644 --- a/uncloud_django_based/uncloud/uncloud_pay/models.py +++ b/uncloud_django_based/uncloud/uncloud_pay/models.py @@ -4,7 +4,7 @@ from django.contrib.auth import get_user_model from django.core.validators import MinValueValidator from django.utils.translation import gettext_lazy as _ from django.utils import timezone -from django.core.exceptions import ObjectDoesNotExist +from django.core.exceptions import ObjectDoesNotExist, ValidationError import uuid import logging @@ -811,7 +811,7 @@ class Order(models.Model): # TODO: enforce ending_date - starting_date to be larger than recurring_period. creation_date = models.DateTimeField(auto_now_add=True) - starting_date = models.DateTimeField() + starting_date = models.DateTimeField(default=timezone.now) ending_date = models.DateTimeField(blank=True, null=True) @@ -918,6 +918,17 @@ class Product(UncloudModel): # _state.adding is switched to false after super(...) call. being_created = self._state.adding + # First time saving - create an order + if not self.order: + billing_address = BillingAddress.get_preferred_address_for(self.owner) + + if not billing_address: + raise ValidationError("Cannot create order without a billing address") + + self.order = Order(owner=self.owner, + billing_address=billing_address) + + super(Product, self).save(*args, **kwargs) # Make sure we only create records on creation. diff --git a/uncloud_django_based/uncloud/uncloud_pay/stripe.py b/uncloud_django_based/uncloud/uncloud_pay/stripe.py index f23002b..2ed4ef2 100644 --- a/uncloud_django_based/uncloud/uncloud_pay/stripe.py +++ b/uncloud_django_based/uncloud/uncloud_pay/stripe.py @@ -3,9 +3,9 @@ import stripe.error import logging from django.core.exceptions import ObjectDoesNotExist -import uncloud_pay.models +from django.conf import settings -import uncloud.secrets +import uncloud_pay.models # Static stripe configuration used below. CURRENCY = 'chf' @@ -14,7 +14,7 @@ CURRENCY = 'chf' # https://stripe.com/docs/payments/save-and-reuse # For internal use only. -stripe.api_key = uncloud.secrets.STRIPE_KEY +stripe.api_key = settings.STRIPE_KEY # Helper (decorator) used to catch errors raised by stripe logic. # Catch errors that should not be displayed to the end user, raise again. @@ -64,7 +64,7 @@ def handle_stripe_error(f): # Actual Stripe logic. def public_api_key(): - return uncloud.secrets.STRIPE_PUBLIC_KEY + return settings.STRIPE_PUBLIC_KEY def get_customer_id_for(user): try: From eea654a9f8b71d8dabc112b0c31476878edc6167 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 2 May 2020 19:15:48 +0200 Subject: [PATCH 005/174] Phase in new beta/vm view for creating vms + orders + bills --- .../uncloud/uncloud/settings.py | 5 +-- uncloud_django_based/uncloud/uncloud/urls.py | 4 ++ .../uncloud/uncloud_vm/models.py | 1 + .../uncloud/uncloud_vm/serializers.py | 19 +++++++++ .../uncloud/uncloud_vm/views.py | 40 +++++++++++++++++++ 5 files changed, 65 insertions(+), 4 deletions(-) diff --git a/uncloud_django_based/uncloud/uncloud/settings.py b/uncloud_django_based/uncloud/uncloud/settings.py index 527749d..884c370 100644 --- a/uncloud_django_based/uncloud/uncloud/settings.py +++ b/uncloud_django_based/uncloud/uncloud/settings.py @@ -172,10 +172,6 @@ OPENNEBULA_URL = 'https://opennebula.example.com:2634/RPC2' # user:pass for accessing opennebula OPENNEBULA_USER_PASS = 'user:password' -# See https://django-auth-ldap.readthedocs.io/en/latest/authentication.html -LDAP_ADMIN_DN="" -LDAP_ADMIN_PASSWORD="" -LDAP_SERVER_URI = "" # Stripe (Credit Card payments) STRIPE_KEY="" @@ -184,6 +180,7 @@ STRIPE_PUBLIC_KEY="" # The django secret key SECRET_KEY=get_random_secret_key() +ALLOWED_HOSTS = [] # Overwrite settings with local settings, if existing try: diff --git a/uncloud_django_based/uncloud/uncloud/urls.py b/uncloud_django_based/uncloud/uncloud/urls.py index 4d0ada1..5539846 100644 --- a/uncloud_django_based/uncloud/uncloud/urls.py +++ b/uncloud_django_based/uncloud/uncloud/urls.py @@ -31,12 +31,16 @@ from uncloud_service import views as serviceviews router = routers.DefaultRouter() +# Beta endpoints +router.register(r'beta/vm', vmviews.NicoVMProductViewSet, basename='nicovmproduct') + # VM router.register(r'vm/snapshot', vmviews.VMSnapshotProductViewSet, basename='vmsnapshotproduct') router.register(r'vm/diskimage', vmviews.VMDiskImageProductViewSet, basename='vmdiskimageproduct') router.register(r'vm/disk', vmviews.VMDiskProductViewSet, basename='vmdiskproduct') router.register(r'vm/vm', vmviews.VMProductViewSet, basename='vmproduct') + # creates VM from os image #router.register(r'vm/ipv6onlyvm', vmviews.VMProductViewSet, basename='vmproduct') # ... AND adds IPv4 mapping diff --git a/uncloud_django_based/uncloud/uncloud_vm/models.py b/uncloud_django_based/uncloud/uncloud_vm/models.py index 5dacdbe..39a5f40 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() + # Optional disk primary_disk = models.ForeignKey('VMDiskProduct', on_delete=models.CASCADE, null=True) # Default recurring price is PER_MONTH, see uncloud_pay.models.Product. diff --git a/uncloud_django_based/uncloud/uncloud_vm/serializers.py b/uncloud_django_based/uncloud/uncloud_vm/serializers.py index 92c7fe8..2c7137e 100644 --- a/uncloud_django_based/uncloud/uncloud_vm/serializers.py +++ b/uncloud_django_based/uncloud/uncloud_vm/serializers.py @@ -120,6 +120,25 @@ class OrderVMProductSerializer(VMProductSerializer): # Nico's playground. +class NicoVMProductSerializer(serializers.ModelSerializer): + primary_disk = CreateVMDiskProductSerializer() + snapshots = VMSnapshotProductSerializer(many=True, read_only=True) + disks = VMDiskProductSerializer(many=True, read_only=True) + + class Meta: + model = VMProduct + read_only_fields = ['uuid', 'order', 'owner', 'status', + 'vmhost', 'vmcluster', + 'extra_data' ] + fields = read_only_fields + [ 'name', + 'cores', + 'ram_in_gb', + 'primary_disk', + 'snapshots', + 'disks' ] + + + class DCLVMProductSerializer(serializers.HyperlinkedModelSerializer): """ Create an interface similar to standard DCL diff --git a/uncloud_django_based/uncloud/uncloud_vm/views.py b/uncloud_django_based/uncloud/uncloud_vm/views.py index 1dead62..39b7668 100644 --- a/uncloud_django_based/uncloud/uncloud_vm/views.py +++ b/uncloud_django_based/uncloud/uncloud_vm/views.py @@ -179,6 +179,46 @@ class VMProductViewSet(ProductViewSet): return Response(VMProductSerializer(vm, context={'request': request}).data) +class NicoVMProductViewSet(ProductViewSet): + permission_classes = [permissions.IsAuthenticated] + serializer_class = NicoVMProductSerializer + + def get_queryset(self): + obj = VMProduct.objects.filter(owner=self.request.user) + + return obj + + # Use a database transaction so that we do not get half-created structure + # if something goes wrong. + @transaction.atomic + def create(self, request): + # Extract serializer data. + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + 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. + disk = VMDiskProduct(owner=request.user, order=order, + **serializer.validated_data.pop("primary_disk")) + + # Create VM. + vm = serializer.save(owner=request.user, order=order, primary_disk=disk) + disk.vm = vm + disk.save() + + return Response(VMProductSerializer(vm, context={'request': request}).data) + + ### # Admin stuff. From 927fb206712d92ec33d9969c159b951a9a7ec7ca Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 2 May 2020 20:31:36 +0200 Subject: [PATCH 006/174] Versionise API and cleanups --- uncloud_django_based/uncloud/uncloud/urls.py | 44 +++++++++---------- .../uncloud/uncloud_pay/models.py | 6 ++- .../uncloud/uncloud_vm/models.py | 4 +- .../uncloud/uncloud_vm/serializers.py | 11 ++--- .../uncloud/uncloud_vm/views.py | 1 + 5 files changed, 32 insertions(+), 34 deletions(-) diff --git a/uncloud_django_based/uncloud/uncloud/urls.py b/uncloud_django_based/uncloud/uncloud/urls.py index 5539846..05b1f0f 100644 --- a/uncloud_django_based/uncloud/uncloud/urls.py +++ b/uncloud_django_based/uncloud/uncloud/urls.py @@ -35,10 +35,10 @@ router = routers.DefaultRouter() router.register(r'beta/vm', vmviews.NicoVMProductViewSet, basename='nicovmproduct') # VM -router.register(r'vm/snapshot', vmviews.VMSnapshotProductViewSet, basename='vmsnapshotproduct') -router.register(r'vm/diskimage', vmviews.VMDiskImageProductViewSet, basename='vmdiskimageproduct') -router.register(r'vm/disk', vmviews.VMDiskProductViewSet, basename='vmdiskproduct') -router.register(r'vm/vm', vmviews.VMProductViewSet, basename='vmproduct') +router.register(r'v1/vm/snapshot', vmviews.VMSnapshotProductViewSet, basename='vmsnapshotproduct') +router.register(r'v1/vm/diskimage', vmviews.VMDiskImageProductViewSet, basename='vmdiskimageproduct') +router.register(r'v1/vm/disk', vmviews.VMDiskProductViewSet, basename='vmdiskproduct') +router.register(r'v1/vm/vm', vmviews.VMProductViewSet, basename='vmproduct') # creates VM from os image @@ -47,35 +47,35 @@ router.register(r'vm/vm', vmviews.VMProductViewSet, basename='vmproduct') #router.register(r'vm/dualstackvm', vmviews.VMProductViewSet, basename='vmproduct') # Services -router.register(r'service/matrix', serviceviews.MatrixServiceProductViewSet, basename='matrixserviceproduct') -router.register(r'service/generic', serviceviews.GenericServiceProductViewSet, basename='genericserviceproduct') +router.register(r'v1/service/matrix', serviceviews.MatrixServiceProductViewSet, basename='matrixserviceproduct') +router.register(r'v1/service/generic', serviceviews.GenericServiceProductViewSet, basename='genericserviceproduct') # Net -router.register(r'net/vpn', netviews.VPNNetworkViewSet, basename='vpnnet') -router.register(r'net/vpnreservation', netviews.VPNNetworkReservationViewSet, basename='vpnnetreservation') +router.register(r'v1/net/vpn', netviews.VPNNetworkViewSet, basename='vpnnet') +router.register(r'v1/admin/vpnreservation', netviews.VPNNetworkReservationViewSet, basename='vpnnetreservation') # Pay -router.register(r'address', payviews.BillingAddressViewSet, basename='address') -router.register(r'bill', payviews.BillViewSet, basename='bill') -router.register(r'order', payviews.OrderViewSet, basename='order') -router.register(r'payment', payviews.PaymentViewSet, basename='payment') -router.register(r'payment-method', payviews.PaymentMethodViewSet, basename='payment-method') +router.register(r'v1/my/address', payviews.BillingAddressViewSet, basename='address') +router.register(r'v1/my/bill', payviews.BillViewSet, basename='bill') +router.register(r'v1/my/order', payviews.OrderViewSet, basename='order') +router.register(r'v1/my/payment', payviews.PaymentViewSet, basename='payment') +router.register(r'v1/my/payment-method', payviews.PaymentMethodViewSet, basename='payment-method') # admin/staff urls -router.register(r'admin/bill', payviews.AdminBillViewSet, basename='admin/bill') -router.register(r'admin/payment', payviews.AdminPaymentViewSet, basename='admin/payment') -router.register(r'admin/order', payviews.AdminOrderViewSet, basename='admin/order') -router.register(r'admin/vmhost', vmviews.VMHostViewSet) -router.register(r'admin/vmcluster', vmviews.VMClusterViewSet) -router.register(r'admin/vpnpool', netviews.VPNPoolViewSet) -router.register(r'admin/opennebula', oneviews.VMViewSet, basename='opennebula') +router.register(r'v1/admin/bill', payviews.AdminBillViewSet, basename='admin/bill') +router.register(r'v1/admin/payment', payviews.AdminPaymentViewSet, basename='admin/payment') +router.register(r'v1/admin/order', payviews.AdminOrderViewSet, basename='admin/order') +router.register(r'v1/admin/vmhost', vmviews.VMHostViewSet) +router.register(r'v1/admin/vmcluster', vmviews.VMClusterViewSet) +router.register(r'v1/admin/vpnpool', netviews.VPNPoolViewSet) +router.register(r'v1/admin/opennebula', oneviews.VMViewSet, basename='opennebula') # User/Account -router.register(r'user', authviews.UserViewSet, basename='user') -router.register(r'admin/user', authviews.AdminUserViewSet, basename='useradmin') +router.register(r'v1/my/user', authviews.UserViewSet, basename='user') +router.register(r'v1/admin/user', authviews.AdminUserViewSet, basename='useradmin') urlpatterns = [ path('', include(router.urls)), diff --git a/uncloud_django_based/uncloud/uncloud_pay/models.py b/uncloud_django_based/uncloud/uncloud_pay/models.py index 55cf1ea..b06473e 100644 --- a/uncloud_django_based/uncloud/uncloud_pay/models.py +++ b/uncloud_django_based/uncloud/uncloud_pay/models.py @@ -825,7 +825,11 @@ class Order(models.Model): # Trigger initial bill generation at order creation. def save(self, *args, **kwargs): - super(Order, self).save(*args, **kwargs) + if self.ending_date and self.ending_date < self.starting_date: + raise ValidationError("End date cannot be before starting date") + + super().save(*args, **kwargs) + Bill.generate_for(self.starting_date.year, self.starting_date.month, self.owner) @property diff --git a/uncloud_django_based/uncloud/uncloud_vm/models.py b/uncloud_django_based/uncloud/uncloud_vm/models.py index 39a5f40..06b5386 100644 --- a/uncloud_django_based/uncloud/uncloud_vm/models.py +++ b/uncloud_django_based/uncloud/uncloud_vm/models.py @@ -69,9 +69,6 @@ class VMProduct(Product): cores = models.IntegerField() ram_in_gb = models.FloatField() - # Optional disk - primary_disk = models.ForeignKey('VMDiskProduct', on_delete=models.CASCADE, null=True) - # Default recurring price is PER_MONTH, see uncloud_pay.models.Product. @property def recurring_price(self): @@ -175,6 +172,7 @@ class VMDiskProduct(Product): super().save(*args, **kwargs) + class VMNetworkCard(models.Model): vm = models.ForeignKey(VMProduct, on_delete=models.CASCADE) diff --git a/uncloud_django_based/uncloud/uncloud_vm/serializers.py b/uncloud_django_based/uncloud/uncloud_vm/serializers.py index 2c7137e..a04af8f 100644 --- a/uncloud_django_based/uncloud/uncloud_vm/serializers.py +++ b/uncloud_django_based/uncloud/uncloud_vm/serializers.py @@ -121,22 +121,17 @@ class OrderVMProductSerializer(VMProductSerializer): # Nico's playground. class NicoVMProductSerializer(serializers.ModelSerializer): - primary_disk = CreateVMDiskProductSerializer() snapshots = VMSnapshotProductSerializer(many=True, read_only=True) - disks = VMDiskProductSerializer(many=True, read_only=True) class Meta: model = VMProduct read_only_fields = ['uuid', 'order', 'owner', 'status', - 'vmhost', 'vmcluster', + 'vmhost', 'vmcluster', 'snapshots', 'extra_data' ] fields = read_only_fields + [ 'name', 'cores', - 'ram_in_gb', - 'primary_disk', - 'snapshots', - 'disks' ] - + 'ram_in_gb' + ] class DCLVMProductSerializer(serializers.HyperlinkedModelSerializer): diff --git a/uncloud_django_based/uncloud/uncloud_vm/views.py b/uncloud_django_based/uncloud/uncloud_vm/views.py index 39b7668..2d0a693 100644 --- a/uncloud_django_based/uncloud/uncloud_vm/views.py +++ b/uncloud_django_based/uncloud/uncloud_vm/views.py @@ -195,6 +195,7 @@ class NicoVMProductViewSet(ProductViewSet): # Extract serializer data. serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) + order_recurring_period = serializer.validated_data.pop("recurring_period") order_billing_address = serializer.validated_data.pop("billing_address") From 7d708cfbb685c655fdaaf0672e9df6cebb5fbde9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 2 May 2020 20:42:09 +0200 Subject: [PATCH 007/174] Fix empty vat number bug --- uncloud_django_based/uncloud/uncloud_pay/views.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/uncloud_django_based/uncloud/uncloud_pay/views.py b/uncloud_django_based/uncloud/uncloud_pay/views.py index 82b5787..59d310e 100644 --- a/uncloud_django_based/uncloud/uncloud_pay/views.py +++ b/uncloud_django_based/uncloud/uncloud_pay/views.py @@ -215,10 +215,11 @@ class BillingAddressViewSet(mixins.CreateModelMixin, # Validate VAT numbers. country = serializer.validated_data["country"] - vat_number = serializer.validated_data["vat_number"] # We ignore empty VAT numbers. - if vat_number != "": + if 'vat_number' in serializer.validated_data and serializer.validated_data["vat_number"] != "": + vat_number = serializer.validated_data["vat_number"] + if not validate_vat(country, vat_number): return Response( {'error': 'Malformed VAT number.'}, From 736fe274935a33006d3eb84f21025872cf536155 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 2 May 2020 20:45:19 +0200 Subject: [PATCH 008/174] Add issues.org as a shortcut for registering issues --- issues.org | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 issues.org diff --git a/issues.org b/issues.org new file mode 100644 index 0000000..f79c1dc --- /dev/null +++ b/issues.org @@ -0,0 +1,5 @@ +* Intro + This file lists issues that should be handled, are small and likely + not yet high prio. +* Issues +** TODO Register prefered address in User model From 4097c2ce13bfe862a5312ff9952ae625a33c05b2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 2 May 2020 21:20:14 +0200 Subject: [PATCH 009/174] BillingAddress: make mget_preferred_address a classmethod --- uncloud_django_based/uncloud/uncloud_pay/models.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/uncloud_django_based/uncloud/uncloud_pay/models.py b/uncloud_django_based/uncloud/uncloud_pay/models.py index b06473e..3b4535c 100644 --- a/uncloud_django_based/uncloud/uncloud_pay/models.py +++ b/uncloud_django_based/uncloud/uncloud_pay/models.py @@ -455,9 +455,9 @@ class BillingAddress(models.Model): def get_addresses_for(user): return BillingAddress.objects.filter(owner=user) - @staticmethod - def get_preferred_address_for(user): - addresses = get_addresses_for(user) + @classmethod + def get_preferred_address_for(cls, user): + addresses = cls.get_addresses_for(user) if len(addresses) == 0: return None else: @@ -927,7 +927,7 @@ class Product(UncloudModel): billing_address = BillingAddress.get_preferred_address_for(self.owner) if not billing_address: - raise ValidationError("Cannot create order without a billing address") + raise ValidationError("Cannot order without a billing address") self.order = Order(owner=self.owner, billing_address=billing_address) From 9ef5309b91f2f60ae5dead5d02b9a95f83cda4d9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 2 May 2020 21:21:29 +0200 Subject: [PATCH 010/174] +db migrations for pay/vm Signed-off-by: Nico Schottelius --- .../migrations/0008_auto_20200502_1921.py | 19 +++++++++++++++++++ .../0013_remove_vmproduct_primary_disk.py | 17 +++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 uncloud_django_based/uncloud/uncloud_pay/migrations/0008_auto_20200502_1921.py create mode 100644 uncloud_django_based/uncloud/uncloud_vm/migrations/0013_remove_vmproduct_primary_disk.py diff --git a/uncloud_django_based/uncloud/uncloud_pay/migrations/0008_auto_20200502_1921.py b/uncloud_django_based/uncloud/uncloud_pay/migrations/0008_auto_20200502_1921.py new file mode 100644 index 0000000..c244357 --- /dev/null +++ b/uncloud_django_based/uncloud/uncloud_pay/migrations/0008_auto_20200502_1921.py @@ -0,0 +1,19 @@ +# Generated by Django 3.0.5 on 2020-05-02 19:21 + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('uncloud_pay', '0007_auto_20200418_0737'), + ] + + operations = [ + migrations.AlterField( + model_name='order', + name='starting_date', + field=models.DateTimeField(default=django.utils.timezone.now), + ), + ] diff --git a/uncloud_django_based/uncloud/uncloud_vm/migrations/0013_remove_vmproduct_primary_disk.py b/uncloud_django_based/uncloud/uncloud_vm/migrations/0013_remove_vmproduct_primary_disk.py new file mode 100644 index 0000000..849012d --- /dev/null +++ b/uncloud_django_based/uncloud/uncloud_vm/migrations/0013_remove_vmproduct_primary_disk.py @@ -0,0 +1,17 @@ +# Generated by Django 3.0.5 on 2020-05-02 19:21 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('uncloud_vm', '0012_auto_20200418_0641'), + ] + + operations = [ + migrations.RemoveField( + model_name='vmproduct', + name='primary_disk', + ), + ] From 028f1ebe6e3e80121e58fe1bf50ffb8535ba0e91 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 2 May 2020 22:03:34 +0200 Subject: [PATCH 011/174] Entry point /beta/vm/ works for creating VM + order --- issues.org | 1 + .../uncloud/uncloud_pay/models.py | 26 +++++++++------ .../uncloud/uncloud_vm/models.py | 6 ++++ .../uncloud/uncloud_vm/serializers.py | 1 + .../uncloud/uncloud_vm/views.py | 32 ++----------------- 5 files changed, 28 insertions(+), 38 deletions(-) diff --git a/issues.org b/issues.org index f79c1dc..840ec3c 100644 --- a/issues.org +++ b/issues.org @@ -3,3 +3,4 @@ not yet high prio. * Issues ** TODO Register prefered address in User model +** TODO Allow to specify different recurring periods diff --git a/uncloud_django_based/uncloud/uncloud_pay/models.py b/uncloud_django_based/uncloud/uncloud_pay/models.py index 3b4535c..a326810 100644 --- a/uncloud_django_based/uncloud/uncloud_pay/models.py +++ b/uncloud_django_based/uncloud/uncloud_pay/models.py @@ -855,6 +855,11 @@ class Order(models.Model): recurring_price=recurring_price, description=description) + def __str__(self): + return "Order {} created at {}, {}->{}, recurring period {}".format( + self.uuid, self.creation_date, + self.starting_date, self.ending_date, + self.recurring_period) class OrderRecord(models.Model): @@ -925,23 +930,26 @@ class Product(UncloudModel): # First time saving - create an order if not self.order: billing_address = BillingAddress.get_preferred_address_for(self.owner) + print(billing_address) if not billing_address: raise ValidationError("Cannot order without a billing address") - self.order = Order(owner=self.owner, + self.order = Order.objects.create(owner=self.owner, billing_address=billing_address) - super(Product, self).save(*args, **kwargs) + print("in save op: {}".format(self)) + print(self.order) + super().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, - description=self.description) - self.order.orderrecord_set.add(record, bulk=False) + # # 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, + # description=self.description) + # self.order.orderrecord_set.add(record, bulk=False) @property def recurring_price(self): diff --git a/uncloud_django_based/uncloud/uncloud_vm/models.py b/uncloud_django_based/uncloud/uncloud_vm/models.py index 06b5386..91c9291 100644 --- a/uncloud_django_based/uncloud/uncloud_vm/models.py +++ b/uncloud_django_based/uncloud/uncloud_vm/models.py @@ -91,6 +91,12 @@ class VMProduct(Product): RecurringPeriod.PER_MONTH, RecurringPeriod.PER_HOUR], RecurringPeriod.choices)) + def __str__(self): + return "VM {} ({} Cores/{} GB RAM) running on {} in cluster {}".format( + self.uuid, self.cores, self.ram_in_gb, + self.vmhost, self.vmcluster) + + class VMWithOSProduct(VMProduct): pass diff --git a/uncloud_django_based/uncloud/uncloud_vm/serializers.py b/uncloud_django_based/uncloud/uncloud_vm/serializers.py index a04af8f..701b187 100644 --- a/uncloud_django_based/uncloud/uncloud_vm/serializers.py +++ b/uncloud_django_based/uncloud/uncloud_vm/serializers.py @@ -122,6 +122,7 @@ class OrderVMProductSerializer(VMProductSerializer): class NicoVMProductSerializer(serializers.ModelSerializer): snapshots = VMSnapshotProductSerializer(many=True, read_only=True) + order = serializers.StringRelatedField() class Meta: model = VMProduct diff --git a/uncloud_django_based/uncloud/uncloud_vm/views.py b/uncloud_django_based/uncloud/uncloud_vm/views.py index 2d0a693..cf90891 100644 --- a/uncloud_django_based/uncloud/uncloud_vm/views.py +++ b/uncloud_django_based/uncloud/uncloud_vm/views.py @@ -185,40 +185,14 @@ class NicoVMProductViewSet(ProductViewSet): def get_queryset(self): obj = VMProduct.objects.filter(owner=self.request.user) - return obj - # Use a database transaction so that we do not get half-created structure - # if something goes wrong. - @transaction.atomic def create(self, request): - # Extract serializer data. - serializer = self.get_serializer(data=request.data) + serializer = self.serializer_class(data=request.data, context={'request': request}) serializer.is_valid(raise_exception=True) + vm = serializer.save(owner=request.user) - 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. - disk = VMDiskProduct(owner=request.user, order=order, - **serializer.validated_data.pop("primary_disk")) - - # Create VM. - vm = serializer.save(owner=request.user, order=order, primary_disk=disk) - disk.vm = vm - disk.save() - - return Response(VMProductSerializer(vm, context={'request': request}).data) - + return Response(serializer.data) ### # Admin stuff. From c835c874d5e17da2a49d6ed1360556081244d945 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 2 May 2020 22:48:05 +0200 Subject: [PATCH 012/174] [BREAKING] make Order a stand-alone version I think that while the idea of an Orderrecord is good, we might get away / have a simpler implementation if we only use orders and reference them where needed. I saved the previous Order model for easy rollback, if my assumption is wrong. --- .../migrations/0009_auto_20200502_2047.py | 47 ++++++++++++++ .../uncloud/uncloud_pay/models.py | 65 ++++++++++++++++++- 2 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 uncloud_django_based/uncloud/uncloud_pay/migrations/0009_auto_20200502_2047.py diff --git a/uncloud_django_based/uncloud/uncloud_pay/migrations/0009_auto_20200502_2047.py b/uncloud_django_based/uncloud/uncloud_pay/migrations/0009_auto_20200502_2047.py new file mode 100644 index 0000000..cb9cd78 --- /dev/null +++ b/uncloud_django_based/uncloud/uncloud_pay/migrations/0009_auto_20200502_2047.py @@ -0,0 +1,47 @@ +# Generated by Django 3.0.5 on 2020-05-02 20:47 + +from django.conf import settings +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('uncloud_pay', '0008_auto_20200502_1921'), + ] + + operations = [ + migrations.AddField( + model_name='order', + name='one_time_price', + field=models.DecimalField(decimal_places=2, default=0.0, max_digits=10, validators=[django.core.validators.MinValueValidator(0)]), + ), + migrations.AddField( + model_name='order', + name='recurring_price', + field=models.DecimalField(decimal_places=2, default=0.0, max_digits=10, validators=[django.core.validators.MinValueValidator(0)]), + ), + migrations.AddField( + model_name='order', + name='replaced_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='uncloud_pay.Order'), + ), + migrations.CreateModel( + name='OrderTimothee', + fields=[ + ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('creation_date', models.DateTimeField(auto_now_add=True)), + ('starting_date', models.DateTimeField(default=django.utils.timezone.now)), + ('ending_date', models.DateTimeField(blank=True, null=True)), + ('recurring_period', 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)), + ('bill', models.ManyToManyField(blank=True, editable=False, to='uncloud_pay.Bill')), + ('billing_address', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='uncloud_pay.BillingAddress')), + ('owner', models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/uncloud_django_based/uncloud/uncloud_pay/models.py b/uncloud_django_based/uncloud/uncloud_pay/models.py index a326810..9a8a49a 100644 --- a/uncloud_django_based/uncloud/uncloud_pay/models.py +++ b/uncloud_django_based/uncloud/uncloud_pay/models.py @@ -809,6 +809,64 @@ class Order(models.Model): editable=False) billing_address = models.ForeignKey(BillingAddress, on_delete=models.CASCADE) + # TODO: enforce ending_date - starting_date to be larger than recurring_period. + creation_date = models.DateTimeField(auto_now_add=True) + starting_date = models.DateTimeField(default=timezone.now) + ending_date = models.DateTimeField(blank=True, + null=True) + + bill = models.ManyToManyField(Bill, + editable=False, + blank=True) + + recurring_period = models.CharField(max_length=32, + choices = RecurringPeriod.choices, + default = RecurringPeriod.PER_MONTH) + + one_time_price = models.DecimalField(default=0.0, + max_digits=AMOUNT_MAX_DIGITS, + decimal_places=AMOUNT_DECIMALS, + validators=[MinValueValidator(0)]) + + recurring_price = models.DecimalField(default=0.0, + max_digits=AMOUNT_MAX_DIGITS, + decimal_places=AMOUNT_DECIMALS, + validators=[MinValueValidator(0)]) + + replaced_by = models.ForeignKey('self', + on_delete=models.PROTECT, + blank=True, + null=True) + + # Trigger initial bill generation at order creation. + def save(self, *args, **kwargs): + if self.ending_date and self.ending_date < self.starting_date: + raise ValidationError("End date cannot be before starting date") + + super().save(*args, **kwargs) + + Bill.generate_for(self.starting_date.year, self.starting_date.month, self.owner) + + # Used by uncloud_pay tests. + @property + def bills(self): + return Bill.objects.filter(order=self) + + def __str__(self): + return "Order {} created at {}, {}->{}, recurring period {}. Price one time {}, recurring {}".format( + self.uuid, self.creation_date, + self.starting_date, self.ending_date, + self.recurring_period, + self.one_time_price, + self.recurring_price) + +class OrderTimothee(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) + billing_address = models.ForeignKey(BillingAddress, on_delete=models.CASCADE) + # TODO: enforce ending_date - starting_date to be larger than recurring_period. creation_date = models.DateTimeField(auto_now_add=True) starting_date = models.DateTimeField(default=timezone.now) @@ -856,10 +914,13 @@ class Order(models.Model): description=description) def __str__(self): - return "Order {} created at {}, {}->{}, recurring period {}".format( + return "Order {} created at {}, {}->{}, recurring period {}. Price one time {}, recurring {}".format( self.uuid, self.creation_date, self.starting_date, self.ending_date, - self.recurring_period) + self.recurring_period, + self.one_time_price, + self.recurring_price) + class OrderRecord(models.Model): From 99a18232aaacc0872f294952291bc3dbeb5b5c80 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 2 May 2020 23:44:20 +0200 Subject: [PATCH 013/174] VMs now properly set their pricing --- .../uncloud/uncloud_pay/models.py | 19 +++++++++---------- .../uncloud/uncloud_vm/models.py | 3 ++- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/uncloud_django_based/uncloud/uncloud_pay/models.py b/uncloud_django_based/uncloud/uncloud_pay/models.py index 9a8a49a..aca226e 100644 --- a/uncloud_django_based/uncloud/uncloud_pay/models.py +++ b/uncloud_django_based/uncloud/uncloud_pay/models.py @@ -845,15 +845,15 @@ class Order(models.Model): super().save(*args, **kwargs) - Bill.generate_for(self.starting_date.year, self.starting_date.month, self.owner) +# Bill.generate_for(self.starting_date.year, self.starting_date.month, self.owner) - # Used by uncloud_pay tests. - @property - def bills(self): - return Bill.objects.filter(order=self) + # # Used by uncloud_pay tests. + # @property + # def bills(self): + # return Bill.objects.filter(order=self) def __str__(self): - return "Order {} created at {}, {}->{}, recurring period {}. Price one time {}, recurring {}".format( + return "Order {} created at {}, {}->{}, recurring period {}. One time price {}, recurring price {}".format( self.uuid, self.creation_date, self.starting_date, self.ending_date, self.recurring_period, @@ -997,11 +997,10 @@ class Product(UncloudModel): raise ValidationError("Cannot order without a billing address") self.order = Order.objects.create(owner=self.owner, - billing_address=billing_address) + billing_address=billing_address, + one_time_price=self.one_time_price, + recurring_price=self.recurring_price) - - print("in save op: {}".format(self)) - print(self.order) super().save(*args, **kwargs) # # Make sure we only create records on creation. diff --git a/uncloud_django_based/uncloud/uncloud_vm/models.py b/uncloud_django_based/uncloud/uncloud_vm/models.py index 91c9291..a542503 100644 --- a/uncloud_django_based/uncloud/uncloud_vm/models.py +++ b/uncloud_django_based/uncloud/uncloud_vm/models.py @@ -69,7 +69,7 @@ class VMProduct(Product): cores = models.IntegerField() ram_in_gb = models.FloatField() - # Default recurring price is PER_MONTH, see uncloud_pay.models.Product. + @property def recurring_price(self): return self.cores * 3 + self.ram_in_gb * 4 @@ -79,6 +79,7 @@ class VMProduct(Product): self.name, self.cores, self.ram_in_gb) + @property def description(self): return "Virtual machine '{}': {} core(s), {}GB memory".format( From e3b28354fef7cff2afdc878030817b97153d4986 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 5 May 2020 15:19:04 +0200 Subject: [PATCH 014/174] ++notes --- .../doc/README-how-to-configure-remote-uncloud-clients.org | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/uncloud_django_based/uncloud/doc/README-how-to-configure-remote-uncloud-clients.org b/uncloud_django_based/uncloud/doc/README-how-to-configure-remote-uncloud-clients.org index 7217e1f..b48886b 100644 --- a/uncloud_django_based/uncloud/doc/README-how-to-configure-remote-uncloud-clients.org +++ b/uncloud_django_based/uncloud/doc/README-how-to-configure-remote-uncloud-clients.org @@ -10,6 +10,7 @@ | SSH -L tunnel | All nodes can use [::1]:5432 | SSH setup can be fragile | | ssh djangohost manage.py | All DB ops locally | Code is only executed on django host | | https + token | Rest alike / consistent access | Code is only executed on django host | +| from_django | Everything is on the django host | main host can become bottleneck | ** remote vs. local Django code execution - If manage.py is executed locally (= on the client), it can check/modify local configs @@ -19,3 +20,9 @@ - Remote execution (= on the primary django host) can acess the db via unix socket - However remote execution cannot check local state +** from_django + - might reuse existing methods like celery + - reduces the amount of things to be installed on the client to + almost zero + - follows the opennebula model + - has a single point of failurebin From 594f1a9b69016ad3d02bcf3fe1cc65761c513a8e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 5 May 2020 15:19:50 +0200 Subject: [PATCH 015/174] +hacks --- uncloud_django_based/{ => hacks}/abk-hacks.py | 0 .../{ => hacks}/abkhack/opennebula_hacks.py | 0 uncloud_django_based/hacks/command-wrapper.sh | 18 ++++++++++++++++++ 3 files changed, 18 insertions(+) rename uncloud_django_based/{ => hacks}/abk-hacks.py (100%) rename uncloud_django_based/{ => hacks}/abkhack/opennebula_hacks.py (100%) create mode 100644 uncloud_django_based/hacks/command-wrapper.sh diff --git a/uncloud_django_based/abk-hacks.py b/uncloud_django_based/hacks/abk-hacks.py similarity index 100% rename from uncloud_django_based/abk-hacks.py rename to uncloud_django_based/hacks/abk-hacks.py diff --git a/uncloud_django_based/abkhack/opennebula_hacks.py b/uncloud_django_based/hacks/abkhack/opennebula_hacks.py similarity index 100% rename from uncloud_django_based/abkhack/opennebula_hacks.py rename to uncloud_django_based/hacks/abkhack/opennebula_hacks.py diff --git a/uncloud_django_based/hacks/command-wrapper.sh b/uncloud_django_based/hacks/command-wrapper.sh new file mode 100644 index 0000000..d6ddd13 --- /dev/null +++ b/uncloud_django_based/hacks/command-wrapper.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +dbhost=$1; shift + +ssh -L5432:localhost:5432 "$dbhost" & + +python manage.py "$@" + + + +# command only needs to be active while manage command is running + +# -T no pseudo terminal + + +# alternatively: commands output shell code + +# ssh uncloud@dbhost "python manage.py --hostname xxx ..." From aa8ade473033e81664a9eacf17c89af386c3644e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 5 May 2020 16:01:47 +0200 Subject: [PATCH 016/174] Add readme about identifiers --- .../uncloud/doc/README-identifiers.org | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 uncloud_django_based/uncloud/doc/README-identifiers.org diff --git a/uncloud_django_based/uncloud/doc/README-identifiers.org b/uncloud_django_based/uncloud/doc/README-identifiers.org new file mode 100644 index 0000000..3dbb4b5 --- /dev/null +++ b/uncloud_django_based/uncloud/doc/README-identifiers.org @@ -0,0 +1,29 @@ +* Identifiers +** Problem description + Identifiers can be integers, strings or other objects. They should + be unique. +** Approach 1: integers + Integers are somewhat easy to remember, but also include + predictable growth, which might allow access to guessed hacking + (obivously proper permissions should prevent this). +** Approach 2: random uuids + UUIDs are 128 bit integers. Python supports uuid.uuid4() for random + uuids. +** Approach 3: IPv6 addresses + uncloud heavily depends on IPv6 in the first place. uncloud could + use a /48 to identify all objects. Objects that have IPv6 addresses + on their own, don't need to draw from the system /48. +*** Possible Subnetworks + Assuming uncloud uses a /48 to represent all resources. + + | Network | Name | Description | + |-----------------+-----------------+----------------------------------------------| + | 2001:db8::/48 | uncloud network | All identifiers drawn from here | + | 2001:db8:1::/64 | VM network | Every VM has an IPv6 address in this network | + | 2001:db8:2::/64 | Bill network | Every bill has an IPv6 address | + | 2001:db8:3::/64 | Order network | Every order has an IPv6 address | + | 2001:db8:5::/64 | Product network | Every product (?) has an IPv6 address | + | 2001:db8:4::/64 | Disk network | Every disk is identified | + +*** Tests + [15:47:37] black3.place6:~# rbd create -s 10G ssd/2a0a:e5c0:1::8 From 892b2b6f137c97bd863b9d0ef35fcf27be952389 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Thu, 7 May 2020 12:03:28 +0200 Subject: [PATCH 017/174] Revert "Disable vat validator to get project back running" This reverts commit 1cf20a2cb6c84b2db79d2e45e49d5fbb81b392e7. --- uncloud_django_based/uncloud/uncloud_pay/views.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/uncloud_django_based/uncloud/uncloud_pay/views.py b/uncloud_django_based/uncloud/uncloud_pay/views.py index 59d310e..0c68ac6 100644 --- a/uncloud_django_based/uncloud/uncloud_pay/views.py +++ b/uncloud_django_based/uncloud/uncloud_pay/views.py @@ -7,8 +7,8 @@ from rest_framework.response import Response from rest_framework.decorators import action from rest_framework.reverse import reverse from rest_framework.decorators import renderer_classes -#from vat_validator import validate_vat, vies -#from vat_validator.countries import EU_COUNTRY_CODES +from vat_validator import validate_vat, vies +from vat_validator.countries import EU_COUNTRY_CODES import json import logging @@ -16,7 +16,7 @@ import logging from .models import * from .serializers import * from datetime import datetime -#from vat_validator import sanitize_vat +from vat_validator import sanitize_vat import uncloud_pay.stripe as uncloud_stripe logger = logging.getLogger(__name__) From db3c29d17ed9ee42b56f7d6d086524a4a40d7581 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Thu, 7 May 2020 12:05:26 +0200 Subject: [PATCH 018/174] Fix admin order creation --- .../uncloud/uncloud_pay/serializers.py | 32 +++++++++++++++++-- .../uncloud/uncloud_pay/views.py | 4 ++- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/uncloud_django_based/uncloud/uncloud_pay/serializers.py b/uncloud_django_based/uncloud/uncloud_pay/serializers.py index 1b5db24..70f5c5e 100644 --- a/uncloud_django_based/uncloud/uncloud_pay/serializers.py +++ b/uncloud_django_based/uncloud/uncloud_pay/serializers.py @@ -1,5 +1,6 @@ from django.contrib.auth import get_user_model from rest_framework import serializers +from uncloud_auth.serializers import UserSerializer from .models import * ### @@ -41,11 +42,36 @@ class OrderRecordSerializer(serializers.ModelSerializer): class OrderSerializer(serializers.ModelSerializer): - records = OrderRecordSerializer(many=True, read_only=True) + owner = serializers.PrimaryKeyRelatedField(queryset=get_user_model().objects.all()) + + def __init__(self, *args, **kwargs): + # Don't pass the 'fields' arg up to the superclass + admin = kwargs.pop('admin', None) + + # Instantiate the superclass normally + super(OrderSerializer, self).__init__(*args, **kwargs) + + # Only allows owner in admin mode. + if not admin: + self.fields.pop('owner') + + def create(self, validated_data): + billing_address = BillingAddress.get_preferred_address_for(validated_data["owner"]) + instance = Order(billing_address=billing_address, **validated_data) + instance.save() + + return instance + + def validate_owner(self, value): + if BillingAddress.get_preferred_address_for(value) == None: + raise serializers.ValidationError("Owner does not have a valid billing address.") + + return value + class Meta: model = Order - fields = ['uuid', 'creation_date', 'starting_date', 'ending_date', - 'bill', 'recurring_period', 'records', 'recurring_price', 'one_time_price'] + fields = ['uuid', 'owner', 'creation_date', 'starting_date', 'ending_date', + 'bill', 'recurring_period', 'recurring_price', 'one_time_price'] ### diff --git a/uncloud_django_based/uncloud/uncloud_pay/views.py b/uncloud_django_based/uncloud/uncloud_pay/views.py index 0c68ac6..54ff2f0 100644 --- a/uncloud_django_based/uncloud/uncloud_pay/views.py +++ b/uncloud_django_based/uncloud/uncloud_pay/views.py @@ -279,9 +279,11 @@ class AdminBillViewSet(viewsets.ModelViewSet): return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) class AdminOrderViewSet(viewsets.ModelViewSet): - serializer_class = OrderSerializer permission_classes = [permissions.IsAuthenticated] + def get_serializer(self, *args, **kwargs): + return OrderSerializer(*args, **kwargs, admin=True) + def get_queryset(self): return Order.objects.all() From 056006332639a94b2583877e6fc047349d76cb99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Thu, 7 May 2020 12:08:18 +0200 Subject: [PATCH 019/174] Add description field to Orders --- .../migrations/0010_order_description.py | 19 +++++++++++++++++++ .../uncloud/uncloud_pay/models.py | 1 + .../uncloud/uncloud_pay/serializers.py | 2 +- 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 uncloud_django_based/uncloud/uncloud_pay/migrations/0010_order_description.py diff --git a/uncloud_django_based/uncloud/uncloud_pay/migrations/0010_order_description.py b/uncloud_django_based/uncloud/uncloud_pay/migrations/0010_order_description.py new file mode 100644 index 0000000..2613bff --- /dev/null +++ b/uncloud_django_based/uncloud/uncloud_pay/migrations/0010_order_description.py @@ -0,0 +1,19 @@ +# Generated by Django 3.0.6 on 2020-05-07 10:07 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('uncloud_pay', '0009_auto_20200502_2047'), + ] + + operations = [ + migrations.AddField( + model_name='order', + name='description', + field=models.TextField(default=''), + preserve_default=False, + ), + ] diff --git a/uncloud_django_based/uncloud/uncloud_pay/models.py b/uncloud_django_based/uncloud/uncloud_pay/models.py index aca226e..1294a54 100644 --- a/uncloud_django_based/uncloud/uncloud_pay/models.py +++ b/uncloud_django_based/uncloud/uncloud_pay/models.py @@ -808,6 +808,7 @@ class Order(models.Model): on_delete=models.CASCADE, editable=False) billing_address = models.ForeignKey(BillingAddress, on_delete=models.CASCADE) + description = models.TextField() # TODO: enforce ending_date - starting_date to be larger than recurring_period. creation_date = models.DateTimeField(auto_now_add=True) diff --git a/uncloud_django_based/uncloud/uncloud_pay/serializers.py b/uncloud_django_based/uncloud/uncloud_pay/serializers.py index 70f5c5e..ad50c68 100644 --- a/uncloud_django_based/uncloud/uncloud_pay/serializers.py +++ b/uncloud_django_based/uncloud/uncloud_pay/serializers.py @@ -70,7 +70,7 @@ class OrderSerializer(serializers.ModelSerializer): class Meta: model = Order - fields = ['uuid', 'owner', 'creation_date', 'starting_date', 'ending_date', + fields = ['uuid', 'owner', 'description', 'creation_date', 'starting_date', 'ending_date', 'bill', 'recurring_period', 'recurring_price', 'one_time_price'] From 95d43f002f742090e644d76c9ba8c09a77397db6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Thu, 7 May 2020 12:12:35 +0200 Subject: [PATCH 020/174] Move django-based uncloud to top-level --- issues.org => archive/issues.org | 0 .../uncloud_django_based}/hacks/abk-hacks.py | 0 .../hacks/abkhack/opennebula_hacks.py | 0 .../uncloud_django_based}/hacks/command-wrapper.sh | 0 .../uncloud_django_based}/meow-payv1/README.md | 0 .../uncloud_django_based}/meow-payv1/config.py | 0 .../uncloud_django_based}/meow-payv1/hack-a-vpn.py | 0 .../uncloud_django_based}/meow-payv1/helper.py | 0 .../meow-payv1/products/ipv6-only-django.json | 0 .../meow-payv1/products/ipv6-only-vm.json | 0 .../meow-payv1/products/ipv6-only-vpn.json | 0 .../meow-payv1/products/ipv6box.json | 0 .../meow-payv1/products/membership.json | 0 .../meow-payv1/requirements.txt | 0 .../meow-payv1/sample-pay.conf | 0 .../uncloud_django_based}/meow-payv1/schemas.py | 0 .../uncloud_django_based}/meow-payv1/stripe_hack.py | 0 .../meow-payv1/stripe_utils.py | 0 .../uncloud_django_based}/meow-payv1/ucloud_pay.py | 0 .../uncloud_django_based}/notes-abk.md | 0 .../uncloud_django_based}/notes-nico.org | 0 .../uncloud_django_based}/plan.org | 0 .../uncloud_django_based}/uncloud/.gitignore | 0 .../uncloud_django_based}/vat_rates.csv | 0 .../uncloud_etcd_based}/bin/gen-version | 0 .../uncloud_etcd_based}/bin/uncloud | 0 .../uncloud_etcd_based}/bin/uncloud-run-reinstall | 0 .../uncloud_etcd_based}/conf/uncloud.conf | 0 .../uncloud_etcd_based}/docs/Makefile | 0 .../uncloud_etcd_based}/docs/README.md | 0 .../uncloud_etcd_based/docs}/__init__.py | 0 .../uncloud_etcd_based/docs/source}/__init__.py | 0 .../uncloud_etcd_based}/docs/source/admin-guide.rst | 0 .../uncloud_etcd_based}/docs/source/conf.py | 0 .../docs/source/diagram-code/ucloud | 0 .../uncloud_etcd_based}/docs/source/hacking.rst | 0 .../docs/source/images/ucloud.svg | 0 .../uncloud_etcd_based}/docs/source/index.rst | 0 .../docs/source/introduction.rst | 0 .../uncloud_etcd_based}/docs/source/misc/todo.rst | 0 .../docs/source/setup-install.rst | 0 .../docs/source/theory/summary.rst | 0 .../docs/source/troubleshooting.rst | 0 .../uncloud_etcd_based}/docs/source/user-guide.rst | 0 .../how-to-create-an-os-image-for-ucloud.rst | 0 .../uncloud_etcd_based}/docs/source/vm-images.rst | 0 .../uncloud_etcd_based}/scripts/uncloud | 0 .../uncloud_etcd_based}/setup.py | 0 .../uncloud_etcd_based/test}/__init__.py | 0 .../uncloud_etcd_based}/test/test_mac_local.py | 0 .../uncloud_etcd_based}/uncloud/__init__.py | 0 .../uncloud_etcd_based}/uncloud/api/README.md | 0 .../uncloud_etcd_based}/uncloud/api/__init__.py | 0 .../uncloud/api/common_fields.py | 0 .../uncloud/api/create_image_store.py | 0 .../uncloud_etcd_based}/uncloud/api/helper.py | 0 .../uncloud_etcd_based}/uncloud/api/main.py | 0 .../uncloud_etcd_based}/uncloud/api/schemas.py | 0 .../uncloud_etcd_based/uncloud/cli}/__init__.py | 0 .../uncloud_etcd_based}/uncloud/cli/helper.py | 0 .../uncloud_etcd_based}/uncloud/cli/host.py | 0 .../uncloud_etcd_based}/uncloud/cli/image.py | 0 .../uncloud_etcd_based}/uncloud/cli/main.py | 0 .../uncloud_etcd_based}/uncloud/cli/network.py | 0 .../uncloud_etcd_based}/uncloud/cli/user.py | 0 .../uncloud_etcd_based}/uncloud/cli/vm.py | 0 .../uncloud_etcd_based/uncloud/client}/__init__.py | 0 .../uncloud_etcd_based}/uncloud/client/main.py | 0 .../uncloud_etcd_based}/uncloud/common/__init__.py | 0 .../uncloud_etcd_based}/uncloud/common/classes.py | 0 .../uncloud_etcd_based}/uncloud/common/cli.py | 0 .../uncloud_etcd_based}/uncloud/common/counters.py | 0 .../uncloud/common/etcd_wrapper.py | 0 .../uncloud_etcd_based}/uncloud/common/host.py | 0 .../uncloud_etcd_based}/uncloud/common/network.py | 0 .../uncloud_etcd_based}/uncloud/common/parser.py | 0 .../uncloud_etcd_based}/uncloud/common/request.py | 0 .../uncloud_etcd_based}/uncloud/common/schemas.py | 0 .../uncloud_etcd_based}/uncloud/common/settings.py | 0 .../uncloud_etcd_based}/uncloud/common/shared.py | 0 .../uncloud/common/storage_handlers.py | 0 .../uncloud_etcd_based}/uncloud/common/vm.py | 0 .../uncloud/configure}/__init__.py | 0 .../uncloud_etcd_based}/uncloud/configure/main.py | 0 .../uncloud/filescanner/__init__.py | 0 .../uncloud_etcd_based}/uncloud/filescanner/main.py | 0 .../uncloud_etcd_based}/uncloud/hack/README.org | 0 .../uncloud_etcd_based}/uncloud/hack/__init__.py | 0 .../uncloud/hack/conf.d/ucloud-host | 0 .../uncloud_etcd_based}/uncloud/hack/config.py | 0 .../uncloud_etcd_based}/uncloud/hack/db.py | 0 .../uncloud/hack/hackcloud/.gitignore | 0 .../uncloud/hack/hackcloud/__init__.py | 0 .../uncloud/hack/hackcloud/etcd-client.sh | 0 .../uncloud/hack/hackcloud/ifdown.sh | 0 .../uncloud/hack/hackcloud/ifup.sh | 0 .../uncloud/hack/hackcloud/mac-last | 0 .../uncloud/hack/hackcloud/mac-prefix | 0 .../uncloud/hack/hackcloud/net.sh | 0 .../uncloud/hack/hackcloud/nftrules | 0 .../uncloud/hack/hackcloud/radvd.conf | 0 .../uncloud/hack/hackcloud/radvd.sh | 0 .../uncloud/hack/hackcloud/vm.sh | 0 .../uncloud_etcd_based}/uncloud/hack/host.py | 0 .../uncloud_etcd_based}/uncloud/hack/mac.py | 0 .../uncloud_etcd_based}/uncloud/hack/main.py | 0 .../uncloud_etcd_based}/uncloud/hack/net.py | 0 .../uncloud_etcd_based}/uncloud/hack/nftables.conf | 0 .../uncloud_etcd_based}/uncloud/hack/product.py | 0 .../uncloud/hack/rc-scripts/ucloud-api | 0 .../uncloud/hack/rc-scripts/ucloud-host | 0 .../uncloud/hack/rc-scripts/ucloud-metadata | 0 .../uncloud/hack/rc-scripts/ucloud-scheduler | 0 .../uncloud/hack/uncloud-hack-init-host | 0 .../uncloud_etcd_based}/uncloud/hack/uncloud-run-vm | 0 .../uncloud_etcd_based}/uncloud/hack/vm.py | 0 .../uncloud_etcd_based}/uncloud/host/__init__.py | 0 .../uncloud_etcd_based}/uncloud/host/main.py | 0 .../uncloud/host/virtualmachine.py | 0 .../uncloud/imagescanner/__init__.py | 0 .../uncloud/imagescanner/main.py | 0 .../uncloud/metadata/__init__.py | 0 .../uncloud_etcd_based}/uncloud/metadata/main.py | 0 .../uncloud_etcd_based}/uncloud/network/README | 0 .../uncloud_etcd_based/uncloud/network}/__init__.py | 0 .../uncloud/network/create-bridge.sh | 0 .../uncloud/network/create-tap.sh | 0 .../uncloud/network/create-vxlan.sh | 0 .../uncloud/network/radvd-template.conf | 0 .../uncloud_etcd_based}/uncloud/oneshot/__init__.py | 0 .../uncloud_etcd_based}/uncloud/oneshot/main.py | 0 .../uncloud/oneshot/virtualmachine.py | 0 .../uncloud/scheduler/__init__.py | 0 .../uncloud_etcd_based}/uncloud/scheduler/helper.py | 0 .../uncloud_etcd_based}/uncloud/scheduler/main.py | 0 .../uncloud/scheduler/tests}/__init__.py | 0 .../uncloud/scheduler/tests/test_basics.py | 0 .../scheduler/tests/test_dead_host_mechanism.py | 0 .../uncloud_etcd_based}/uncloud/version.py | 0 .../uncloud_etcd_based}/uncloud/vmm/__init__.py | 0 ...ADME-how-to-configure-remote-uncloud-clients.org | 0 .../uncloud/doc => doc}/README-identifiers.org | 0 .../uncloud/doc => doc}/README-object-relations.md | 0 .../uncloud/doc => doc}/README-postgresql.org | 0 .../uncloud/doc => doc}/README-products.md | 0 .../uncloud/doc => doc}/README-vpn.org | 0 {uncloud_django_based/uncloud/doc => doc}/README.md | 0 uncloud_django_based/uncloud/manage.py => manage.py | 0 .../uncloud/models.dot => models.dot | 0 .../uncloud/models.png => models.png | Bin .../uncloud_service => opennebula}/__init__.py | 0 .../uncloud/opennebula => opennebula}/admin.py | 0 .../uncloud/opennebula => opennebula}/apps.py | 0 .../management/commands/opennebula-synchosts.py | 0 .../management/commands/opennebula-syncvms.py | 0 .../management/commands/opennebula-to-uncloud.py | 0 .../migrations/0001_initial.py | 0 .../migrations/0002_auto_20200225_1335.py | 0 .../migrations/0003_auto_20200225_1428.py | 0 .../migrations/0004_auto_20200225_1816.py | 0 .../migrations/__init__.py | 0 .../uncloud/opennebula => opennebula}/models.py | 0 .../opennebula => opennebula}/serializers.py | 0 .../uncloud/opennebula => opennebula}/tests.py | 0 .../uncloud/opennebula => opennebula}/views.py | 0 .../uncloud/requirements.txt => requirements.txt | 0 .../uncloud/uncloud => uncloud}/.gitignore | 0 .../uncloud/uncloud => uncloud}/__init__.py | 0 .../uncloud/uncloud => uncloud}/asgi.py | 0 .../management/commands/uncloud.py | 0 .../uncloud/uncloud => uncloud}/models.py | 0 .../uncloud/uncloud => uncloud}/settings.py | 0 .../uncloud/uncloud => uncloud}/urls.py | 0 .../uncloud/uncloud => uncloud}/wsgi.py | 0 .../uncloud_storage => uncloud_auth}/__init__.py | 0 .../uncloud/uncloud_auth => uncloud_auth}/admin.py | 0 .../uncloud/uncloud_auth => uncloud_auth}/apps.py | 0 .../migrations/0001_initial.py | 0 .../migrations/0002_auto_20200318_1343.py | 0 .../migrations/0003_auto_20200318_1345.py | 0 .../migrations}/__init__.py | 0 .../uncloud/uncloud_auth => uncloud_auth}/models.py | 0 .../uncloud_auth => uncloud_auth}/serializers.py | 0 .../uncloud/uncloud_auth => uncloud_auth}/views.py | 0 .../migrations => uncloud_net}/__init__.py | 0 .../uncloud/uncloud_net => uncloud_net}/admin.py | 0 .../uncloud/uncloud_net => uncloud_net}/apps.py | 0 .../management/commands/vpn.py | 0 .../migrations/0001_initial.py | 0 .../migrations/0002_auto_20200409_1225.py | 0 .../migrations/0003_auto_20200417_0551.py | 0 .../docs => uncloud_net/migrations}/__init__.py | 0 .../uncloud/uncloud_net => uncloud_net}/models.py | 0 .../uncloud_net => uncloud_net}/serializers.py | 0 .../uncloud/uncloud_net => uncloud_net}/tests.py | 0 .../uncloud/uncloud_net => uncloud_net}/views.py | 0 .../docs/source => uncloud_pay}/__init__.py | 0 .../uncloud/uncloud_pay => uncloud_pay}/admin.py | 0 .../uncloud/uncloud_pay => uncloud_pay}/apps.py | 0 .../uncloud/uncloud_pay => uncloud_pay}/helpers.py | 0 .../management/commands/charge-negative-balance.py | 0 .../management/commands/generate-bills.py | 0 .../management/commands/handle-overdue-bills.py | 0 .../management/commands/import-vat-rates.py | 0 .../migrations/0001_initial.py | 0 .../migrations/0002_auto_20200305_1524.py | 0 .../migrations/0003_auto_20200305_1354.py | 0 .../migrations/0004_auto_20200409_1225.py | 0 .../migrations/0005_auto_20200413_0924.py | 0 .../migrations/0006_auto_20200415_1003.py | 0 .../migrations/0006_billingaddress.py | 0 .../migrations/0007_auto_20200418_0737.py | 0 .../migrations/0008_auto_20200502_1921.py | 0 .../migrations/0009_auto_20200502_2047.py | 0 .../migrations/0010_order_description.py | 0 .../test => uncloud_pay/migrations}/__init__.py | 0 .../uncloud/uncloud_pay => uncloud_pay}/models.py | 0 .../uncloud_pay => uncloud_pay}/serializers.py | 0 .../uncloud/uncloud_pay => uncloud_pay}/stripe.py | 0 .../uncloud_pay => uncloud_pay}/templates/bill.html | 0 .../templates/error.html.j2 | 0 .../templates/stripe-payment.html.j2 | 0 .../uncloud/uncloud_pay => uncloud_pay}/tests.py | 0 .../uncloud/uncloud_pay => uncloud_pay}/views.py | 0 .../uncloud/cli => uncloud_service}/__init__.py | 0 .../uncloud_service => uncloud_service}/admin.py | 0 .../uncloud_service => uncloud_service}/apps.py | 0 .../migrations/0001_initial.py | 0 .../migrations/0002_auto_20200418_0641.py | 0 .../migrations}/__init__.py | 0 .../uncloud_service => uncloud_service}/models.py | 0 .../serializers.py | 0 .../uncloud_service => uncloud_service}/tests.py | 0 .../uncloud_service => uncloud_service}/views.py | 0 .../configure => uncloud_storage}/__init__.py | 0 .../uncloud_storage => uncloud_storage}/admin.py | 0 .../uncloud_storage => uncloud_storage}/apps.py | 0 .../uncloud_storage => uncloud_storage}/models.py | 0 .../uncloud_storage => uncloud_storage}/tests.py | 0 .../uncloud_storage => uncloud_storage}/views.py | 0 .../uncloud/network => uncloud_vm}/__init__.py | 0 .../uncloud/uncloud_vm => uncloud_vm}/admin.py | 0 .../uncloud/uncloud_vm => uncloud_vm}/apps.py | 0 .../management/commands/vm.py | 0 .../migrations/0001_initial.py | 0 .../migrations/0002_auto_20200305_1321.py | 0 .../migrations/0003_remove_vmhost_vms.py | 0 .../migrations/0004_remove_vmproduct_vmid.py | 0 .../migrations/0004_vmproduct_primary_disk.py | 0 .../migrations/0005_auto_20200309_1258.py | 0 .../migrations/0005_auto_20200321_1058.py | 0 .../migrations/0006_auto_20200322_1758.py | 0 .../migrations/0007_vmhost_vmcluster.py | 0 .../migrations/0008_auto_20200403_1727.py | 0 .../migrations/0009_auto_20200417_0551.py | 0 .../migrations/0009_merge_20200413_0857.py | 0 .../migrations/0010_auto_20200413_0924.py | 0 .../migrations/0011_merge_20200418_0641.py | 0 .../migrations/0012_auto_20200418_0641.py | 0 .../0013_remove_vmproduct_primary_disk.py | 0 .../tests => uncloud_vm/migrations}/__init__.py | 0 .../uncloud/uncloud_vm => uncloud_vm}/models.py | 0 .../uncloud_vm => uncloud_vm}/serializers.py | 0 .../uncloud/uncloud_vm => uncloud_vm}/tests.py | 0 .../uncloud/uncloud_vm => uncloud_vm}/views.py | 0 265 files changed, 0 insertions(+), 0 deletions(-) rename issues.org => archive/issues.org (100%) rename {uncloud_django_based => archive/uncloud_django_based}/hacks/abk-hacks.py (100%) rename {uncloud_django_based => archive/uncloud_django_based}/hacks/abkhack/opennebula_hacks.py (100%) rename {uncloud_django_based => archive/uncloud_django_based}/hacks/command-wrapper.sh (100%) rename {uncloud_django_based => archive/uncloud_django_based}/meow-payv1/README.md (100%) rename {uncloud_django_based => archive/uncloud_django_based}/meow-payv1/config.py (100%) rename {uncloud_django_based => archive/uncloud_django_based}/meow-payv1/hack-a-vpn.py (100%) rename {uncloud_django_based => archive/uncloud_django_based}/meow-payv1/helper.py (100%) rename {uncloud_django_based => archive/uncloud_django_based}/meow-payv1/products/ipv6-only-django.json (100%) rename {uncloud_django_based => archive/uncloud_django_based}/meow-payv1/products/ipv6-only-vm.json (100%) rename {uncloud_django_based => archive/uncloud_django_based}/meow-payv1/products/ipv6-only-vpn.json (100%) rename {uncloud_django_based => archive/uncloud_django_based}/meow-payv1/products/ipv6box.json (100%) rename {uncloud_django_based => archive/uncloud_django_based}/meow-payv1/products/membership.json (100%) rename {uncloud_django_based => archive/uncloud_django_based}/meow-payv1/requirements.txt (100%) rename {uncloud_django_based => archive/uncloud_django_based}/meow-payv1/sample-pay.conf (100%) rename {uncloud_django_based => archive/uncloud_django_based}/meow-payv1/schemas.py (100%) rename {uncloud_django_based => archive/uncloud_django_based}/meow-payv1/stripe_hack.py (100%) rename {uncloud_django_based => archive/uncloud_django_based}/meow-payv1/stripe_utils.py (100%) rename {uncloud_django_based => archive/uncloud_django_based}/meow-payv1/ucloud_pay.py (100%) rename {uncloud_django_based => archive/uncloud_django_based}/notes-abk.md (100%) rename {uncloud_django_based => archive/uncloud_django_based}/notes-nico.org (100%) rename {uncloud_django_based => archive/uncloud_django_based}/plan.org (100%) rename {uncloud_django_based => archive/uncloud_django_based}/uncloud/.gitignore (100%) rename {uncloud_django_based => archive/uncloud_django_based}/vat_rates.csv (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/bin/gen-version (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/bin/uncloud (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/bin/uncloud-run-reinstall (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/conf/uncloud.conf (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/docs/Makefile (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/docs/README.md (100%) rename {uncloud_django_based/uncloud/opennebula => archive/uncloud_etcd_based/docs}/__init__.py (100%) rename {uncloud_django_based/uncloud/opennebula/migrations => archive/uncloud_etcd_based/docs/source}/__init__.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/docs/source/admin-guide.rst (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/docs/source/conf.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/docs/source/diagram-code/ucloud (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/docs/source/hacking.rst (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/docs/source/images/ucloud.svg (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/docs/source/index.rst (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/docs/source/introduction.rst (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/docs/source/misc/todo.rst (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/docs/source/setup-install.rst (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/docs/source/theory/summary.rst (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/docs/source/troubleshooting.rst (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/docs/source/user-guide.rst (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/docs/source/user-guide/how-to-create-an-os-image-for-ucloud.rst (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/docs/source/vm-images.rst (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/scripts/uncloud (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/setup.py (100%) rename {uncloud_django_based/uncloud/uncloud_auth => archive/uncloud_etcd_based/test}/__init__.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/test/test_mac_local.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/__init__.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/api/README.md (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/api/__init__.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/api/common_fields.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/api/create_image_store.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/api/helper.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/api/main.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/api/schemas.py (100%) rename {uncloud_django_based/uncloud/uncloud_auth/migrations => archive/uncloud_etcd_based/uncloud/cli}/__init__.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/cli/helper.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/cli/host.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/cli/image.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/cli/main.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/cli/network.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/cli/user.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/cli/vm.py (100%) rename {uncloud_django_based/uncloud/uncloud_net => archive/uncloud_etcd_based/uncloud/client}/__init__.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/client/main.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/common/__init__.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/common/classes.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/common/cli.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/common/counters.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/common/etcd_wrapper.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/common/host.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/common/network.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/common/parser.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/common/request.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/common/schemas.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/common/settings.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/common/shared.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/common/storage_handlers.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/common/vm.py (100%) rename {uncloud_django_based/uncloud/uncloud_net/migrations => archive/uncloud_etcd_based/uncloud/configure}/__init__.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/configure/main.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/filescanner/__init__.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/filescanner/main.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/README.org (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/__init__.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/conf.d/ucloud-host (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/config.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/db.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/hackcloud/.gitignore (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/hackcloud/__init__.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/hackcloud/etcd-client.sh (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/hackcloud/ifdown.sh (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/hackcloud/ifup.sh (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/hackcloud/mac-last (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/hackcloud/mac-prefix (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/hackcloud/net.sh (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/hackcloud/nftrules (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/hackcloud/radvd.conf (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/hackcloud/radvd.sh (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/hackcloud/vm.sh (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/host.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/mac.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/main.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/net.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/nftables.conf (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/product.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/rc-scripts/ucloud-api (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/rc-scripts/ucloud-host (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/rc-scripts/ucloud-metadata (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/rc-scripts/ucloud-scheduler (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/uncloud-hack-init-host (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/uncloud-run-vm (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/hack/vm.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/host/__init__.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/host/main.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/host/virtualmachine.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/imagescanner/__init__.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/imagescanner/main.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/metadata/__init__.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/metadata/main.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/network/README (100%) rename {uncloud_django_based/uncloud/uncloud_pay => archive/uncloud_etcd_based/uncloud/network}/__init__.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/network/create-bridge.sh (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/network/create-tap.sh (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/network/create-vxlan.sh (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/network/radvd-template.conf (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/oneshot/__init__.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/oneshot/main.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/oneshot/virtualmachine.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/scheduler/__init__.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/scheduler/helper.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/scheduler/main.py (100%) rename {uncloud_django_based/uncloud/uncloud_pay/migrations => archive/uncloud_etcd_based/uncloud/scheduler/tests}/__init__.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/scheduler/tests/test_basics.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/scheduler/tests/test_dead_host_mechanism.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/version.py (100%) rename {uncloud_etcd_based => archive/uncloud_etcd_based}/uncloud/vmm/__init__.py (100%) rename {uncloud_django_based/uncloud/doc => doc}/README-how-to-configure-remote-uncloud-clients.org (100%) rename {uncloud_django_based/uncloud/doc => doc}/README-identifiers.org (100%) rename {uncloud_django_based/uncloud/doc => doc}/README-object-relations.md (100%) rename {uncloud_django_based/uncloud/doc => doc}/README-postgresql.org (100%) rename {uncloud_django_based/uncloud/doc => doc}/README-products.md (100%) rename {uncloud_django_based/uncloud/doc => doc}/README-vpn.org (100%) rename {uncloud_django_based/uncloud/doc => doc}/README.md (100%) rename uncloud_django_based/uncloud/manage.py => manage.py (100%) rename uncloud_django_based/uncloud/models.dot => models.dot (100%) rename uncloud_django_based/uncloud/models.png => models.png (100%) rename {uncloud_django_based/uncloud/uncloud_service => opennebula}/__init__.py (100%) rename {uncloud_django_based/uncloud/opennebula => opennebula}/admin.py (100%) rename {uncloud_django_based/uncloud/opennebula => opennebula}/apps.py (100%) rename {uncloud_django_based/uncloud/opennebula => opennebula}/management/commands/opennebula-synchosts.py (100%) rename {uncloud_django_based/uncloud/opennebula => opennebula}/management/commands/opennebula-syncvms.py (100%) rename {uncloud_django_based/uncloud/opennebula => opennebula}/management/commands/opennebula-to-uncloud.py (100%) rename {uncloud_django_based/uncloud/opennebula => opennebula}/migrations/0001_initial.py (100%) rename {uncloud_django_based/uncloud/opennebula => opennebula}/migrations/0002_auto_20200225_1335.py (100%) rename {uncloud_django_based/uncloud/opennebula => opennebula}/migrations/0003_auto_20200225_1428.py (100%) rename {uncloud_django_based/uncloud/opennebula => opennebula}/migrations/0004_auto_20200225_1816.py (100%) rename {uncloud_django_based/uncloud/uncloud_service => opennebula}/migrations/__init__.py (100%) rename {uncloud_django_based/uncloud/opennebula => opennebula}/models.py (100%) rename {uncloud_django_based/uncloud/opennebula => opennebula}/serializers.py (100%) rename {uncloud_django_based/uncloud/opennebula => opennebula}/tests.py (100%) rename {uncloud_django_based/uncloud/opennebula => opennebula}/views.py (100%) rename uncloud_django_based/uncloud/requirements.txt => requirements.txt (100%) rename {uncloud_django_based/uncloud/uncloud => uncloud}/.gitignore (100%) rename {uncloud_django_based/uncloud/uncloud => uncloud}/__init__.py (100%) rename {uncloud_django_based/uncloud/uncloud => uncloud}/asgi.py (100%) rename {uncloud_django_based/uncloud/uncloud => uncloud}/management/commands/uncloud.py (100%) rename {uncloud_django_based/uncloud/uncloud => uncloud}/models.py (100%) rename {uncloud_django_based/uncloud/uncloud => uncloud}/settings.py (100%) rename {uncloud_django_based/uncloud/uncloud => uncloud}/urls.py (100%) rename {uncloud_django_based/uncloud/uncloud => uncloud}/wsgi.py (100%) rename {uncloud_django_based/uncloud/uncloud_storage => uncloud_auth}/__init__.py (100%) rename {uncloud_django_based/uncloud/uncloud_auth => uncloud_auth}/admin.py (100%) rename {uncloud_django_based/uncloud/uncloud_auth => uncloud_auth}/apps.py (100%) rename {uncloud_django_based/uncloud/uncloud_auth => uncloud_auth}/migrations/0001_initial.py (100%) rename {uncloud_django_based/uncloud/uncloud_auth => uncloud_auth}/migrations/0002_auto_20200318_1343.py (100%) rename {uncloud_django_based/uncloud/uncloud_auth => uncloud_auth}/migrations/0003_auto_20200318_1345.py (100%) rename {uncloud_django_based/uncloud/uncloud_vm => uncloud_auth/migrations}/__init__.py (100%) rename {uncloud_django_based/uncloud/uncloud_auth => uncloud_auth}/models.py (100%) rename {uncloud_django_based/uncloud/uncloud_auth => uncloud_auth}/serializers.py (100%) rename {uncloud_django_based/uncloud/uncloud_auth => uncloud_auth}/views.py (100%) rename {uncloud_django_based/uncloud/uncloud_vm/migrations => uncloud_net}/__init__.py (100%) rename {uncloud_django_based/uncloud/uncloud_net => uncloud_net}/admin.py (100%) rename {uncloud_django_based/uncloud/uncloud_net => uncloud_net}/apps.py (100%) rename {uncloud_django_based/uncloud/uncloud_net => uncloud_net}/management/commands/vpn.py (100%) rename {uncloud_django_based/uncloud/uncloud_net => uncloud_net}/migrations/0001_initial.py (100%) rename {uncloud_django_based/uncloud/uncloud_net => uncloud_net}/migrations/0002_auto_20200409_1225.py (100%) rename {uncloud_django_based/uncloud/uncloud_net => uncloud_net}/migrations/0003_auto_20200417_0551.py (100%) rename {uncloud_etcd_based/docs => uncloud_net/migrations}/__init__.py (100%) rename {uncloud_django_based/uncloud/uncloud_net => uncloud_net}/models.py (100%) rename {uncloud_django_based/uncloud/uncloud_net => uncloud_net}/serializers.py (100%) rename {uncloud_django_based/uncloud/uncloud_net => uncloud_net}/tests.py (100%) rename {uncloud_django_based/uncloud/uncloud_net => uncloud_net}/views.py (100%) rename {uncloud_etcd_based/docs/source => uncloud_pay}/__init__.py (100%) rename {uncloud_django_based/uncloud/uncloud_pay => uncloud_pay}/admin.py (100%) rename {uncloud_django_based/uncloud/uncloud_pay => uncloud_pay}/apps.py (100%) rename {uncloud_django_based/uncloud/uncloud_pay => uncloud_pay}/helpers.py (100%) rename {uncloud_django_based/uncloud/uncloud_pay => uncloud_pay}/management/commands/charge-negative-balance.py (100%) rename {uncloud_django_based/uncloud/uncloud_pay => uncloud_pay}/management/commands/generate-bills.py (100%) rename {uncloud_django_based/uncloud/uncloud_pay => uncloud_pay}/management/commands/handle-overdue-bills.py (100%) rename {uncloud_django_based/uncloud/uncloud_pay => uncloud_pay}/management/commands/import-vat-rates.py (100%) rename {uncloud_django_based/uncloud/uncloud_pay => uncloud_pay}/migrations/0001_initial.py (100%) rename {uncloud_django_based/uncloud/uncloud_pay => uncloud_pay}/migrations/0002_auto_20200305_1524.py (100%) rename {uncloud_django_based/uncloud/uncloud_pay => uncloud_pay}/migrations/0003_auto_20200305_1354.py (100%) rename {uncloud_django_based/uncloud/uncloud_pay => uncloud_pay}/migrations/0004_auto_20200409_1225.py (100%) rename {uncloud_django_based/uncloud/uncloud_pay => uncloud_pay}/migrations/0005_auto_20200413_0924.py (100%) rename {uncloud_django_based/uncloud/uncloud_pay => uncloud_pay}/migrations/0006_auto_20200415_1003.py (100%) rename {uncloud_django_based/uncloud/uncloud_pay => uncloud_pay}/migrations/0006_billingaddress.py (100%) rename {uncloud_django_based/uncloud/uncloud_pay => uncloud_pay}/migrations/0007_auto_20200418_0737.py (100%) rename {uncloud_django_based/uncloud/uncloud_pay => uncloud_pay}/migrations/0008_auto_20200502_1921.py (100%) rename {uncloud_django_based/uncloud/uncloud_pay => uncloud_pay}/migrations/0009_auto_20200502_2047.py (100%) rename {uncloud_django_based/uncloud/uncloud_pay => uncloud_pay}/migrations/0010_order_description.py (100%) rename {uncloud_etcd_based/test => uncloud_pay/migrations}/__init__.py (100%) rename {uncloud_django_based/uncloud/uncloud_pay => uncloud_pay}/models.py (100%) rename {uncloud_django_based/uncloud/uncloud_pay => uncloud_pay}/serializers.py (100%) rename {uncloud_django_based/uncloud/uncloud_pay => uncloud_pay}/stripe.py (100%) rename {uncloud_django_based/uncloud/uncloud_pay => uncloud_pay}/templates/bill.html (100%) rename {uncloud_django_based/uncloud/uncloud_pay => uncloud_pay}/templates/error.html.j2 (100%) rename {uncloud_django_based/uncloud/uncloud_pay => uncloud_pay}/templates/stripe-payment.html.j2 (100%) rename {uncloud_django_based/uncloud/uncloud_pay => uncloud_pay}/tests.py (100%) rename {uncloud_django_based/uncloud/uncloud_pay => uncloud_pay}/views.py (100%) rename {uncloud_etcd_based/uncloud/cli => uncloud_service}/__init__.py (100%) rename {uncloud_django_based/uncloud/uncloud_service => uncloud_service}/admin.py (100%) rename {uncloud_django_based/uncloud/uncloud_service => uncloud_service}/apps.py (100%) rename {uncloud_django_based/uncloud/uncloud_service => uncloud_service}/migrations/0001_initial.py (100%) rename {uncloud_django_based/uncloud/uncloud_service => uncloud_service}/migrations/0002_auto_20200418_0641.py (100%) rename {uncloud_etcd_based/uncloud/client => uncloud_service/migrations}/__init__.py (100%) rename {uncloud_django_based/uncloud/uncloud_service => uncloud_service}/models.py (100%) rename {uncloud_django_based/uncloud/uncloud_service => uncloud_service}/serializers.py (100%) rename {uncloud_django_based/uncloud/uncloud_service => uncloud_service}/tests.py (100%) rename {uncloud_django_based/uncloud/uncloud_service => uncloud_service}/views.py (100%) rename {uncloud_etcd_based/uncloud/configure => uncloud_storage}/__init__.py (100%) rename {uncloud_django_based/uncloud/uncloud_storage => uncloud_storage}/admin.py (100%) rename {uncloud_django_based/uncloud/uncloud_storage => uncloud_storage}/apps.py (100%) rename {uncloud_django_based/uncloud/uncloud_storage => uncloud_storage}/models.py (100%) rename {uncloud_django_based/uncloud/uncloud_storage => uncloud_storage}/tests.py (100%) rename {uncloud_django_based/uncloud/uncloud_storage => uncloud_storage}/views.py (100%) rename {uncloud_etcd_based/uncloud/network => uncloud_vm}/__init__.py (100%) rename {uncloud_django_based/uncloud/uncloud_vm => uncloud_vm}/admin.py (100%) rename {uncloud_django_based/uncloud/uncloud_vm => uncloud_vm}/apps.py (100%) rename {uncloud_django_based/uncloud/uncloud_vm => uncloud_vm}/management/commands/vm.py (100%) rename {uncloud_django_based/uncloud/uncloud_vm => uncloud_vm}/migrations/0001_initial.py (100%) rename {uncloud_django_based/uncloud/uncloud_vm => uncloud_vm}/migrations/0002_auto_20200305_1321.py (100%) rename {uncloud_django_based/uncloud/uncloud_vm => uncloud_vm}/migrations/0003_remove_vmhost_vms.py (100%) rename {uncloud_django_based/uncloud/uncloud_vm => uncloud_vm}/migrations/0004_remove_vmproduct_vmid.py (100%) rename {uncloud_django_based/uncloud/uncloud_vm => uncloud_vm}/migrations/0004_vmproduct_primary_disk.py (100%) rename {uncloud_django_based/uncloud/uncloud_vm => uncloud_vm}/migrations/0005_auto_20200309_1258.py (100%) rename {uncloud_django_based/uncloud/uncloud_vm => uncloud_vm}/migrations/0005_auto_20200321_1058.py (100%) rename {uncloud_django_based/uncloud/uncloud_vm => uncloud_vm}/migrations/0006_auto_20200322_1758.py (100%) rename {uncloud_django_based/uncloud/uncloud_vm => uncloud_vm}/migrations/0007_vmhost_vmcluster.py (100%) rename {uncloud_django_based/uncloud/uncloud_vm => uncloud_vm}/migrations/0008_auto_20200403_1727.py (100%) rename {uncloud_django_based/uncloud/uncloud_vm => uncloud_vm}/migrations/0009_auto_20200417_0551.py (100%) rename {uncloud_django_based/uncloud/uncloud_vm => uncloud_vm}/migrations/0009_merge_20200413_0857.py (100%) rename {uncloud_django_based/uncloud/uncloud_vm => uncloud_vm}/migrations/0010_auto_20200413_0924.py (100%) rename {uncloud_django_based/uncloud/uncloud_vm => uncloud_vm}/migrations/0011_merge_20200418_0641.py (100%) rename {uncloud_django_based/uncloud/uncloud_vm => uncloud_vm}/migrations/0012_auto_20200418_0641.py (100%) rename {uncloud_django_based/uncloud/uncloud_vm => uncloud_vm}/migrations/0013_remove_vmproduct_primary_disk.py (100%) rename {uncloud_etcd_based/uncloud/scheduler/tests => uncloud_vm/migrations}/__init__.py (100%) rename {uncloud_django_based/uncloud/uncloud_vm => uncloud_vm}/models.py (100%) rename {uncloud_django_based/uncloud/uncloud_vm => uncloud_vm}/serializers.py (100%) rename {uncloud_django_based/uncloud/uncloud_vm => uncloud_vm}/tests.py (100%) rename {uncloud_django_based/uncloud/uncloud_vm => uncloud_vm}/views.py (100%) diff --git a/issues.org b/archive/issues.org similarity index 100% rename from issues.org rename to archive/issues.org diff --git a/uncloud_django_based/hacks/abk-hacks.py b/archive/uncloud_django_based/hacks/abk-hacks.py similarity index 100% rename from uncloud_django_based/hacks/abk-hacks.py rename to archive/uncloud_django_based/hacks/abk-hacks.py diff --git a/uncloud_django_based/hacks/abkhack/opennebula_hacks.py b/archive/uncloud_django_based/hacks/abkhack/opennebula_hacks.py similarity index 100% rename from uncloud_django_based/hacks/abkhack/opennebula_hacks.py rename to archive/uncloud_django_based/hacks/abkhack/opennebula_hacks.py diff --git a/uncloud_django_based/hacks/command-wrapper.sh b/archive/uncloud_django_based/hacks/command-wrapper.sh similarity index 100% rename from uncloud_django_based/hacks/command-wrapper.sh rename to archive/uncloud_django_based/hacks/command-wrapper.sh diff --git a/uncloud_django_based/meow-payv1/README.md b/archive/uncloud_django_based/meow-payv1/README.md similarity index 100% rename from uncloud_django_based/meow-payv1/README.md rename to archive/uncloud_django_based/meow-payv1/README.md diff --git a/uncloud_django_based/meow-payv1/config.py b/archive/uncloud_django_based/meow-payv1/config.py similarity index 100% rename from uncloud_django_based/meow-payv1/config.py rename to archive/uncloud_django_based/meow-payv1/config.py diff --git a/uncloud_django_based/meow-payv1/hack-a-vpn.py b/archive/uncloud_django_based/meow-payv1/hack-a-vpn.py similarity index 100% rename from uncloud_django_based/meow-payv1/hack-a-vpn.py rename to archive/uncloud_django_based/meow-payv1/hack-a-vpn.py diff --git a/uncloud_django_based/meow-payv1/helper.py b/archive/uncloud_django_based/meow-payv1/helper.py similarity index 100% rename from uncloud_django_based/meow-payv1/helper.py rename to archive/uncloud_django_based/meow-payv1/helper.py diff --git a/uncloud_django_based/meow-payv1/products/ipv6-only-django.json b/archive/uncloud_django_based/meow-payv1/products/ipv6-only-django.json similarity index 100% rename from uncloud_django_based/meow-payv1/products/ipv6-only-django.json rename to archive/uncloud_django_based/meow-payv1/products/ipv6-only-django.json diff --git a/uncloud_django_based/meow-payv1/products/ipv6-only-vm.json b/archive/uncloud_django_based/meow-payv1/products/ipv6-only-vm.json similarity index 100% rename from uncloud_django_based/meow-payv1/products/ipv6-only-vm.json rename to archive/uncloud_django_based/meow-payv1/products/ipv6-only-vm.json diff --git a/uncloud_django_based/meow-payv1/products/ipv6-only-vpn.json b/archive/uncloud_django_based/meow-payv1/products/ipv6-only-vpn.json similarity index 100% rename from uncloud_django_based/meow-payv1/products/ipv6-only-vpn.json rename to archive/uncloud_django_based/meow-payv1/products/ipv6-only-vpn.json diff --git a/uncloud_django_based/meow-payv1/products/ipv6box.json b/archive/uncloud_django_based/meow-payv1/products/ipv6box.json similarity index 100% rename from uncloud_django_based/meow-payv1/products/ipv6box.json rename to archive/uncloud_django_based/meow-payv1/products/ipv6box.json diff --git a/uncloud_django_based/meow-payv1/products/membership.json b/archive/uncloud_django_based/meow-payv1/products/membership.json similarity index 100% rename from uncloud_django_based/meow-payv1/products/membership.json rename to archive/uncloud_django_based/meow-payv1/products/membership.json diff --git a/uncloud_django_based/meow-payv1/requirements.txt b/archive/uncloud_django_based/meow-payv1/requirements.txt similarity index 100% rename from uncloud_django_based/meow-payv1/requirements.txt rename to archive/uncloud_django_based/meow-payv1/requirements.txt diff --git a/uncloud_django_based/meow-payv1/sample-pay.conf b/archive/uncloud_django_based/meow-payv1/sample-pay.conf similarity index 100% rename from uncloud_django_based/meow-payv1/sample-pay.conf rename to archive/uncloud_django_based/meow-payv1/sample-pay.conf diff --git a/uncloud_django_based/meow-payv1/schemas.py b/archive/uncloud_django_based/meow-payv1/schemas.py similarity index 100% rename from uncloud_django_based/meow-payv1/schemas.py rename to archive/uncloud_django_based/meow-payv1/schemas.py diff --git a/uncloud_django_based/meow-payv1/stripe_hack.py b/archive/uncloud_django_based/meow-payv1/stripe_hack.py similarity index 100% rename from uncloud_django_based/meow-payv1/stripe_hack.py rename to archive/uncloud_django_based/meow-payv1/stripe_hack.py diff --git a/uncloud_django_based/meow-payv1/stripe_utils.py b/archive/uncloud_django_based/meow-payv1/stripe_utils.py similarity index 100% rename from uncloud_django_based/meow-payv1/stripe_utils.py rename to archive/uncloud_django_based/meow-payv1/stripe_utils.py diff --git a/uncloud_django_based/meow-payv1/ucloud_pay.py b/archive/uncloud_django_based/meow-payv1/ucloud_pay.py similarity index 100% rename from uncloud_django_based/meow-payv1/ucloud_pay.py rename to archive/uncloud_django_based/meow-payv1/ucloud_pay.py diff --git a/uncloud_django_based/notes-abk.md b/archive/uncloud_django_based/notes-abk.md similarity index 100% rename from uncloud_django_based/notes-abk.md rename to archive/uncloud_django_based/notes-abk.md diff --git a/uncloud_django_based/notes-nico.org b/archive/uncloud_django_based/notes-nico.org similarity index 100% rename from uncloud_django_based/notes-nico.org rename to archive/uncloud_django_based/notes-nico.org diff --git a/uncloud_django_based/plan.org b/archive/uncloud_django_based/plan.org similarity index 100% rename from uncloud_django_based/plan.org rename to archive/uncloud_django_based/plan.org diff --git a/uncloud_django_based/uncloud/.gitignore b/archive/uncloud_django_based/uncloud/.gitignore similarity index 100% rename from uncloud_django_based/uncloud/.gitignore rename to archive/uncloud_django_based/uncloud/.gitignore diff --git a/uncloud_django_based/vat_rates.csv b/archive/uncloud_django_based/vat_rates.csv similarity index 100% rename from uncloud_django_based/vat_rates.csv rename to archive/uncloud_django_based/vat_rates.csv diff --git a/uncloud_etcd_based/bin/gen-version b/archive/uncloud_etcd_based/bin/gen-version similarity index 100% rename from uncloud_etcd_based/bin/gen-version rename to archive/uncloud_etcd_based/bin/gen-version diff --git a/uncloud_etcd_based/bin/uncloud b/archive/uncloud_etcd_based/bin/uncloud similarity index 100% rename from uncloud_etcd_based/bin/uncloud rename to archive/uncloud_etcd_based/bin/uncloud diff --git a/uncloud_etcd_based/bin/uncloud-run-reinstall b/archive/uncloud_etcd_based/bin/uncloud-run-reinstall similarity index 100% rename from uncloud_etcd_based/bin/uncloud-run-reinstall rename to archive/uncloud_etcd_based/bin/uncloud-run-reinstall diff --git a/uncloud_etcd_based/conf/uncloud.conf b/archive/uncloud_etcd_based/conf/uncloud.conf similarity index 100% rename from uncloud_etcd_based/conf/uncloud.conf rename to archive/uncloud_etcd_based/conf/uncloud.conf diff --git a/uncloud_etcd_based/docs/Makefile b/archive/uncloud_etcd_based/docs/Makefile similarity index 100% rename from uncloud_etcd_based/docs/Makefile rename to archive/uncloud_etcd_based/docs/Makefile diff --git a/uncloud_etcd_based/docs/README.md b/archive/uncloud_etcd_based/docs/README.md similarity index 100% rename from uncloud_etcd_based/docs/README.md rename to archive/uncloud_etcd_based/docs/README.md diff --git a/uncloud_django_based/uncloud/opennebula/__init__.py b/archive/uncloud_etcd_based/docs/__init__.py similarity index 100% rename from uncloud_django_based/uncloud/opennebula/__init__.py rename to archive/uncloud_etcd_based/docs/__init__.py diff --git a/uncloud_django_based/uncloud/opennebula/migrations/__init__.py b/archive/uncloud_etcd_based/docs/source/__init__.py similarity index 100% rename from uncloud_django_based/uncloud/opennebula/migrations/__init__.py rename to archive/uncloud_etcd_based/docs/source/__init__.py diff --git a/uncloud_etcd_based/docs/source/admin-guide.rst b/archive/uncloud_etcd_based/docs/source/admin-guide.rst similarity index 100% rename from uncloud_etcd_based/docs/source/admin-guide.rst rename to archive/uncloud_etcd_based/docs/source/admin-guide.rst diff --git a/uncloud_etcd_based/docs/source/conf.py b/archive/uncloud_etcd_based/docs/source/conf.py similarity index 100% rename from uncloud_etcd_based/docs/source/conf.py rename to archive/uncloud_etcd_based/docs/source/conf.py diff --git a/uncloud_etcd_based/docs/source/diagram-code/ucloud b/archive/uncloud_etcd_based/docs/source/diagram-code/ucloud similarity index 100% rename from uncloud_etcd_based/docs/source/diagram-code/ucloud rename to archive/uncloud_etcd_based/docs/source/diagram-code/ucloud diff --git a/uncloud_etcd_based/docs/source/hacking.rst b/archive/uncloud_etcd_based/docs/source/hacking.rst similarity index 100% rename from uncloud_etcd_based/docs/source/hacking.rst rename to archive/uncloud_etcd_based/docs/source/hacking.rst diff --git a/uncloud_etcd_based/docs/source/images/ucloud.svg b/archive/uncloud_etcd_based/docs/source/images/ucloud.svg similarity index 100% rename from uncloud_etcd_based/docs/source/images/ucloud.svg rename to archive/uncloud_etcd_based/docs/source/images/ucloud.svg diff --git a/uncloud_etcd_based/docs/source/index.rst b/archive/uncloud_etcd_based/docs/source/index.rst similarity index 100% rename from uncloud_etcd_based/docs/source/index.rst rename to archive/uncloud_etcd_based/docs/source/index.rst diff --git a/uncloud_etcd_based/docs/source/introduction.rst b/archive/uncloud_etcd_based/docs/source/introduction.rst similarity index 100% rename from uncloud_etcd_based/docs/source/introduction.rst rename to archive/uncloud_etcd_based/docs/source/introduction.rst diff --git a/uncloud_etcd_based/docs/source/misc/todo.rst b/archive/uncloud_etcd_based/docs/source/misc/todo.rst similarity index 100% rename from uncloud_etcd_based/docs/source/misc/todo.rst rename to archive/uncloud_etcd_based/docs/source/misc/todo.rst diff --git a/uncloud_etcd_based/docs/source/setup-install.rst b/archive/uncloud_etcd_based/docs/source/setup-install.rst similarity index 100% rename from uncloud_etcd_based/docs/source/setup-install.rst rename to archive/uncloud_etcd_based/docs/source/setup-install.rst diff --git a/uncloud_etcd_based/docs/source/theory/summary.rst b/archive/uncloud_etcd_based/docs/source/theory/summary.rst similarity index 100% rename from uncloud_etcd_based/docs/source/theory/summary.rst rename to archive/uncloud_etcd_based/docs/source/theory/summary.rst diff --git a/uncloud_etcd_based/docs/source/troubleshooting.rst b/archive/uncloud_etcd_based/docs/source/troubleshooting.rst similarity index 100% rename from uncloud_etcd_based/docs/source/troubleshooting.rst rename to archive/uncloud_etcd_based/docs/source/troubleshooting.rst diff --git a/uncloud_etcd_based/docs/source/user-guide.rst b/archive/uncloud_etcd_based/docs/source/user-guide.rst similarity index 100% rename from uncloud_etcd_based/docs/source/user-guide.rst rename to archive/uncloud_etcd_based/docs/source/user-guide.rst diff --git a/uncloud_etcd_based/docs/source/user-guide/how-to-create-an-os-image-for-ucloud.rst b/archive/uncloud_etcd_based/docs/source/user-guide/how-to-create-an-os-image-for-ucloud.rst similarity index 100% rename from uncloud_etcd_based/docs/source/user-guide/how-to-create-an-os-image-for-ucloud.rst rename to archive/uncloud_etcd_based/docs/source/user-guide/how-to-create-an-os-image-for-ucloud.rst diff --git a/uncloud_etcd_based/docs/source/vm-images.rst b/archive/uncloud_etcd_based/docs/source/vm-images.rst similarity index 100% rename from uncloud_etcd_based/docs/source/vm-images.rst rename to archive/uncloud_etcd_based/docs/source/vm-images.rst diff --git a/uncloud_etcd_based/scripts/uncloud b/archive/uncloud_etcd_based/scripts/uncloud similarity index 100% rename from uncloud_etcd_based/scripts/uncloud rename to archive/uncloud_etcd_based/scripts/uncloud diff --git a/uncloud_etcd_based/setup.py b/archive/uncloud_etcd_based/setup.py similarity index 100% rename from uncloud_etcd_based/setup.py rename to archive/uncloud_etcd_based/setup.py diff --git a/uncloud_django_based/uncloud/uncloud_auth/__init__.py b/archive/uncloud_etcd_based/test/__init__.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_auth/__init__.py rename to archive/uncloud_etcd_based/test/__init__.py diff --git a/uncloud_etcd_based/test/test_mac_local.py b/archive/uncloud_etcd_based/test/test_mac_local.py similarity index 100% rename from uncloud_etcd_based/test/test_mac_local.py rename to archive/uncloud_etcd_based/test/test_mac_local.py diff --git a/uncloud_etcd_based/uncloud/__init__.py b/archive/uncloud_etcd_based/uncloud/__init__.py similarity index 100% rename from uncloud_etcd_based/uncloud/__init__.py rename to archive/uncloud_etcd_based/uncloud/__init__.py diff --git a/uncloud_etcd_based/uncloud/api/README.md b/archive/uncloud_etcd_based/uncloud/api/README.md similarity index 100% rename from uncloud_etcd_based/uncloud/api/README.md rename to archive/uncloud_etcd_based/uncloud/api/README.md diff --git a/uncloud_etcd_based/uncloud/api/__init__.py b/archive/uncloud_etcd_based/uncloud/api/__init__.py similarity index 100% rename from uncloud_etcd_based/uncloud/api/__init__.py rename to archive/uncloud_etcd_based/uncloud/api/__init__.py diff --git a/uncloud_etcd_based/uncloud/api/common_fields.py b/archive/uncloud_etcd_based/uncloud/api/common_fields.py similarity index 100% rename from uncloud_etcd_based/uncloud/api/common_fields.py rename to archive/uncloud_etcd_based/uncloud/api/common_fields.py diff --git a/uncloud_etcd_based/uncloud/api/create_image_store.py b/archive/uncloud_etcd_based/uncloud/api/create_image_store.py similarity index 100% rename from uncloud_etcd_based/uncloud/api/create_image_store.py rename to archive/uncloud_etcd_based/uncloud/api/create_image_store.py diff --git a/uncloud_etcd_based/uncloud/api/helper.py b/archive/uncloud_etcd_based/uncloud/api/helper.py similarity index 100% rename from uncloud_etcd_based/uncloud/api/helper.py rename to archive/uncloud_etcd_based/uncloud/api/helper.py diff --git a/uncloud_etcd_based/uncloud/api/main.py b/archive/uncloud_etcd_based/uncloud/api/main.py similarity index 100% rename from uncloud_etcd_based/uncloud/api/main.py rename to archive/uncloud_etcd_based/uncloud/api/main.py diff --git a/uncloud_etcd_based/uncloud/api/schemas.py b/archive/uncloud_etcd_based/uncloud/api/schemas.py similarity index 100% rename from uncloud_etcd_based/uncloud/api/schemas.py rename to archive/uncloud_etcd_based/uncloud/api/schemas.py diff --git a/uncloud_django_based/uncloud/uncloud_auth/migrations/__init__.py b/archive/uncloud_etcd_based/uncloud/cli/__init__.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_auth/migrations/__init__.py rename to archive/uncloud_etcd_based/uncloud/cli/__init__.py diff --git a/uncloud_etcd_based/uncloud/cli/helper.py b/archive/uncloud_etcd_based/uncloud/cli/helper.py similarity index 100% rename from uncloud_etcd_based/uncloud/cli/helper.py rename to archive/uncloud_etcd_based/uncloud/cli/helper.py diff --git a/uncloud_etcd_based/uncloud/cli/host.py b/archive/uncloud_etcd_based/uncloud/cli/host.py similarity index 100% rename from uncloud_etcd_based/uncloud/cli/host.py rename to archive/uncloud_etcd_based/uncloud/cli/host.py diff --git a/uncloud_etcd_based/uncloud/cli/image.py b/archive/uncloud_etcd_based/uncloud/cli/image.py similarity index 100% rename from uncloud_etcd_based/uncloud/cli/image.py rename to archive/uncloud_etcd_based/uncloud/cli/image.py diff --git a/uncloud_etcd_based/uncloud/cli/main.py b/archive/uncloud_etcd_based/uncloud/cli/main.py similarity index 100% rename from uncloud_etcd_based/uncloud/cli/main.py rename to archive/uncloud_etcd_based/uncloud/cli/main.py diff --git a/uncloud_etcd_based/uncloud/cli/network.py b/archive/uncloud_etcd_based/uncloud/cli/network.py similarity index 100% rename from uncloud_etcd_based/uncloud/cli/network.py rename to archive/uncloud_etcd_based/uncloud/cli/network.py diff --git a/uncloud_etcd_based/uncloud/cli/user.py b/archive/uncloud_etcd_based/uncloud/cli/user.py similarity index 100% rename from uncloud_etcd_based/uncloud/cli/user.py rename to archive/uncloud_etcd_based/uncloud/cli/user.py diff --git a/uncloud_etcd_based/uncloud/cli/vm.py b/archive/uncloud_etcd_based/uncloud/cli/vm.py similarity index 100% rename from uncloud_etcd_based/uncloud/cli/vm.py rename to archive/uncloud_etcd_based/uncloud/cli/vm.py diff --git a/uncloud_django_based/uncloud/uncloud_net/__init__.py b/archive/uncloud_etcd_based/uncloud/client/__init__.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_net/__init__.py rename to archive/uncloud_etcd_based/uncloud/client/__init__.py diff --git a/uncloud_etcd_based/uncloud/client/main.py b/archive/uncloud_etcd_based/uncloud/client/main.py similarity index 100% rename from uncloud_etcd_based/uncloud/client/main.py rename to archive/uncloud_etcd_based/uncloud/client/main.py diff --git a/uncloud_etcd_based/uncloud/common/__init__.py b/archive/uncloud_etcd_based/uncloud/common/__init__.py similarity index 100% rename from uncloud_etcd_based/uncloud/common/__init__.py rename to archive/uncloud_etcd_based/uncloud/common/__init__.py diff --git a/uncloud_etcd_based/uncloud/common/classes.py b/archive/uncloud_etcd_based/uncloud/common/classes.py similarity index 100% rename from uncloud_etcd_based/uncloud/common/classes.py rename to archive/uncloud_etcd_based/uncloud/common/classes.py diff --git a/uncloud_etcd_based/uncloud/common/cli.py b/archive/uncloud_etcd_based/uncloud/common/cli.py similarity index 100% rename from uncloud_etcd_based/uncloud/common/cli.py rename to archive/uncloud_etcd_based/uncloud/common/cli.py diff --git a/uncloud_etcd_based/uncloud/common/counters.py b/archive/uncloud_etcd_based/uncloud/common/counters.py similarity index 100% rename from uncloud_etcd_based/uncloud/common/counters.py rename to archive/uncloud_etcd_based/uncloud/common/counters.py diff --git a/uncloud_etcd_based/uncloud/common/etcd_wrapper.py b/archive/uncloud_etcd_based/uncloud/common/etcd_wrapper.py similarity index 100% rename from uncloud_etcd_based/uncloud/common/etcd_wrapper.py rename to archive/uncloud_etcd_based/uncloud/common/etcd_wrapper.py diff --git a/uncloud_etcd_based/uncloud/common/host.py b/archive/uncloud_etcd_based/uncloud/common/host.py similarity index 100% rename from uncloud_etcd_based/uncloud/common/host.py rename to archive/uncloud_etcd_based/uncloud/common/host.py diff --git a/uncloud_etcd_based/uncloud/common/network.py b/archive/uncloud_etcd_based/uncloud/common/network.py similarity index 100% rename from uncloud_etcd_based/uncloud/common/network.py rename to archive/uncloud_etcd_based/uncloud/common/network.py diff --git a/uncloud_etcd_based/uncloud/common/parser.py b/archive/uncloud_etcd_based/uncloud/common/parser.py similarity index 100% rename from uncloud_etcd_based/uncloud/common/parser.py rename to archive/uncloud_etcd_based/uncloud/common/parser.py diff --git a/uncloud_etcd_based/uncloud/common/request.py b/archive/uncloud_etcd_based/uncloud/common/request.py similarity index 100% rename from uncloud_etcd_based/uncloud/common/request.py rename to archive/uncloud_etcd_based/uncloud/common/request.py diff --git a/uncloud_etcd_based/uncloud/common/schemas.py b/archive/uncloud_etcd_based/uncloud/common/schemas.py similarity index 100% rename from uncloud_etcd_based/uncloud/common/schemas.py rename to archive/uncloud_etcd_based/uncloud/common/schemas.py diff --git a/uncloud_etcd_based/uncloud/common/settings.py b/archive/uncloud_etcd_based/uncloud/common/settings.py similarity index 100% rename from uncloud_etcd_based/uncloud/common/settings.py rename to archive/uncloud_etcd_based/uncloud/common/settings.py diff --git a/uncloud_etcd_based/uncloud/common/shared.py b/archive/uncloud_etcd_based/uncloud/common/shared.py similarity index 100% rename from uncloud_etcd_based/uncloud/common/shared.py rename to archive/uncloud_etcd_based/uncloud/common/shared.py diff --git a/uncloud_etcd_based/uncloud/common/storage_handlers.py b/archive/uncloud_etcd_based/uncloud/common/storage_handlers.py similarity index 100% rename from uncloud_etcd_based/uncloud/common/storage_handlers.py rename to archive/uncloud_etcd_based/uncloud/common/storage_handlers.py diff --git a/uncloud_etcd_based/uncloud/common/vm.py b/archive/uncloud_etcd_based/uncloud/common/vm.py similarity index 100% rename from uncloud_etcd_based/uncloud/common/vm.py rename to archive/uncloud_etcd_based/uncloud/common/vm.py diff --git a/uncloud_django_based/uncloud/uncloud_net/migrations/__init__.py b/archive/uncloud_etcd_based/uncloud/configure/__init__.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_net/migrations/__init__.py rename to archive/uncloud_etcd_based/uncloud/configure/__init__.py diff --git a/uncloud_etcd_based/uncloud/configure/main.py b/archive/uncloud_etcd_based/uncloud/configure/main.py similarity index 100% rename from uncloud_etcd_based/uncloud/configure/main.py rename to archive/uncloud_etcd_based/uncloud/configure/main.py diff --git a/uncloud_etcd_based/uncloud/filescanner/__init__.py b/archive/uncloud_etcd_based/uncloud/filescanner/__init__.py similarity index 100% rename from uncloud_etcd_based/uncloud/filescanner/__init__.py rename to archive/uncloud_etcd_based/uncloud/filescanner/__init__.py diff --git a/uncloud_etcd_based/uncloud/filescanner/main.py b/archive/uncloud_etcd_based/uncloud/filescanner/main.py similarity index 100% rename from uncloud_etcd_based/uncloud/filescanner/main.py rename to archive/uncloud_etcd_based/uncloud/filescanner/main.py diff --git a/uncloud_etcd_based/uncloud/hack/README.org b/archive/uncloud_etcd_based/uncloud/hack/README.org similarity index 100% rename from uncloud_etcd_based/uncloud/hack/README.org rename to archive/uncloud_etcd_based/uncloud/hack/README.org diff --git a/uncloud_etcd_based/uncloud/hack/__init__.py b/archive/uncloud_etcd_based/uncloud/hack/__init__.py similarity index 100% rename from uncloud_etcd_based/uncloud/hack/__init__.py rename to archive/uncloud_etcd_based/uncloud/hack/__init__.py diff --git a/uncloud_etcd_based/uncloud/hack/conf.d/ucloud-host b/archive/uncloud_etcd_based/uncloud/hack/conf.d/ucloud-host similarity index 100% rename from uncloud_etcd_based/uncloud/hack/conf.d/ucloud-host rename to archive/uncloud_etcd_based/uncloud/hack/conf.d/ucloud-host diff --git a/uncloud_etcd_based/uncloud/hack/config.py b/archive/uncloud_etcd_based/uncloud/hack/config.py similarity index 100% rename from uncloud_etcd_based/uncloud/hack/config.py rename to archive/uncloud_etcd_based/uncloud/hack/config.py diff --git a/uncloud_etcd_based/uncloud/hack/db.py b/archive/uncloud_etcd_based/uncloud/hack/db.py similarity index 100% rename from uncloud_etcd_based/uncloud/hack/db.py rename to archive/uncloud_etcd_based/uncloud/hack/db.py diff --git a/uncloud_etcd_based/uncloud/hack/hackcloud/.gitignore b/archive/uncloud_etcd_based/uncloud/hack/hackcloud/.gitignore similarity index 100% rename from uncloud_etcd_based/uncloud/hack/hackcloud/.gitignore rename to archive/uncloud_etcd_based/uncloud/hack/hackcloud/.gitignore diff --git a/uncloud_etcd_based/uncloud/hack/hackcloud/__init__.py b/archive/uncloud_etcd_based/uncloud/hack/hackcloud/__init__.py similarity index 100% rename from uncloud_etcd_based/uncloud/hack/hackcloud/__init__.py rename to archive/uncloud_etcd_based/uncloud/hack/hackcloud/__init__.py diff --git a/uncloud_etcd_based/uncloud/hack/hackcloud/etcd-client.sh b/archive/uncloud_etcd_based/uncloud/hack/hackcloud/etcd-client.sh similarity index 100% rename from uncloud_etcd_based/uncloud/hack/hackcloud/etcd-client.sh rename to archive/uncloud_etcd_based/uncloud/hack/hackcloud/etcd-client.sh diff --git a/uncloud_etcd_based/uncloud/hack/hackcloud/ifdown.sh b/archive/uncloud_etcd_based/uncloud/hack/hackcloud/ifdown.sh similarity index 100% rename from uncloud_etcd_based/uncloud/hack/hackcloud/ifdown.sh rename to archive/uncloud_etcd_based/uncloud/hack/hackcloud/ifdown.sh diff --git a/uncloud_etcd_based/uncloud/hack/hackcloud/ifup.sh b/archive/uncloud_etcd_based/uncloud/hack/hackcloud/ifup.sh similarity index 100% rename from uncloud_etcd_based/uncloud/hack/hackcloud/ifup.sh rename to archive/uncloud_etcd_based/uncloud/hack/hackcloud/ifup.sh diff --git a/uncloud_etcd_based/uncloud/hack/hackcloud/mac-last b/archive/uncloud_etcd_based/uncloud/hack/hackcloud/mac-last similarity index 100% rename from uncloud_etcd_based/uncloud/hack/hackcloud/mac-last rename to archive/uncloud_etcd_based/uncloud/hack/hackcloud/mac-last diff --git a/uncloud_etcd_based/uncloud/hack/hackcloud/mac-prefix b/archive/uncloud_etcd_based/uncloud/hack/hackcloud/mac-prefix similarity index 100% rename from uncloud_etcd_based/uncloud/hack/hackcloud/mac-prefix rename to archive/uncloud_etcd_based/uncloud/hack/hackcloud/mac-prefix diff --git a/uncloud_etcd_based/uncloud/hack/hackcloud/net.sh b/archive/uncloud_etcd_based/uncloud/hack/hackcloud/net.sh similarity index 100% rename from uncloud_etcd_based/uncloud/hack/hackcloud/net.sh rename to archive/uncloud_etcd_based/uncloud/hack/hackcloud/net.sh diff --git a/uncloud_etcd_based/uncloud/hack/hackcloud/nftrules b/archive/uncloud_etcd_based/uncloud/hack/hackcloud/nftrules similarity index 100% rename from uncloud_etcd_based/uncloud/hack/hackcloud/nftrules rename to archive/uncloud_etcd_based/uncloud/hack/hackcloud/nftrules diff --git a/uncloud_etcd_based/uncloud/hack/hackcloud/radvd.conf b/archive/uncloud_etcd_based/uncloud/hack/hackcloud/radvd.conf similarity index 100% rename from uncloud_etcd_based/uncloud/hack/hackcloud/radvd.conf rename to archive/uncloud_etcd_based/uncloud/hack/hackcloud/radvd.conf diff --git a/uncloud_etcd_based/uncloud/hack/hackcloud/radvd.sh b/archive/uncloud_etcd_based/uncloud/hack/hackcloud/radvd.sh similarity index 100% rename from uncloud_etcd_based/uncloud/hack/hackcloud/radvd.sh rename to archive/uncloud_etcd_based/uncloud/hack/hackcloud/radvd.sh diff --git a/uncloud_etcd_based/uncloud/hack/hackcloud/vm.sh b/archive/uncloud_etcd_based/uncloud/hack/hackcloud/vm.sh similarity index 100% rename from uncloud_etcd_based/uncloud/hack/hackcloud/vm.sh rename to archive/uncloud_etcd_based/uncloud/hack/hackcloud/vm.sh diff --git a/uncloud_etcd_based/uncloud/hack/host.py b/archive/uncloud_etcd_based/uncloud/hack/host.py similarity index 100% rename from uncloud_etcd_based/uncloud/hack/host.py rename to archive/uncloud_etcd_based/uncloud/hack/host.py diff --git a/uncloud_etcd_based/uncloud/hack/mac.py b/archive/uncloud_etcd_based/uncloud/hack/mac.py similarity index 100% rename from uncloud_etcd_based/uncloud/hack/mac.py rename to archive/uncloud_etcd_based/uncloud/hack/mac.py diff --git a/uncloud_etcd_based/uncloud/hack/main.py b/archive/uncloud_etcd_based/uncloud/hack/main.py similarity index 100% rename from uncloud_etcd_based/uncloud/hack/main.py rename to archive/uncloud_etcd_based/uncloud/hack/main.py diff --git a/uncloud_etcd_based/uncloud/hack/net.py b/archive/uncloud_etcd_based/uncloud/hack/net.py similarity index 100% rename from uncloud_etcd_based/uncloud/hack/net.py rename to archive/uncloud_etcd_based/uncloud/hack/net.py diff --git a/uncloud_etcd_based/uncloud/hack/nftables.conf b/archive/uncloud_etcd_based/uncloud/hack/nftables.conf similarity index 100% rename from uncloud_etcd_based/uncloud/hack/nftables.conf rename to archive/uncloud_etcd_based/uncloud/hack/nftables.conf diff --git a/uncloud_etcd_based/uncloud/hack/product.py b/archive/uncloud_etcd_based/uncloud/hack/product.py similarity index 100% rename from uncloud_etcd_based/uncloud/hack/product.py rename to archive/uncloud_etcd_based/uncloud/hack/product.py diff --git a/uncloud_etcd_based/uncloud/hack/rc-scripts/ucloud-api b/archive/uncloud_etcd_based/uncloud/hack/rc-scripts/ucloud-api similarity index 100% rename from uncloud_etcd_based/uncloud/hack/rc-scripts/ucloud-api rename to archive/uncloud_etcd_based/uncloud/hack/rc-scripts/ucloud-api diff --git a/uncloud_etcd_based/uncloud/hack/rc-scripts/ucloud-host b/archive/uncloud_etcd_based/uncloud/hack/rc-scripts/ucloud-host similarity index 100% rename from uncloud_etcd_based/uncloud/hack/rc-scripts/ucloud-host rename to archive/uncloud_etcd_based/uncloud/hack/rc-scripts/ucloud-host diff --git a/uncloud_etcd_based/uncloud/hack/rc-scripts/ucloud-metadata b/archive/uncloud_etcd_based/uncloud/hack/rc-scripts/ucloud-metadata similarity index 100% rename from uncloud_etcd_based/uncloud/hack/rc-scripts/ucloud-metadata rename to archive/uncloud_etcd_based/uncloud/hack/rc-scripts/ucloud-metadata diff --git a/uncloud_etcd_based/uncloud/hack/rc-scripts/ucloud-scheduler b/archive/uncloud_etcd_based/uncloud/hack/rc-scripts/ucloud-scheduler similarity index 100% rename from uncloud_etcd_based/uncloud/hack/rc-scripts/ucloud-scheduler rename to archive/uncloud_etcd_based/uncloud/hack/rc-scripts/ucloud-scheduler diff --git a/uncloud_etcd_based/uncloud/hack/uncloud-hack-init-host b/archive/uncloud_etcd_based/uncloud/hack/uncloud-hack-init-host similarity index 100% rename from uncloud_etcd_based/uncloud/hack/uncloud-hack-init-host rename to archive/uncloud_etcd_based/uncloud/hack/uncloud-hack-init-host diff --git a/uncloud_etcd_based/uncloud/hack/uncloud-run-vm b/archive/uncloud_etcd_based/uncloud/hack/uncloud-run-vm similarity index 100% rename from uncloud_etcd_based/uncloud/hack/uncloud-run-vm rename to archive/uncloud_etcd_based/uncloud/hack/uncloud-run-vm diff --git a/uncloud_etcd_based/uncloud/hack/vm.py b/archive/uncloud_etcd_based/uncloud/hack/vm.py similarity index 100% rename from uncloud_etcd_based/uncloud/hack/vm.py rename to archive/uncloud_etcd_based/uncloud/hack/vm.py diff --git a/uncloud_etcd_based/uncloud/host/__init__.py b/archive/uncloud_etcd_based/uncloud/host/__init__.py similarity index 100% rename from uncloud_etcd_based/uncloud/host/__init__.py rename to archive/uncloud_etcd_based/uncloud/host/__init__.py diff --git a/uncloud_etcd_based/uncloud/host/main.py b/archive/uncloud_etcd_based/uncloud/host/main.py similarity index 100% rename from uncloud_etcd_based/uncloud/host/main.py rename to archive/uncloud_etcd_based/uncloud/host/main.py diff --git a/uncloud_etcd_based/uncloud/host/virtualmachine.py b/archive/uncloud_etcd_based/uncloud/host/virtualmachine.py similarity index 100% rename from uncloud_etcd_based/uncloud/host/virtualmachine.py rename to archive/uncloud_etcd_based/uncloud/host/virtualmachine.py diff --git a/uncloud_etcd_based/uncloud/imagescanner/__init__.py b/archive/uncloud_etcd_based/uncloud/imagescanner/__init__.py similarity index 100% rename from uncloud_etcd_based/uncloud/imagescanner/__init__.py rename to archive/uncloud_etcd_based/uncloud/imagescanner/__init__.py diff --git a/uncloud_etcd_based/uncloud/imagescanner/main.py b/archive/uncloud_etcd_based/uncloud/imagescanner/main.py similarity index 100% rename from uncloud_etcd_based/uncloud/imagescanner/main.py rename to archive/uncloud_etcd_based/uncloud/imagescanner/main.py diff --git a/uncloud_etcd_based/uncloud/metadata/__init__.py b/archive/uncloud_etcd_based/uncloud/metadata/__init__.py similarity index 100% rename from uncloud_etcd_based/uncloud/metadata/__init__.py rename to archive/uncloud_etcd_based/uncloud/metadata/__init__.py diff --git a/uncloud_etcd_based/uncloud/metadata/main.py b/archive/uncloud_etcd_based/uncloud/metadata/main.py similarity index 100% rename from uncloud_etcd_based/uncloud/metadata/main.py rename to archive/uncloud_etcd_based/uncloud/metadata/main.py diff --git a/uncloud_etcd_based/uncloud/network/README b/archive/uncloud_etcd_based/uncloud/network/README similarity index 100% rename from uncloud_etcd_based/uncloud/network/README rename to archive/uncloud_etcd_based/uncloud/network/README diff --git a/uncloud_django_based/uncloud/uncloud_pay/__init__.py b/archive/uncloud_etcd_based/uncloud/network/__init__.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_pay/__init__.py rename to archive/uncloud_etcd_based/uncloud/network/__init__.py diff --git a/uncloud_etcd_based/uncloud/network/create-bridge.sh b/archive/uncloud_etcd_based/uncloud/network/create-bridge.sh similarity index 100% rename from uncloud_etcd_based/uncloud/network/create-bridge.sh rename to archive/uncloud_etcd_based/uncloud/network/create-bridge.sh diff --git a/uncloud_etcd_based/uncloud/network/create-tap.sh b/archive/uncloud_etcd_based/uncloud/network/create-tap.sh similarity index 100% rename from uncloud_etcd_based/uncloud/network/create-tap.sh rename to archive/uncloud_etcd_based/uncloud/network/create-tap.sh diff --git a/uncloud_etcd_based/uncloud/network/create-vxlan.sh b/archive/uncloud_etcd_based/uncloud/network/create-vxlan.sh similarity index 100% rename from uncloud_etcd_based/uncloud/network/create-vxlan.sh rename to archive/uncloud_etcd_based/uncloud/network/create-vxlan.sh diff --git a/uncloud_etcd_based/uncloud/network/radvd-template.conf b/archive/uncloud_etcd_based/uncloud/network/radvd-template.conf similarity index 100% rename from uncloud_etcd_based/uncloud/network/radvd-template.conf rename to archive/uncloud_etcd_based/uncloud/network/radvd-template.conf diff --git a/uncloud_etcd_based/uncloud/oneshot/__init__.py b/archive/uncloud_etcd_based/uncloud/oneshot/__init__.py similarity index 100% rename from uncloud_etcd_based/uncloud/oneshot/__init__.py rename to archive/uncloud_etcd_based/uncloud/oneshot/__init__.py diff --git a/uncloud_etcd_based/uncloud/oneshot/main.py b/archive/uncloud_etcd_based/uncloud/oneshot/main.py similarity index 100% rename from uncloud_etcd_based/uncloud/oneshot/main.py rename to archive/uncloud_etcd_based/uncloud/oneshot/main.py diff --git a/uncloud_etcd_based/uncloud/oneshot/virtualmachine.py b/archive/uncloud_etcd_based/uncloud/oneshot/virtualmachine.py similarity index 100% rename from uncloud_etcd_based/uncloud/oneshot/virtualmachine.py rename to archive/uncloud_etcd_based/uncloud/oneshot/virtualmachine.py diff --git a/uncloud_etcd_based/uncloud/scheduler/__init__.py b/archive/uncloud_etcd_based/uncloud/scheduler/__init__.py similarity index 100% rename from uncloud_etcd_based/uncloud/scheduler/__init__.py rename to archive/uncloud_etcd_based/uncloud/scheduler/__init__.py diff --git a/uncloud_etcd_based/uncloud/scheduler/helper.py b/archive/uncloud_etcd_based/uncloud/scheduler/helper.py similarity index 100% rename from uncloud_etcd_based/uncloud/scheduler/helper.py rename to archive/uncloud_etcd_based/uncloud/scheduler/helper.py diff --git a/uncloud_etcd_based/uncloud/scheduler/main.py b/archive/uncloud_etcd_based/uncloud/scheduler/main.py similarity index 100% rename from uncloud_etcd_based/uncloud/scheduler/main.py rename to archive/uncloud_etcd_based/uncloud/scheduler/main.py diff --git a/uncloud_django_based/uncloud/uncloud_pay/migrations/__init__.py b/archive/uncloud_etcd_based/uncloud/scheduler/tests/__init__.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_pay/migrations/__init__.py rename to archive/uncloud_etcd_based/uncloud/scheduler/tests/__init__.py diff --git a/uncloud_etcd_based/uncloud/scheduler/tests/test_basics.py b/archive/uncloud_etcd_based/uncloud/scheduler/tests/test_basics.py similarity index 100% rename from uncloud_etcd_based/uncloud/scheduler/tests/test_basics.py rename to archive/uncloud_etcd_based/uncloud/scheduler/tests/test_basics.py diff --git a/uncloud_etcd_based/uncloud/scheduler/tests/test_dead_host_mechanism.py b/archive/uncloud_etcd_based/uncloud/scheduler/tests/test_dead_host_mechanism.py similarity index 100% rename from uncloud_etcd_based/uncloud/scheduler/tests/test_dead_host_mechanism.py rename to archive/uncloud_etcd_based/uncloud/scheduler/tests/test_dead_host_mechanism.py diff --git a/uncloud_etcd_based/uncloud/version.py b/archive/uncloud_etcd_based/uncloud/version.py similarity index 100% rename from uncloud_etcd_based/uncloud/version.py rename to archive/uncloud_etcd_based/uncloud/version.py diff --git a/uncloud_etcd_based/uncloud/vmm/__init__.py b/archive/uncloud_etcd_based/uncloud/vmm/__init__.py similarity index 100% rename from uncloud_etcd_based/uncloud/vmm/__init__.py rename to archive/uncloud_etcd_based/uncloud/vmm/__init__.py diff --git a/uncloud_django_based/uncloud/doc/README-how-to-configure-remote-uncloud-clients.org b/doc/README-how-to-configure-remote-uncloud-clients.org similarity index 100% rename from uncloud_django_based/uncloud/doc/README-how-to-configure-remote-uncloud-clients.org rename to doc/README-how-to-configure-remote-uncloud-clients.org diff --git a/uncloud_django_based/uncloud/doc/README-identifiers.org b/doc/README-identifiers.org similarity index 100% rename from uncloud_django_based/uncloud/doc/README-identifiers.org rename to doc/README-identifiers.org diff --git a/uncloud_django_based/uncloud/doc/README-object-relations.md b/doc/README-object-relations.md similarity index 100% rename from uncloud_django_based/uncloud/doc/README-object-relations.md rename to doc/README-object-relations.md diff --git a/uncloud_django_based/uncloud/doc/README-postgresql.org b/doc/README-postgresql.org similarity index 100% rename from uncloud_django_based/uncloud/doc/README-postgresql.org rename to doc/README-postgresql.org diff --git a/uncloud_django_based/uncloud/doc/README-products.md b/doc/README-products.md similarity index 100% rename from uncloud_django_based/uncloud/doc/README-products.md rename to doc/README-products.md diff --git a/uncloud_django_based/uncloud/doc/README-vpn.org b/doc/README-vpn.org similarity index 100% rename from uncloud_django_based/uncloud/doc/README-vpn.org rename to doc/README-vpn.org diff --git a/uncloud_django_based/uncloud/doc/README.md b/doc/README.md similarity index 100% rename from uncloud_django_based/uncloud/doc/README.md rename to doc/README.md diff --git a/uncloud_django_based/uncloud/manage.py b/manage.py similarity index 100% rename from uncloud_django_based/uncloud/manage.py rename to manage.py diff --git a/uncloud_django_based/uncloud/models.dot b/models.dot similarity index 100% rename from uncloud_django_based/uncloud/models.dot rename to models.dot diff --git a/uncloud_django_based/uncloud/models.png b/models.png similarity index 100% rename from uncloud_django_based/uncloud/models.png rename to models.png diff --git a/uncloud_django_based/uncloud/uncloud_service/__init__.py b/opennebula/__init__.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_service/__init__.py rename to opennebula/__init__.py diff --git a/uncloud_django_based/uncloud/opennebula/admin.py b/opennebula/admin.py similarity index 100% rename from uncloud_django_based/uncloud/opennebula/admin.py rename to opennebula/admin.py diff --git a/uncloud_django_based/uncloud/opennebula/apps.py b/opennebula/apps.py similarity index 100% rename from uncloud_django_based/uncloud/opennebula/apps.py rename to opennebula/apps.py diff --git a/uncloud_django_based/uncloud/opennebula/management/commands/opennebula-synchosts.py b/opennebula/management/commands/opennebula-synchosts.py similarity index 100% rename from uncloud_django_based/uncloud/opennebula/management/commands/opennebula-synchosts.py rename to opennebula/management/commands/opennebula-synchosts.py diff --git a/uncloud_django_based/uncloud/opennebula/management/commands/opennebula-syncvms.py b/opennebula/management/commands/opennebula-syncvms.py similarity index 100% rename from uncloud_django_based/uncloud/opennebula/management/commands/opennebula-syncvms.py rename to opennebula/management/commands/opennebula-syncvms.py diff --git a/uncloud_django_based/uncloud/opennebula/management/commands/opennebula-to-uncloud.py b/opennebula/management/commands/opennebula-to-uncloud.py similarity index 100% rename from uncloud_django_based/uncloud/opennebula/management/commands/opennebula-to-uncloud.py rename to opennebula/management/commands/opennebula-to-uncloud.py diff --git a/uncloud_django_based/uncloud/opennebula/migrations/0001_initial.py b/opennebula/migrations/0001_initial.py similarity index 100% rename from uncloud_django_based/uncloud/opennebula/migrations/0001_initial.py rename to opennebula/migrations/0001_initial.py diff --git a/uncloud_django_based/uncloud/opennebula/migrations/0002_auto_20200225_1335.py b/opennebula/migrations/0002_auto_20200225_1335.py similarity index 100% rename from uncloud_django_based/uncloud/opennebula/migrations/0002_auto_20200225_1335.py rename to opennebula/migrations/0002_auto_20200225_1335.py diff --git a/uncloud_django_based/uncloud/opennebula/migrations/0003_auto_20200225_1428.py b/opennebula/migrations/0003_auto_20200225_1428.py similarity index 100% rename from uncloud_django_based/uncloud/opennebula/migrations/0003_auto_20200225_1428.py rename to opennebula/migrations/0003_auto_20200225_1428.py diff --git a/uncloud_django_based/uncloud/opennebula/migrations/0004_auto_20200225_1816.py b/opennebula/migrations/0004_auto_20200225_1816.py similarity index 100% rename from uncloud_django_based/uncloud/opennebula/migrations/0004_auto_20200225_1816.py rename to opennebula/migrations/0004_auto_20200225_1816.py diff --git a/uncloud_django_based/uncloud/uncloud_service/migrations/__init__.py b/opennebula/migrations/__init__.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_service/migrations/__init__.py rename to opennebula/migrations/__init__.py diff --git a/uncloud_django_based/uncloud/opennebula/models.py b/opennebula/models.py similarity index 100% rename from uncloud_django_based/uncloud/opennebula/models.py rename to opennebula/models.py diff --git a/uncloud_django_based/uncloud/opennebula/serializers.py b/opennebula/serializers.py similarity index 100% rename from uncloud_django_based/uncloud/opennebula/serializers.py rename to opennebula/serializers.py diff --git a/uncloud_django_based/uncloud/opennebula/tests.py b/opennebula/tests.py similarity index 100% rename from uncloud_django_based/uncloud/opennebula/tests.py rename to opennebula/tests.py diff --git a/uncloud_django_based/uncloud/opennebula/views.py b/opennebula/views.py similarity index 100% rename from uncloud_django_based/uncloud/opennebula/views.py rename to opennebula/views.py diff --git a/uncloud_django_based/uncloud/requirements.txt b/requirements.txt similarity index 100% rename from uncloud_django_based/uncloud/requirements.txt rename to requirements.txt diff --git a/uncloud_django_based/uncloud/uncloud/.gitignore b/uncloud/.gitignore similarity index 100% rename from uncloud_django_based/uncloud/uncloud/.gitignore rename to uncloud/.gitignore diff --git a/uncloud_django_based/uncloud/uncloud/__init__.py b/uncloud/__init__.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud/__init__.py rename to uncloud/__init__.py diff --git a/uncloud_django_based/uncloud/uncloud/asgi.py b/uncloud/asgi.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud/asgi.py rename to uncloud/asgi.py diff --git a/uncloud_django_based/uncloud/uncloud/management/commands/uncloud.py b/uncloud/management/commands/uncloud.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud/management/commands/uncloud.py rename to uncloud/management/commands/uncloud.py diff --git a/uncloud_django_based/uncloud/uncloud/models.py b/uncloud/models.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud/models.py rename to uncloud/models.py diff --git a/uncloud_django_based/uncloud/uncloud/settings.py b/uncloud/settings.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud/settings.py rename to uncloud/settings.py diff --git a/uncloud_django_based/uncloud/uncloud/urls.py b/uncloud/urls.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud/urls.py rename to uncloud/urls.py diff --git a/uncloud_django_based/uncloud/uncloud/wsgi.py b/uncloud/wsgi.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud/wsgi.py rename to uncloud/wsgi.py diff --git a/uncloud_django_based/uncloud/uncloud_storage/__init__.py b/uncloud_auth/__init__.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_storage/__init__.py rename to uncloud_auth/__init__.py diff --git a/uncloud_django_based/uncloud/uncloud_auth/admin.py b/uncloud_auth/admin.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_auth/admin.py rename to uncloud_auth/admin.py diff --git a/uncloud_django_based/uncloud/uncloud_auth/apps.py b/uncloud_auth/apps.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_auth/apps.py rename to uncloud_auth/apps.py diff --git a/uncloud_django_based/uncloud/uncloud_auth/migrations/0001_initial.py b/uncloud_auth/migrations/0001_initial.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_auth/migrations/0001_initial.py rename to uncloud_auth/migrations/0001_initial.py diff --git a/uncloud_django_based/uncloud/uncloud_auth/migrations/0002_auto_20200318_1343.py b/uncloud_auth/migrations/0002_auto_20200318_1343.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_auth/migrations/0002_auto_20200318_1343.py rename to uncloud_auth/migrations/0002_auto_20200318_1343.py diff --git a/uncloud_django_based/uncloud/uncloud_auth/migrations/0003_auto_20200318_1345.py b/uncloud_auth/migrations/0003_auto_20200318_1345.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_auth/migrations/0003_auto_20200318_1345.py rename to uncloud_auth/migrations/0003_auto_20200318_1345.py diff --git a/uncloud_django_based/uncloud/uncloud_vm/__init__.py b/uncloud_auth/migrations/__init__.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_vm/__init__.py rename to uncloud_auth/migrations/__init__.py diff --git a/uncloud_django_based/uncloud/uncloud_auth/models.py b/uncloud_auth/models.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_auth/models.py rename to uncloud_auth/models.py diff --git a/uncloud_django_based/uncloud/uncloud_auth/serializers.py b/uncloud_auth/serializers.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_auth/serializers.py rename to uncloud_auth/serializers.py diff --git a/uncloud_django_based/uncloud/uncloud_auth/views.py b/uncloud_auth/views.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_auth/views.py rename to uncloud_auth/views.py diff --git a/uncloud_django_based/uncloud/uncloud_vm/migrations/__init__.py b/uncloud_net/__init__.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_vm/migrations/__init__.py rename to uncloud_net/__init__.py diff --git a/uncloud_django_based/uncloud/uncloud_net/admin.py b/uncloud_net/admin.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_net/admin.py rename to uncloud_net/admin.py diff --git a/uncloud_django_based/uncloud/uncloud_net/apps.py b/uncloud_net/apps.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_net/apps.py rename to uncloud_net/apps.py diff --git a/uncloud_django_based/uncloud/uncloud_net/management/commands/vpn.py b/uncloud_net/management/commands/vpn.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_net/management/commands/vpn.py rename to uncloud_net/management/commands/vpn.py diff --git a/uncloud_django_based/uncloud/uncloud_net/migrations/0001_initial.py b/uncloud_net/migrations/0001_initial.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_net/migrations/0001_initial.py rename to uncloud_net/migrations/0001_initial.py diff --git a/uncloud_django_based/uncloud/uncloud_net/migrations/0002_auto_20200409_1225.py b/uncloud_net/migrations/0002_auto_20200409_1225.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_net/migrations/0002_auto_20200409_1225.py rename to uncloud_net/migrations/0002_auto_20200409_1225.py diff --git a/uncloud_django_based/uncloud/uncloud_net/migrations/0003_auto_20200417_0551.py b/uncloud_net/migrations/0003_auto_20200417_0551.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_net/migrations/0003_auto_20200417_0551.py rename to uncloud_net/migrations/0003_auto_20200417_0551.py diff --git a/uncloud_etcd_based/docs/__init__.py b/uncloud_net/migrations/__init__.py similarity index 100% rename from uncloud_etcd_based/docs/__init__.py rename to uncloud_net/migrations/__init__.py diff --git a/uncloud_django_based/uncloud/uncloud_net/models.py b/uncloud_net/models.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_net/models.py rename to uncloud_net/models.py diff --git a/uncloud_django_based/uncloud/uncloud_net/serializers.py b/uncloud_net/serializers.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_net/serializers.py rename to uncloud_net/serializers.py diff --git a/uncloud_django_based/uncloud/uncloud_net/tests.py b/uncloud_net/tests.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_net/tests.py rename to uncloud_net/tests.py diff --git a/uncloud_django_based/uncloud/uncloud_net/views.py b/uncloud_net/views.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_net/views.py rename to uncloud_net/views.py diff --git a/uncloud_etcd_based/docs/source/__init__.py b/uncloud_pay/__init__.py similarity index 100% rename from uncloud_etcd_based/docs/source/__init__.py rename to uncloud_pay/__init__.py diff --git a/uncloud_django_based/uncloud/uncloud_pay/admin.py b/uncloud_pay/admin.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_pay/admin.py rename to uncloud_pay/admin.py diff --git a/uncloud_django_based/uncloud/uncloud_pay/apps.py b/uncloud_pay/apps.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_pay/apps.py rename to uncloud_pay/apps.py diff --git a/uncloud_django_based/uncloud/uncloud_pay/helpers.py b/uncloud_pay/helpers.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_pay/helpers.py rename to uncloud_pay/helpers.py diff --git a/uncloud_django_based/uncloud/uncloud_pay/management/commands/charge-negative-balance.py b/uncloud_pay/management/commands/charge-negative-balance.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_pay/management/commands/charge-negative-balance.py rename to uncloud_pay/management/commands/charge-negative-balance.py diff --git a/uncloud_django_based/uncloud/uncloud_pay/management/commands/generate-bills.py b/uncloud_pay/management/commands/generate-bills.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_pay/management/commands/generate-bills.py rename to uncloud_pay/management/commands/generate-bills.py diff --git a/uncloud_django_based/uncloud/uncloud_pay/management/commands/handle-overdue-bills.py b/uncloud_pay/management/commands/handle-overdue-bills.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_pay/management/commands/handle-overdue-bills.py rename to uncloud_pay/management/commands/handle-overdue-bills.py diff --git a/uncloud_django_based/uncloud/uncloud_pay/management/commands/import-vat-rates.py b/uncloud_pay/management/commands/import-vat-rates.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_pay/management/commands/import-vat-rates.py rename to uncloud_pay/management/commands/import-vat-rates.py diff --git a/uncloud_django_based/uncloud/uncloud_pay/migrations/0001_initial.py b/uncloud_pay/migrations/0001_initial.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_pay/migrations/0001_initial.py rename to uncloud_pay/migrations/0001_initial.py diff --git a/uncloud_django_based/uncloud/uncloud_pay/migrations/0002_auto_20200305_1524.py b/uncloud_pay/migrations/0002_auto_20200305_1524.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_pay/migrations/0002_auto_20200305_1524.py rename to uncloud_pay/migrations/0002_auto_20200305_1524.py diff --git a/uncloud_django_based/uncloud/uncloud_pay/migrations/0003_auto_20200305_1354.py b/uncloud_pay/migrations/0003_auto_20200305_1354.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_pay/migrations/0003_auto_20200305_1354.py rename to uncloud_pay/migrations/0003_auto_20200305_1354.py diff --git a/uncloud_django_based/uncloud/uncloud_pay/migrations/0004_auto_20200409_1225.py b/uncloud_pay/migrations/0004_auto_20200409_1225.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_pay/migrations/0004_auto_20200409_1225.py rename to uncloud_pay/migrations/0004_auto_20200409_1225.py diff --git a/uncloud_django_based/uncloud/uncloud_pay/migrations/0005_auto_20200413_0924.py b/uncloud_pay/migrations/0005_auto_20200413_0924.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_pay/migrations/0005_auto_20200413_0924.py rename to uncloud_pay/migrations/0005_auto_20200413_0924.py diff --git a/uncloud_django_based/uncloud/uncloud_pay/migrations/0006_auto_20200415_1003.py b/uncloud_pay/migrations/0006_auto_20200415_1003.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_pay/migrations/0006_auto_20200415_1003.py rename to uncloud_pay/migrations/0006_auto_20200415_1003.py diff --git a/uncloud_django_based/uncloud/uncloud_pay/migrations/0006_billingaddress.py b/uncloud_pay/migrations/0006_billingaddress.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_pay/migrations/0006_billingaddress.py rename to uncloud_pay/migrations/0006_billingaddress.py diff --git a/uncloud_django_based/uncloud/uncloud_pay/migrations/0007_auto_20200418_0737.py b/uncloud_pay/migrations/0007_auto_20200418_0737.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_pay/migrations/0007_auto_20200418_0737.py rename to uncloud_pay/migrations/0007_auto_20200418_0737.py diff --git a/uncloud_django_based/uncloud/uncloud_pay/migrations/0008_auto_20200502_1921.py b/uncloud_pay/migrations/0008_auto_20200502_1921.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_pay/migrations/0008_auto_20200502_1921.py rename to uncloud_pay/migrations/0008_auto_20200502_1921.py diff --git a/uncloud_django_based/uncloud/uncloud_pay/migrations/0009_auto_20200502_2047.py b/uncloud_pay/migrations/0009_auto_20200502_2047.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_pay/migrations/0009_auto_20200502_2047.py rename to uncloud_pay/migrations/0009_auto_20200502_2047.py diff --git a/uncloud_django_based/uncloud/uncloud_pay/migrations/0010_order_description.py b/uncloud_pay/migrations/0010_order_description.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_pay/migrations/0010_order_description.py rename to uncloud_pay/migrations/0010_order_description.py diff --git a/uncloud_etcd_based/test/__init__.py b/uncloud_pay/migrations/__init__.py similarity index 100% rename from uncloud_etcd_based/test/__init__.py rename to uncloud_pay/migrations/__init__.py diff --git a/uncloud_django_based/uncloud/uncloud_pay/models.py b/uncloud_pay/models.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_pay/models.py rename to uncloud_pay/models.py diff --git a/uncloud_django_based/uncloud/uncloud_pay/serializers.py b/uncloud_pay/serializers.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_pay/serializers.py rename to uncloud_pay/serializers.py diff --git a/uncloud_django_based/uncloud/uncloud_pay/stripe.py b/uncloud_pay/stripe.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_pay/stripe.py rename to uncloud_pay/stripe.py diff --git a/uncloud_django_based/uncloud/uncloud_pay/templates/bill.html b/uncloud_pay/templates/bill.html similarity index 100% rename from uncloud_django_based/uncloud/uncloud_pay/templates/bill.html rename to uncloud_pay/templates/bill.html diff --git a/uncloud_django_based/uncloud/uncloud_pay/templates/error.html.j2 b/uncloud_pay/templates/error.html.j2 similarity index 100% rename from uncloud_django_based/uncloud/uncloud_pay/templates/error.html.j2 rename to uncloud_pay/templates/error.html.j2 diff --git a/uncloud_django_based/uncloud/uncloud_pay/templates/stripe-payment.html.j2 b/uncloud_pay/templates/stripe-payment.html.j2 similarity index 100% rename from uncloud_django_based/uncloud/uncloud_pay/templates/stripe-payment.html.j2 rename to uncloud_pay/templates/stripe-payment.html.j2 diff --git a/uncloud_django_based/uncloud/uncloud_pay/tests.py b/uncloud_pay/tests.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_pay/tests.py rename to uncloud_pay/tests.py diff --git a/uncloud_django_based/uncloud/uncloud_pay/views.py b/uncloud_pay/views.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_pay/views.py rename to uncloud_pay/views.py diff --git a/uncloud_etcd_based/uncloud/cli/__init__.py b/uncloud_service/__init__.py similarity index 100% rename from uncloud_etcd_based/uncloud/cli/__init__.py rename to uncloud_service/__init__.py diff --git a/uncloud_django_based/uncloud/uncloud_service/admin.py b/uncloud_service/admin.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_service/admin.py rename to uncloud_service/admin.py diff --git a/uncloud_django_based/uncloud/uncloud_service/apps.py b/uncloud_service/apps.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_service/apps.py rename to uncloud_service/apps.py diff --git a/uncloud_django_based/uncloud/uncloud_service/migrations/0001_initial.py b/uncloud_service/migrations/0001_initial.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_service/migrations/0001_initial.py rename to uncloud_service/migrations/0001_initial.py diff --git a/uncloud_django_based/uncloud/uncloud_service/migrations/0002_auto_20200418_0641.py b/uncloud_service/migrations/0002_auto_20200418_0641.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_service/migrations/0002_auto_20200418_0641.py rename to uncloud_service/migrations/0002_auto_20200418_0641.py diff --git a/uncloud_etcd_based/uncloud/client/__init__.py b/uncloud_service/migrations/__init__.py similarity index 100% rename from uncloud_etcd_based/uncloud/client/__init__.py rename to uncloud_service/migrations/__init__.py diff --git a/uncloud_django_based/uncloud/uncloud_service/models.py b/uncloud_service/models.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_service/models.py rename to uncloud_service/models.py diff --git a/uncloud_django_based/uncloud/uncloud_service/serializers.py b/uncloud_service/serializers.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_service/serializers.py rename to uncloud_service/serializers.py diff --git a/uncloud_django_based/uncloud/uncloud_service/tests.py b/uncloud_service/tests.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_service/tests.py rename to uncloud_service/tests.py diff --git a/uncloud_django_based/uncloud/uncloud_service/views.py b/uncloud_service/views.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_service/views.py rename to uncloud_service/views.py diff --git a/uncloud_etcd_based/uncloud/configure/__init__.py b/uncloud_storage/__init__.py similarity index 100% rename from uncloud_etcd_based/uncloud/configure/__init__.py rename to uncloud_storage/__init__.py diff --git a/uncloud_django_based/uncloud/uncloud_storage/admin.py b/uncloud_storage/admin.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_storage/admin.py rename to uncloud_storage/admin.py diff --git a/uncloud_django_based/uncloud/uncloud_storage/apps.py b/uncloud_storage/apps.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_storage/apps.py rename to uncloud_storage/apps.py diff --git a/uncloud_django_based/uncloud/uncloud_storage/models.py b/uncloud_storage/models.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_storage/models.py rename to uncloud_storage/models.py diff --git a/uncloud_django_based/uncloud/uncloud_storage/tests.py b/uncloud_storage/tests.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_storage/tests.py rename to uncloud_storage/tests.py diff --git a/uncloud_django_based/uncloud/uncloud_storage/views.py b/uncloud_storage/views.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_storage/views.py rename to uncloud_storage/views.py diff --git a/uncloud_etcd_based/uncloud/network/__init__.py b/uncloud_vm/__init__.py similarity index 100% rename from uncloud_etcd_based/uncloud/network/__init__.py rename to uncloud_vm/__init__.py diff --git a/uncloud_django_based/uncloud/uncloud_vm/admin.py b/uncloud_vm/admin.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_vm/admin.py rename to uncloud_vm/admin.py diff --git a/uncloud_django_based/uncloud/uncloud_vm/apps.py b/uncloud_vm/apps.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_vm/apps.py rename to uncloud_vm/apps.py diff --git a/uncloud_django_based/uncloud/uncloud_vm/management/commands/vm.py b/uncloud_vm/management/commands/vm.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_vm/management/commands/vm.py rename to uncloud_vm/management/commands/vm.py diff --git a/uncloud_django_based/uncloud/uncloud_vm/migrations/0001_initial.py b/uncloud_vm/migrations/0001_initial.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_vm/migrations/0001_initial.py rename to uncloud_vm/migrations/0001_initial.py diff --git a/uncloud_django_based/uncloud/uncloud_vm/migrations/0002_auto_20200305_1321.py b/uncloud_vm/migrations/0002_auto_20200305_1321.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_vm/migrations/0002_auto_20200305_1321.py rename to uncloud_vm/migrations/0002_auto_20200305_1321.py diff --git a/uncloud_django_based/uncloud/uncloud_vm/migrations/0003_remove_vmhost_vms.py b/uncloud_vm/migrations/0003_remove_vmhost_vms.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_vm/migrations/0003_remove_vmhost_vms.py rename to uncloud_vm/migrations/0003_remove_vmhost_vms.py diff --git a/uncloud_django_based/uncloud/uncloud_vm/migrations/0004_remove_vmproduct_vmid.py b/uncloud_vm/migrations/0004_remove_vmproduct_vmid.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_vm/migrations/0004_remove_vmproduct_vmid.py rename to uncloud_vm/migrations/0004_remove_vmproduct_vmid.py diff --git a/uncloud_django_based/uncloud/uncloud_vm/migrations/0004_vmproduct_primary_disk.py b/uncloud_vm/migrations/0004_vmproduct_primary_disk.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_vm/migrations/0004_vmproduct_primary_disk.py rename to uncloud_vm/migrations/0004_vmproduct_primary_disk.py diff --git a/uncloud_django_based/uncloud/uncloud_vm/migrations/0005_auto_20200309_1258.py b/uncloud_vm/migrations/0005_auto_20200309_1258.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_vm/migrations/0005_auto_20200309_1258.py rename to uncloud_vm/migrations/0005_auto_20200309_1258.py diff --git a/uncloud_django_based/uncloud/uncloud_vm/migrations/0005_auto_20200321_1058.py b/uncloud_vm/migrations/0005_auto_20200321_1058.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_vm/migrations/0005_auto_20200321_1058.py rename to uncloud_vm/migrations/0005_auto_20200321_1058.py diff --git a/uncloud_django_based/uncloud/uncloud_vm/migrations/0006_auto_20200322_1758.py b/uncloud_vm/migrations/0006_auto_20200322_1758.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_vm/migrations/0006_auto_20200322_1758.py rename to uncloud_vm/migrations/0006_auto_20200322_1758.py diff --git a/uncloud_django_based/uncloud/uncloud_vm/migrations/0007_vmhost_vmcluster.py b/uncloud_vm/migrations/0007_vmhost_vmcluster.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_vm/migrations/0007_vmhost_vmcluster.py rename to uncloud_vm/migrations/0007_vmhost_vmcluster.py diff --git a/uncloud_django_based/uncloud/uncloud_vm/migrations/0008_auto_20200403_1727.py b/uncloud_vm/migrations/0008_auto_20200403_1727.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_vm/migrations/0008_auto_20200403_1727.py rename to uncloud_vm/migrations/0008_auto_20200403_1727.py diff --git a/uncloud_django_based/uncloud/uncloud_vm/migrations/0009_auto_20200417_0551.py b/uncloud_vm/migrations/0009_auto_20200417_0551.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_vm/migrations/0009_auto_20200417_0551.py rename to uncloud_vm/migrations/0009_auto_20200417_0551.py diff --git a/uncloud_django_based/uncloud/uncloud_vm/migrations/0009_merge_20200413_0857.py b/uncloud_vm/migrations/0009_merge_20200413_0857.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_vm/migrations/0009_merge_20200413_0857.py rename to uncloud_vm/migrations/0009_merge_20200413_0857.py diff --git a/uncloud_django_based/uncloud/uncloud_vm/migrations/0010_auto_20200413_0924.py b/uncloud_vm/migrations/0010_auto_20200413_0924.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_vm/migrations/0010_auto_20200413_0924.py rename to uncloud_vm/migrations/0010_auto_20200413_0924.py diff --git a/uncloud_django_based/uncloud/uncloud_vm/migrations/0011_merge_20200418_0641.py b/uncloud_vm/migrations/0011_merge_20200418_0641.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_vm/migrations/0011_merge_20200418_0641.py rename to uncloud_vm/migrations/0011_merge_20200418_0641.py diff --git a/uncloud_django_based/uncloud/uncloud_vm/migrations/0012_auto_20200418_0641.py b/uncloud_vm/migrations/0012_auto_20200418_0641.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_vm/migrations/0012_auto_20200418_0641.py rename to uncloud_vm/migrations/0012_auto_20200418_0641.py diff --git a/uncloud_django_based/uncloud/uncloud_vm/migrations/0013_remove_vmproduct_primary_disk.py b/uncloud_vm/migrations/0013_remove_vmproduct_primary_disk.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_vm/migrations/0013_remove_vmproduct_primary_disk.py rename to uncloud_vm/migrations/0013_remove_vmproduct_primary_disk.py diff --git a/uncloud_etcd_based/uncloud/scheduler/tests/__init__.py b/uncloud_vm/migrations/__init__.py similarity index 100% rename from uncloud_etcd_based/uncloud/scheduler/tests/__init__.py rename to uncloud_vm/migrations/__init__.py diff --git a/uncloud_django_based/uncloud/uncloud_vm/models.py b/uncloud_vm/models.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_vm/models.py rename to uncloud_vm/models.py diff --git a/uncloud_django_based/uncloud/uncloud_vm/serializers.py b/uncloud_vm/serializers.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_vm/serializers.py rename to uncloud_vm/serializers.py diff --git a/uncloud_django_based/uncloud/uncloud_vm/tests.py b/uncloud_vm/tests.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_vm/tests.py rename to uncloud_vm/tests.py diff --git a/uncloud_django_based/uncloud/uncloud_vm/views.py b/uncloud_vm/views.py similarity index 100% rename from uncloud_django_based/uncloud/uncloud_vm/views.py rename to uncloud_vm/views.py From 1245c191c0083b92a07861709f00de8f2386bea5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Thu, 7 May 2020 12:13:48 +0200 Subject: [PATCH 021/174] Adapt CI to new structure --- .gitlab-ci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index afdc4a1..33c1c06 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -15,8 +15,6 @@ run-tests: before_script: - 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 - - cp uncloud/secrets_sample.py uncloud/secrets.py - coverage run --source='.' ./manage.py test - coverage report From b512d42058104931ff77a839e52ccd4b2c05a4b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Thu, 7 May 2020 12:21:49 +0200 Subject: [PATCH 022/174] Add devel environment setup instructions --- README.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0e32f57..4ebdd8c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,49 @@ -# ucloud +# Uncloud -Checkout https://ungleich.ch/ucloud/ for the documentation of ucloud. +Cloud management platform, the ungleich way. + +## Development setup + +Install system dependencies: + * On Fedora, you will need the following packages: `python3-virtualenv python3-devel libpq-devel openldap-devel gcc chromium` + +You will need a Postgres database running locally: + * Install on configure PGSQL on your base system. + * OR use a container! `podman run --rm -p 5432:5432 -e POSTGRES_HOST_AUTH_METHOD=trust -it postgres:latest` + +NOTE: you will need to configure a LDAP server and credentials for authentication. See `uncloud/settings.py`. + +``` +# Initialize virtualenv. +» virtualenv .venv +Using base prefix '/usr' +New python executable in /home/fnux/Workspace/ungleich/uncloud/uncloud/.venv/bin/python3 +Also creating executable in /home/fnux/Workspace/ungleich/uncloud/uncloud/.venv/bin/python +Installing setuptools, pip, wheel... +done. + +# Enter virtualenv. +» source .venv/bin/activate + +# Install dependencies. +» pip install -r requirements.txt +[...] + +# Run migrations. +» ./manage.py migrate +Operations to perform: + Apply all migrations: admin, auth, contenttypes, opennebula, sessions, uncloud_auth, uncloud_net, uncloud_pay, uncloud_service, uncloud_vm +Running migrations: + [...] + +# Run webserver. +» ./manage.py runserver +Watching for file changes with StatReloader +Performing system checks... + +System check identified no issues (0 silenced). +May 07, 2020 - 10:17:08 +Django version 3.0.6, using settings 'uncloud.settings' +Starting development server at http://127.0.0.1:8000/ +Quit the server with CONTROL-C. +``` From ebd4e6fa1b06c17ab438a811df31b776be9f5dd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Thu, 7 May 2020 12:23:17 +0200 Subject: [PATCH 023/174] Add fancy CI badges to README --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 4ebdd8c..ea4e87c 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,11 @@ Cloud management platform, the ungleich way. + +[![pipeline status](https://code.ungleich.ch/uncloud/uncloud/badges/master/pipeline.svg)](https://code.ungleich.ch/uncloud/uncloud/commits/master) + +[![coverage report](https://code.ungleich.ch/uncloud/uncloud/badges/master/coverage.svg)](https://code.ungleich.ch/uncloud/uncloud/commits/master) + ## Development setup Install system dependencies: From 221d98af4b0f9dcb08e0eff72e381118afe05f04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Thu, 7 May 2020 12:24:17 +0200 Subject: [PATCH 024/174] Inline CI badges --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index ea4e87c..87f3067 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,6 @@ Cloud management platform, the ungleich way. [![pipeline status](https://code.ungleich.ch/uncloud/uncloud/badges/master/pipeline.svg)](https://code.ungleich.ch/uncloud/uncloud/commits/master) - [![coverage report](https://code.ungleich.ch/uncloud/uncloud/badges/master/coverage.svg)](https://code.ungleich.ch/uncloud/uncloud/commits/master) ## Development setup From b8ac99acb68740c54bba5a79cc74931385306ab4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Thu, 7 May 2020 12:25:05 +0200 Subject: [PATCH 025/174] On more small commit to fix README formatting --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 87f3067..cb5a25f 100644 --- a/README.md +++ b/README.md @@ -9,11 +9,13 @@ Cloud management platform, the ungleich way. ## Development setup Install system dependencies: - * On Fedora, you will need the following packages: `python3-virtualenv python3-devel libpq-devel openldap-devel gcc chromium` + +* On Fedora, you will need the following packages: `python3-virtualenv python3-devel libpq-devel openldap-devel gcc chromium` You will need a Postgres database running locally: - * Install on configure PGSQL on your base system. - * OR use a container! `podman run --rm -p 5432:5432 -e POSTGRES_HOST_AUTH_METHOD=trust -it postgres:latest` + +* Install on configure PGSQL on your base system. +* OR use a container! `podman run --rm -p 5432:5432 -e POSTGRES_HOST_AUTH_METHOD=trust -it postgres:latest` NOTE: you will need to configure a LDAP server and credentials for authentication. See `uncloud/settings.py`. From 268e08c4dbe09fcdd1c1dc495e7fadd5ac54d107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Thu, 7 May 2020 12:31:59 +0200 Subject: [PATCH 026/174] Adapt README for SQLite --- .gitignore | 1 + README.md | 15 +++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index cbb171f..ab6a151 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ venv/ dist/ *.iso +*.sqlite3 diff --git a/README.md b/README.md index cb5a25f..6da7cdb 100644 --- a/README.md +++ b/README.md @@ -10,12 +10,7 @@ Cloud management platform, the ungleich way. Install system dependencies: -* On Fedora, you will need the following packages: `python3-virtualenv python3-devel libpq-devel openldap-devel gcc chromium` - -You will need a Postgres database running locally: - -* Install on configure PGSQL on your base system. -* OR use a container! `podman run --rm -p 5432:5432 -e POSTGRES_HOST_AUTH_METHOD=trust -it postgres:latest` +* On Fedora, you will need the following packages: `python3-virtualenv python3-devel openldap-devel gcc chromium` NOTE: you will need to configure a LDAP server and credentials for authentication. See `uncloud/settings.py`. @@ -53,3 +48,11 @@ Django version 3.0.6, using settings 'uncloud.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C. ``` + +### Note on PGSQL + +If you want to use Postgres: + +* Install on configure PGSQL on your base system. +* OR use a container! `podman run --rm -p 5432:5432 -e POSTGRES_HOST_AUTH_METHOD=trust -it postgres:latest` + From 718abab9d2ac842f19a08bd4f0f6acf53f2a355c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Thu, 7 May 2020 12:45:06 +0200 Subject: [PATCH 027/174] Add make-admin command to uncloud_auth --- README.md | 6 +++++- uncloud_auth/management/commands/make-admin.py | 16 ++++++++++++++++ uncloud_pay/views.py | 4 ++-- 3 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 uncloud_auth/management/commands/make-admin.py diff --git a/README.md b/README.md index 6da7cdb..8c53654 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,11 @@ Cloud management platform, the ungleich way. [![pipeline status](https://code.ungleich.ch/uncloud/uncloud/badges/master/pipeline.svg)](https://code.ungleich.ch/uncloud/uncloud/commits/master) [![coverage report](https://code.ungleich.ch/uncloud/uncloud/badges/master/coverage.svg)](https://code.ungleich.ch/uncloud/uncloud/commits/master) +## Useful commands + +* `./manage.py import-vat-rates path/to/csv` +* `./manage.py make-admin username` + ## Development setup Install system dependencies: @@ -55,4 +60,3 @@ If you want to use Postgres: * Install on configure PGSQL on your base system. * OR use a container! `podman run --rm -p 5432:5432 -e POSTGRES_HOST_AUTH_METHOD=trust -it postgres:latest` - diff --git a/uncloud_auth/management/commands/make-admin.py b/uncloud_auth/management/commands/make-admin.py new file mode 100644 index 0000000..b750bc3 --- /dev/null +++ b/uncloud_auth/management/commands/make-admin.py @@ -0,0 +1,16 @@ +from django.core.management.base import BaseCommand +from django.contrib.auth import get_user_model +import sys + +class Command(BaseCommand): + help = 'Give Admin rights to existing user' + + def add_arguments(self, parser): + parser.add_argument('username', type=str) + + def handle(self, *args, **options): + user = get_user_model().objects.get(username=options['username']) + user.is_staff = True + user.save() + + print("{} is now admin.".format(user.username)) diff --git a/uncloud_pay/views.py b/uncloud_pay/views.py index 54ff2f0..8bb2280 100644 --- a/uncloud_pay/views.py +++ b/uncloud_pay/views.py @@ -243,7 +243,7 @@ class BillingAddressViewSet(mixins.CreateModelMixin, return Response(serializer.data) ### -# Old admin stuff. +# Admin stuff. class AdminPaymentViewSet(viewsets.ModelViewSet): serializer_class = PaymentSerializer @@ -279,7 +279,7 @@ class AdminBillViewSet(viewsets.ModelViewSet): return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) class AdminOrderViewSet(viewsets.ModelViewSet): - permission_classes = [permissions.IsAuthenticated] + permission_classes = [permissions.IsAdminUser] def get_serializer(self, *args, **kwargs): return OrderSerializer(*args, **kwargs, admin=True) From 56d98cbb55523739375abc007bc89a96b6c288b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Thu, 7 May 2020 13:12:38 +0200 Subject: [PATCH 028/174] Implement Orders/Bills permissions, unpaid bill views --- uncloud_pay/views.py | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/uncloud_pay/views.py b/uncloud_pay/views.py index 8bb2280..bb73cfb 100644 --- a/uncloud_pay/views.py +++ b/uncloud_pay/views.py @@ -182,8 +182,13 @@ class BillViewSet(viewsets.ReadOnlyModelViewSet): def get_queryset(self): return Bill.objects.filter(owner=self.request.user) + + @action(detail=False, methods=['get']) def unpaid(self, request): - return Bill.objects.filter(owner=self.request.user, paid=False) + serializer = self.get_serializer( + Bill.get_unpaid_for(self.request.user), + many=True) + return Response(serializer.data) class OrderViewSet(viewsets.ReadOnlyModelViewSet): @@ -247,7 +252,7 @@ class BillingAddressViewSet(mixins.CreateModelMixin, class AdminPaymentViewSet(viewsets.ModelViewSet): serializer_class = PaymentSerializer - permission_classes = [permissions.IsAuthenticated] + permission_classes = [permissions.IsAdminUser] def get_queryset(self): return Payment.objects.all() @@ -260,25 +265,28 @@ class AdminPaymentViewSet(viewsets.ModelViewSet): headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) -class AdminBillViewSet(viewsets.ModelViewSet): +# Bills are generated from orders and should not be created or updated by hand. +class AdminBillViewSet(viewsets.ReadOnlyModelViewSet): serializer_class = BillSerializer - permission_classes = [permissions.IsAuthenticated] + permission_classes = [permissions.IsAdminUser] def get_queryset(self): return Bill.objects.all() + @action(detail=False, methods=['get']) def unpaid(self, request): - return Bill.objects.filter(owner=self.request.user, paid=False) + unpaid_bills = [] + # XXX: works but we can do better than number of users + 1 SQL requests... + for user in get_user_model().objects.all(): + unpaid_bills = unpaid_bills + Bill.get_unpaid_for(self.request.user) - def create(self, request): - serializer = self.get_serializer(data=request.data) - serializer.is_valid(raise_exception=True) - serializer.save(creation_date=datetime.now()) + serializer = self.get_serializer(unpaid_bills, many=True) + return Response(serializer.data) - headers = self.get_success_headers(serializer.data) - return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) - -class AdminOrderViewSet(viewsets.ModelViewSet): +class AdminOrderViewSet(mixins.ListModelMixin, + mixins.RetrieveModelMixin, + mixins.CreateModelMixin, + viewsets.GenericViewSet): permission_classes = [permissions.IsAdminUser] def get_serializer(self, *args, **kwargs): From 3874165189692604022b11bb3d661edb4d957c3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Thu, 7 May 2020 14:24:04 +0200 Subject: [PATCH 029/174] Fix bill generation --- uncloud_pay/models.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/uncloud_pay/models.py b/uncloud_pay/models.py index 1294a54..68016a9 100644 --- a/uncloud_pay/models.py +++ b/uncloud_pay/models.py @@ -521,9 +521,8 @@ class Bill(models.Model): bill_records = [] orders = Order.objects.filter(bill=self) for order in orders: - for order_record in order.records: - bill_record = BillRecord(self, order_record) - bill_records.append(bill_record) + bill_record = BillRecord(self, order) + bill_records.append(bill_record) return bill_records @@ -710,18 +709,18 @@ class Bill(models.Model): class BillRecord(): """ - Entry of a bill, dynamically generated from order records. + Entry of a bill, dynamically generated from an order. """ - def __init__(self, bill, order_record): + def __init__(self, bill, order): self.bill = bill - self.order = order_record.order - self.recurring_price = order_record.recurring_price - self.recurring_period = order_record.recurring_period - self.description = order_record.description + self.order = order + self.recurring_price = order.recurring_price + self.recurring_period = order.recurring_period + self.description = order.description if self.order.starting_date >= self.bill.starting_date: - self.one_time_price = order_record.one_time_price + self.one_time_price = order.one_time_price else: self.one_time_price = 0 @@ -779,7 +778,7 @@ class BillRecord(): return 0 else: raise Exception('Unsupported recurring period: {}.'. - format(record.recurring_period)) + format(self.order.recurring_period)) @property def vat_rate(self): From ae2bad57544ab257e7c7c94e89fa0242fa8be30c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Thu, 7 May 2020 15:38:49 +0200 Subject: [PATCH 030/174] Generate bill PDFs from /my/bill --- uncloud/urls.py | 1 - .../0011_billingaddress_organization.py | 19 +++ uncloud_pay/models.py | 1 + uncloud_pay/serializers.py | 4 +- .../templates/{bill.html => bill.html.j2} | 156 ++++++------------ uncloud_pay/views.py | 30 ++-- 6 files changed, 96 insertions(+), 115 deletions(-) create mode 100644 uncloud_pay/migrations/0011_billingaddress_organization.py rename uncloud_pay/templates/{bill.html => bill.html.j2} (96%) diff --git a/uncloud/urls.py b/uncloud/urls.py index 05b1f0f..b20f136 100644 --- a/uncloud/urls.py +++ b/uncloud/urls.py @@ -81,7 +81,6 @@ urlpatterns = [ path('', include(router.urls)), # web/ = stuff to view in the browser - path('web/pdf/', payviews.MyPDFView.as_view(), name='pdf'), path('api-auth/', include('rest_framework.urls', namespace='rest_framework')), # for login to REST API path('openapi', get_schema_view( title="uncloud", diff --git a/uncloud_pay/migrations/0011_billingaddress_organization.py b/uncloud_pay/migrations/0011_billingaddress_organization.py new file mode 100644 index 0000000..ac36eee --- /dev/null +++ b/uncloud_pay/migrations/0011_billingaddress_organization.py @@ -0,0 +1,19 @@ +# Generated by Django 3.0.6 on 2020-05-07 13:07 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('uncloud_pay', '0010_order_description'), + ] + + operations = [ + migrations.AddField( + model_name='billingaddress', + name='organization', + field=models.CharField(default='', max_length=100), + preserve_default=False, + ), + ] diff --git a/uncloud_pay/models.py b/uncloud_pay/models.py index 68016a9..92c58ab 100644 --- a/uncloud_pay/models.py +++ b/uncloud_pay/models.py @@ -444,6 +444,7 @@ class BillingAddress(models.Model): uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) owner = models.ForeignKey(get_user_model(), on_delete=models.CASCADE) + organization = models.CharField(max_length=100) name = models.CharField(max_length=100) street = models.CharField(max_length=100) city = models.CharField(max_length=50) diff --git a/uncloud_pay/serializers.py b/uncloud_pay/serializers.py index ad50c68..1d7dcdd 100644 --- a/uncloud_pay/serializers.py +++ b/uncloud_pay/serializers.py @@ -95,7 +95,7 @@ class BillRecordSerializer(serializers.Serializer): class BillingAddressSerializer(serializers.ModelSerializer): class Meta: model = BillingAddress - fields = ['uuid', 'name', 'street', 'city', 'postal_code', 'country', 'vat_number'] + fields = ['uuid', 'organization', 'name', 'street', 'city', 'postal_code', 'country', 'vat_number'] class BillSerializer(serializers.ModelSerializer): billing_address = BillingAddressSerializer(read_only=True) @@ -103,7 +103,7 @@ class BillSerializer(serializers.ModelSerializer): class Meta: model = Bill - fields = ['reference', 'owner', 'amount', 'vat_amount', 'total', + fields = ['uuid', 'reference', 'owner', 'amount', 'vat_amount', 'total', 'due_date', 'creation_date', 'starting_date', 'ending_date', 'records', 'final', 'billing_address'] diff --git a/uncloud_pay/templates/bill.html b/uncloud_pay/templates/bill.html.j2 similarity index 96% rename from uncloud_pay/templates/bill.html rename to uncloud_pay/templates/bill.html.j2 index 8f6c217..0ea7089 100644 --- a/uncloud_pay/templates/bill.html +++ b/uncloud_pay/templates/bill.html.j2 @@ -26,7 +26,7 @@ - Bill name + {{ bill.reference }} | {{ bill.uuid }} +{% endblock %} + +{% block body %} +
+

Registering Stripe Credit Card

+ + + +
+
+ +
+ + +
+
+ + + + + + + +{% endblock %} diff --git a/uncloud_pay/views.py b/uncloud_pay/views.py index edfb189..53d6ef4 100644 --- a/uncloud_pay/views.py +++ b/uncloud_pay/views.py @@ -1,3 +1,7 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.views.generic.base import TemplateView + + from django.shortcuts import render from django.db import transaction from django.contrib.auth import get_user_model @@ -43,6 +47,25 @@ class OrderViewSet(viewsets.ReadOnlyModelViewSet): def get_queryset(self): return Order.objects.filter(owner=self.request.user) + +class RegisterCard(LoginRequiredMixin, TemplateView): + login_url = '/login/' + + # This is not supposed to be "static" -- + # the idea is to be able to switch the provider when needed + template_name = "uncloud_pay/stripe.html" + + def get_context_data(self, **kwargs): + customer_id = uncloud_stripe.get_customer_id_for(self.request.user) + setup_intent = uncloud_stripe.create_setup_intent(customer_id) + + context = super().get_context_data(**kwargs) + context['client_secret'] = setup_intent.client_secret + context['username'] = self.request.user + context['stripe_pk'] = uncloud_stripe.public_api_key + return context + + class PaymentMethodViewSet(viewsets.ModelViewSet): permission_classes = [permissions.IsAuthenticated] From f02f15f09bfc9cdc047334cb6dd12c5094ccd0ca Mon Sep 17 00:00:00 2001 From: PCoder Date: Wed, 14 Apr 2021 17:02:40 +0530 Subject: [PATCH 173/174] First pass at the add-opennebula-vm-orders management command Command executes but still does not create bills --- .../commands/add-opennebula-vm-orders.py | 98 +++++++++++-------- uncloud_vm/migrations/0002_vmproduct_owner.py | 21 ++++ .../0003_vmproduct_created_order_at.py | 20 ++++ .../migrations/0004_auto_20210414_1048.py | 24 +++++ .../migrations/0005_auto_20210414_1119.py | 24 +++++ .../migrations/0006_auto_20210414_1122.py | 20 ++++ uncloud_vm/models.py | 11 +++ 7 files changed, 175 insertions(+), 43 deletions(-) create mode 100644 uncloud_vm/migrations/0002_vmproduct_owner.py create mode 100644 uncloud_vm/migrations/0003_vmproduct_created_order_at.py create mode 100644 uncloud_vm/migrations/0004_auto_20210414_1048.py create mode 100644 uncloud_vm/migrations/0005_auto_20210414_1119.py create mode 100644 uncloud_vm/migrations/0006_auto_20210414_1122.py diff --git a/uncloud_pay/management/commands/add-opennebula-vm-orders.py b/uncloud_pay/management/commands/add-opennebula-vm-orders.py index 1d66790..e0b6758 100644 --- a/uncloud_pay/management/commands/add-opennebula-vm-orders.py +++ b/uncloud_pay/management/commands/add-opennebula-vm-orders.py @@ -1,32 +1,38 @@ -from django.core.management.base import BaseCommand -from django.contrib.auth import get_user_model - -from django.utils import timezone -from datetime import datetime, timedelta - -from uncloud_pay.models import * -from uncloud_vm.models import * - +import datetime import sys +from django.contrib.auth import get_user_model +from django.core.management.base import BaseCommand +from django.utils import timezone + +from uncloud_pay.models import ( + BillingAddress +) +from uncloud_vm.models import ( + VMDiskType, VMProduct +) + + def vm_price_2020(cpu=1, ram=2, v6only=False): if v6only: discount = 9 else: discount = 0 - return cpu*3 + ram*4 - discount + return cpu * 3 + ram * 4 - discount + def disk_price_2020(size_in_gb, disk_type): if disk_type == VMDiskType.CEPH_SSD: - price = 3.5/10 + price = 3.5 / 10 elif disk_type == VMDiskType.CEPH_HDD: - price = 1.5/100 + price = 1.5 / 100 else: raise Exception("not yet defined price") return size_in_gb * price + class Command(BaseCommand): help = 'Adding VMs / creating orders for user' @@ -40,18 +46,20 @@ class Command(BaseCommand): owner=user, active=True, defaults={'organization': 'Undefined organisation', - 'name': 'Undefined name', + 'full_name': 'Undefined name', 'street': 'Undefined Street', 'city': 'Undefined city', 'postal_code': '8750', 'country': 'CH', 'active': True - } + } ) # 25206 + SSD - vm25206 = VMProduct.objects.create(name="one-25206", cores=1, ram_in_gb=4, owner=user) - vm25206.create_order_at(timezone.make_aware(datetime.datetime(2020,3,3))) + vm25206 = VMProduct.objects.create(name="one-25206", cores=1, + ram_in_gb=4, owner=user) + vm25206.create_order_at( + timezone.make_aware(datetime.datetime(2020, 3, 3))) # vm25206_ssd = VMDiskProduct.objects.create(vm=vm25206, owner=user, size_in_gb=30) # vm25206_ssd.create_order_at(timezone.make_aware(datetime.datetime(2020,3,3))) @@ -60,7 +68,8 @@ class Command(BaseCommand): vm25206.cores = 2 vm25206.ram_in_gb = 8 vm25206.save() - vm25206.create_or_update_order(when_to_start=timezone.make_aware(datetime.datetime(2020,4,17))) + vm25206.create_or_update_order( + when_to_start=timezone.make_aware(datetime.datetime(2020, 4, 17))) sys.exit(0) @@ -72,69 +81,72 @@ class Command(BaseCommand): # 25206 done. # 25615 - vm25615 = VMProduct.objects.create(name="one-25615", cores=1, ram_in_gb=4, owner=user) - vm25615.create_order_at(timezone.make_aware(datetime.datetime(2020,3,3))) + vm25615 = VMProduct.objects.create(name="one-25615", cores=1, + ram_in_gb=4, owner=user) + vm25615.create_order_at( + timezone.make_aware(datetime.datetime(2020, 3, 3))) # Change 2020-04-17 vm25615.cores = 2 vm25615.ram_in_gb = 8 vm25615.save() - vm25615.create_or_update_order(when_to_start=timezone.make_aware(datetime.datetime(2020,4,17))) + vm25615.create_or_update_order( + when_to_start=timezone.make_aware(datetime.datetime(2020, 4, 17))) # vm25615_ssd = VMDiskProduct(vm=vm25615, owner=user, size_in_gb=30) # vm25615_ssd.create_order_at(timezone.make_aware(datetime.datetime(2020,3,3))) # vm25615_ssd.save() - vm25208 = VMProduct.objects.create(name="one-25208", cores=1, ram_in_gb=4, owner=user) - vm25208.create_order_at(timezone.make_aware(datetime.datetime(2020,3,5))) + vm25208 = VMProduct.objects.create(name="one-25208", cores=1, + ram_in_gb=4, owner=user) + vm25208.create_order_at( + timezone.make_aware(datetime.datetime(2020, 3, 5))) vm25208.cores = 2 vm25208.ram_in_gb = 8 vm25208.save() - vm25208.create_or_update_order(when_to_start=timezone.make_aware(datetime.datetime(2020,4,17))) + vm25208.create_or_update_order( + when_to_start=timezone.make_aware(datetime.datetime(2020, 4, 17))) - Bill.create_next_bills_for_user(user, ending_date=end_of_month(timezone.make_aware(datetime.datetime(2020,7,31)))) + Bill.create_next_bills_for_user(user, ending_date=end_of_month( + timezone.make_aware(datetime.datetime(2020, 7, 31)))) sys.exit(0) - vm25615_ssd.size_in_gb = 50 vm25615_ssd.save() - vm25615_ssd.create_or_update_order(when_to_start=timezone.make_aware(datetime.datetime(2020,8,5))) - - + vm25615_ssd.create_or_update_order( + when_to_start=timezone.make_aware(datetime.datetime(2020, 8, 5))) vm25208_ssd = VMDiskProduct.objects.create(vm=vm25208, - owner=user, - size_in_gb=30) - - + owner=user, + size_in_gb=30) vm25208_ssd.size_in_gb = 50 vm25208_ssd.save() - vm25208_ssd.create_or_update_order(when_to_start=timezone.make_aware(datetime.datetime(2020,8,5))) - + vm25208_ssd.create_or_update_order( + when_to_start=timezone.make_aware(datetime.datetime(2020, 8, 5))) # 25207 vm25207 = VMProduct.objects.create(name="OpenNebula 25207", - cores=1, - ram_in_gb=4, - owner=user) + cores=1, + ram_in_gb=4, + owner=user) vm25207_ssd = VMDiskProduct.objects.create(vm=vm25207, - owner=user, - size_in_gb=30) + owner=user, + size_in_gb=30) vm25207_ssd.size_in_gb = 50 vm25207_ssd.save() - vm25207_ssd.create_or_update_order(when_to_start=timezone.make_aware(datetime.datetime(2020,8,5))) - + vm25207_ssd.create_or_update_order( + when_to_start=timezone.make_aware(datetime.datetime(2020, 8, 5))) vm25207.cores = 2 vm25207.ram_in_gb = 8 vm25207.save() - vm25207.create_or_update_order(when_to_start=timezone.make_aware(datetime.datetime(2020,6,19))) - + vm25207.create_or_update_order( + when_to_start=timezone.make_aware(datetime.datetime(2020, 6, 19))) # FIXES: check starting times (they are slightly different) # add vm 25236 diff --git a/uncloud_vm/migrations/0002_vmproduct_owner.py b/uncloud_vm/migrations/0002_vmproduct_owner.py new file mode 100644 index 0000000..3b96a87 --- /dev/null +++ b/uncloud_vm/migrations/0002_vmproduct_owner.py @@ -0,0 +1,21 @@ +# Generated by Django 3.1.4 on 2021-04-14 10:40 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('uncloud_vm', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='vmproduct', + name='owner', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/uncloud_vm/migrations/0003_vmproduct_created_order_at.py b/uncloud_vm/migrations/0003_vmproduct_created_order_at.py new file mode 100644 index 0000000..8f5d0c4 --- /dev/null +++ b/uncloud_vm/migrations/0003_vmproduct_created_order_at.py @@ -0,0 +1,20 @@ +# Generated by Django 3.1.4 on 2021-04-14 10:46 + +import datetime +from django.db import migrations, models +from django.utils.timezone import utc + + +class Migration(migrations.Migration): + + dependencies = [ + ('uncloud_vm', '0002_vmproduct_owner'), + ] + + operations = [ + migrations.AddField( + model_name='vmproduct', + name='created_order_at', + field=models.DateTimeField(default=datetime.datetime(2021, 4, 14, 10, 46, 14, 96330, tzinfo=utc)), + ), + ] diff --git a/uncloud_vm/migrations/0004_auto_20210414_1048.py b/uncloud_vm/migrations/0004_auto_20210414_1048.py new file mode 100644 index 0000000..20214bc --- /dev/null +++ b/uncloud_vm/migrations/0004_auto_20210414_1048.py @@ -0,0 +1,24 @@ +# Generated by Django 3.1.4 on 2021-04-14 10:48 + +import datetime +from django.db import migrations, models +from django.utils.timezone import utc + + +class Migration(migrations.Migration): + + dependencies = [ + ('uncloud_vm', '0003_vmproduct_created_order_at'), + ] + + operations = [ + migrations.RemoveField( + model_name='vmproduct', + name='created_order_at', + ), + migrations.AddField( + model_name='vmproduct', + name='create_order_at', + field=models.DateTimeField(default=datetime.datetime(2021, 4, 14, 10, 48, 6, 641056, tzinfo=utc)), + ), + ] diff --git a/uncloud_vm/migrations/0005_auto_20210414_1119.py b/uncloud_vm/migrations/0005_auto_20210414_1119.py new file mode 100644 index 0000000..ef9df79 --- /dev/null +++ b/uncloud_vm/migrations/0005_auto_20210414_1119.py @@ -0,0 +1,24 @@ +# Generated by Django 3.1.4 on 2021-04-14 11:19 + +import datetime +from django.db import migrations, models +from django.utils.timezone import utc + + +class Migration(migrations.Migration): + + dependencies = [ + ('uncloud_vm', '0004_auto_20210414_1048'), + ] + + operations = [ + migrations.RemoveField( + model_name='vmproduct', + name='create_order_at', + ), + migrations.AddField( + model_name='vmproduct', + name='created_order_at', + field=models.DateTimeField(default=datetime.datetime(2021, 4, 14, 11, 19, 39, 447274, tzinfo=utc)), + ), + ] diff --git a/uncloud_vm/migrations/0006_auto_20210414_1122.py b/uncloud_vm/migrations/0006_auto_20210414_1122.py new file mode 100644 index 0000000..2c302fb --- /dev/null +++ b/uncloud_vm/migrations/0006_auto_20210414_1122.py @@ -0,0 +1,20 @@ +# Generated by Django 3.1.4 on 2021-04-14 11:22 + +import datetime +from django.db import migrations, models +from django.utils.timezone import utc + + +class Migration(migrations.Migration): + + dependencies = [ + ('uncloud_vm', '0005_auto_20210414_1119'), + ] + + operations = [ + migrations.AlterField( + model_name='vmproduct', + name='created_order_at', + field=models.DateTimeField(default=datetime.datetime(2021, 4, 14, 11, 22, 11, 352536, tzinfo=utc)), + ), + ] diff --git a/uncloud_vm/models.py b/uncloud_vm/models.py index c605779..952cde9 100644 --- a/uncloud_vm/models.py +++ b/uncloud_vm/models.py @@ -1,3 +1,6 @@ +import datetime +from django.utils import timezone + from django.db import models from django.contrib.auth import get_user_model @@ -50,6 +53,8 @@ class VMHost(UncloudModel): class VMProduct(models.Model): + owner = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, + blank=True, null=True) vmhost = models.ForeignKey( VMHost, on_delete=models.CASCADE, editable=False, blank=True, null=True ) @@ -61,6 +66,7 @@ class VMProduct(models.Model): name = models.CharField(max_length=32, blank=True, null=True) cores = models.IntegerField() ram_in_gb = models.FloatField() + created_order_at = models.DateTimeField(default=timezone.make_aware(datetime.datetime.now())) @property def recurring_price(self): @@ -78,6 +84,11 @@ class VMProduct(models.Model): # RecurringPeriod.PER_30D, RecurringPeriod.PER_HOUR], # RecurringPeriod.choices)) + def create_order_at(self, dt): + self.created_order_at = dt + + def create_or_update_order(self, when_to_start): + self.created_order_at = when_to_start def __str__(self): return f"VM id={self.id},name={self.name},cores={self.cores},ram_in_gb={self.ram_in_gb}" From 29bd6b5b3c792fad9df5c6a6b3f13af46d9e430c Mon Sep 17 00:00:00 2001 From: PCoder Date: Thu, 15 Apr 2021 09:45:20 +0530 Subject: [PATCH 174/174] Use correct app name --- uncloud_service/apps.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncloud_service/apps.py b/uncloud_service/apps.py index 184e181..190bd35 100644 --- a/uncloud_service/apps.py +++ b/uncloud_service/apps.py @@ -2,4 +2,4 @@ from django.apps import AppConfig class UngleichServiceConfig(AppConfig): - name = 'ungleich_service' + name = 'uncloud_service'