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…
	
	Add table
		Add a link
		
	
		Reference in a new issue