vmhosts, restructure urls, etc.
This commit is contained in:
parent
d4b170f813
commit
c7ded96658
9 changed files with 134 additions and 47 deletions
|
@ -23,20 +23,22 @@ from uncloud_vm import views as vmviews
|
||||||
from opennebula import views as oneviews
|
from opennebula import views as oneviews
|
||||||
|
|
||||||
router = routers.DefaultRouter()
|
router = routers.DefaultRouter()
|
||||||
router.register(r'users', apiviews.UserViewSet)
|
|
||||||
router.register(r'opennebula', oneviews.VMViewSet, basename='opennebula')
|
router.register(r'user', apiviews.UserViewSet, basename='user')
|
||||||
router.register(r'opennebula_raw', oneviews.RawVMViewSet)
|
|
||||||
router.register(r'vmsnapshot', apiviews.VMSnapshotView, basename='vmsnapshot')
|
router.register(r'vm/snapshot', apiviews.VMSnapshotView, basename='VMSnapshot')
|
||||||
|
router.register(r'vm/vm', vmviews.VMProductViewSet, basename='vmproduct')
|
||||||
|
|
||||||
# admin/staff urls
|
# admin/staff urls
|
||||||
router.register(r'admin/vmhost', vmviews.VMHostViewSet)
|
router.register(r'admin/vmhost', vmviews.VMHostViewSet)
|
||||||
|
router.register(r'admin/opennebula', oneviews.VMViewSet, basename='opennebula')
|
||||||
|
router.register(r'admin/opennebula_raw', oneviews.RawVMViewSet)
|
||||||
|
|
||||||
|
|
||||||
# Wire up our API using automatic URL routing.
|
# Wire up our API using automatic URL routing.
|
||||||
# Additionally, we include login URLs for the browsable API.
|
# Additionally, we include login URLs for the browsable API.
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', include(router.urls)),
|
path('', include(router.urls)),
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls), # login to django itself
|
||||||
path('products/', apiviews.ProductsView.as_view(), name='products'),
|
path('api-auth/', include('rest_framework.urls', namespace='rest_framework')) # for login to REST API
|
||||||
path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
|
|
||||||
]
|
]
|
||||||
|
|
|
@ -5,11 +5,10 @@ from rest_framework import serializers
|
||||||
|
|
||||||
from .models import VMSnapshotProduct
|
from .models import VMSnapshotProduct
|
||||||
|
|
||||||
|
class UserSerializer(serializers.ModelSerializer):
|
||||||
class UserSerializer(serializers.HyperlinkedModelSerializer):
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = get_user_model()
|
model = get_user_model()
|
||||||
fields = ['url', 'username', 'email', 'groups']
|
fields = ['url', 'username', 'email']
|
||||||
|
|
||||||
class GroupSerializer(serializers.HyperlinkedModelSerializer):
|
class GroupSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
@ -17,18 +17,6 @@ import sys
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class UserViewSet(viewsets.ModelViewSet):
|
|
||||||
|
|
||||||
"""
|
|
||||||
API endpoint that allows users to be viewed or edited.
|
|
||||||
"""
|
|
||||||
queryset = get_user_model().objects.all().order_by('-date_joined')
|
|
||||||
serializer_class = UserSerializer
|
|
||||||
|
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
|
||||||
|
|
||||||
|
|
||||||
# POST /vm/snapshot/ vmuuid=... => create snapshot, returns snapshot uuid
|
# POST /vm/snapshot/ vmuuid=... => create snapshot, returns snapshot uuid
|
||||||
# GET /vm/snapshot => list
|
# GET /vm/snapshot => list
|
||||||
# DEL /vm/snapshot/<uuid:uuid> => delete
|
# DEL /vm/snapshot/<uuid:uuid> => delete
|
||||||
|
@ -69,23 +57,38 @@ class VMSnapshotView(viewsets.ViewSet):
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
|
|
||||||
|
|
||||||
# Next: create /order/<productname> urls
|
|
||||||
# Next: strip off "Product" at the end
|
# maybe drop or not --- we need something to guide the user!
|
||||||
class ProductsView(APIView):
|
# class ProductsViewSet(viewsets.ViewSet):
|
||||||
def get(self, request, format=None):
|
# permission_classes = [permissions.IsAuthenticated]
|
||||||
clsmembers = inspect.getmembers(sys.modules['uncloud_api.models'], inspect.isclass)
|
|
||||||
products = []
|
# def list(self, request):
|
||||||
for name, c in clsmembers:
|
|
||||||
# Include everything that ends in Product, but not Product itself
|
# clsmembers = []
|
||||||
m = re.match(r'(?P<pname>.+)Product$', name)
|
# for modules in [ 'uncloud_api.models', 'uncloud_vm.models' ]:
|
||||||
if m:
|
# clsmembers.extend(inspect.getmembers(sys.modules[modules], inspect.isclass))
|
||||||
products.append({
|
|
||||||
'name': m.group('pname'),
|
|
||||||
'description': c.description,
|
|
||||||
'recurring_period': c.recurring_period,
|
|
||||||
'pricing_model': c.pricing_model()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
return Response(products)
|
# products = []
|
||||||
|
# for name, c in clsmembers:
|
||||||
|
# # Include everything that ends in Product, but not Product itself
|
||||||
|
# m = re.match(r'(?P<pname>.+)Product$', name)
|
||||||
|
# if m:
|
||||||
|
# products.append({
|
||||||
|
# 'name': m.group('pname'),
|
||||||
|
# 'description': c.description,
|
||||||
|
# 'recurring_period': c.recurring_period,
|
||||||
|
# 'pricing_model': c.pricing_model()
|
||||||
|
# }
|
||||||
|
# )
|
||||||
|
|
||||||
|
|
||||||
|
# return Response(products)
|
||||||
|
|
||||||
|
|
||||||
|
class UserViewSet(viewsets.ModelViewSet):
|
||||||
|
serializer_class = UserSerializer
|
||||||
|
permission_classes = [permissions.IsAuthenticated]
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return self.request.user
|
||||||
|
|
21
uncloud/uncloud_vm/management/commands/schedulevms.py
Normal file
21
uncloud/uncloud_vm/management/commands/schedulevms.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import json
|
||||||
|
|
||||||
|
import uncloud.secrets as secrets
|
||||||
|
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
|
||||||
|
from uncloud_vm.models import VMProduct, VMHost
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = 'Select VM Host for VMs'
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
pending_vms = VMProduct.objects.filter(vmhost__isnull=True)
|
||||||
|
vmhosts = VMHost.objects.filter(status='active')
|
||||||
|
for vm in pending_vms:
|
||||||
|
print(vm)
|
||||||
|
# FIXME: implement smart placement
|
24
uncloud/uncloud_vm/management/commands/vmhealth.py
Normal file
24
uncloud/uncloud_vm/management/commands/vmhealth.py
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import json
|
||||||
|
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
|
||||||
|
from uncloud_vm.models import VMProduct, VMHost
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = 'Check health of VMs and VMHosts'
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
pending_vms = VMProduct.objects.filter(vmhost__isnull=True)
|
||||||
|
vmhosts = VMHost.objects.filter(status='active')
|
||||||
|
|
||||||
|
# 1. Check that all active hosts reported back N seconds ago
|
||||||
|
# 2. Check that no VM is running on a dead host
|
||||||
|
# 3. Migrate VMs if necessary
|
||||||
|
# 4. Check that no VMs have been pending for longer than Y seconds
|
||||||
|
|
||||||
|
|
||||||
|
print("Nothing is good, you should implement me")
|
19
uncloud/uncloud_vm/migrations/0003_auto_20200225_2028.py
Normal file
19
uncloud/uncloud_vm/migrations/0003_auto_20200225_2028.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 3.0.3 on 2020-02-25 20:28
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('uncloud_vm', '0002_auto_20200225_1952'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='vmproduct',
|
||||||
|
name='vmhost',
|
||||||
|
field=models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, to='uncloud_vm.VMHost'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -39,7 +39,9 @@ class VMProduct(models.Model):
|
||||||
editable=False)
|
editable=False)
|
||||||
vmhost = models.ForeignKey(VMHost,
|
vmhost = models.ForeignKey(VMHost,
|
||||||
on_delete=models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
editable=False)
|
editable=False,
|
||||||
|
blank=True,
|
||||||
|
null=True)
|
||||||
|
|
||||||
cores = models.IntegerField()
|
cores = models.IntegerField()
|
||||||
ram_in_gb = models.FloatField()
|
ram_in_gb = models.FloatField()
|
||||||
|
|
|
@ -1,9 +1,15 @@
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from .models import VMHost
|
from .models import VMHost, VMProduct
|
||||||
|
|
||||||
class VMHostSerializer(serializers.HyperlinkedModelSerializer):
|
class VMHostSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VMHost
|
model = VMHost
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
|
|
||||||
|
class VMProductSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = VMProduct
|
||||||
|
fields = '__all__'
|
||||||
|
|
|
@ -6,13 +6,24 @@ from django.shortcuts import get_object_or_404
|
||||||
from rest_framework import viewsets, permissions
|
from rest_framework import viewsets, permissions
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
||||||
|
from .models import VMHost, VMProduct
|
||||||
from opennebula.models import VM as OpenNebulaVM
|
from .serializers import VMHostSerializer, VMProductSerializer
|
||||||
|
|
||||||
from .models import VMHost
|
|
||||||
from .serializers import VMHostSerializer
|
|
||||||
|
|
||||||
class VMHostViewSet(viewsets.ModelViewSet):
|
class VMHostViewSet(viewsets.ModelViewSet):
|
||||||
serializer_class = VMHostSerializer
|
serializer_class = VMHostSerializer
|
||||||
queryset = VMHost.objects.all()
|
queryset = VMHost.objects.all()
|
||||||
permission_classes = [permissions.IsAdminUser]
|
permission_classes = [permissions.IsAdminUser]
|
||||||
|
|
||||||
|
class VMProductViewSet(viewsets.ModelViewSet):
|
||||||
|
permission_classes = [permissions.IsAuthenticated]
|
||||||
|
serializer_class = VMProductSerializer
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return VMProduct.objects.filter(owner=self.request.user)
|
||||||
|
|
||||||
|
def create(self, request):
|
||||||
|
serializer = VMProductSerializer(data=request.data, context={'request': request})
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
serializer.save(owner=request.user)
|
||||||
|
|
||||||
|
return Response(serializer.data)
|
||||||
|
|
Loading…
Reference in a new issue