vmhosts, restructure urls, etc.

This commit is contained in:
Nico Schottelius 2020-02-25 22:01:55 +01:00
parent d4b170f813
commit c7ded96658
9 changed files with 134 additions and 47 deletions

View file

@ -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'))
] ]

View file

@ -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:

View file

@ -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

View 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

View 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")

View 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'),
),
]

View file

@ -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()

View file

@ -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__'

View file

@ -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)