Commit 140a1932 by Karsa Zoltán István

add rest endpoints to node, vlan, deploy, shutdown, destroy

parent 60007ab6
from rest_framework.renderers import JSONRenderer
from rest_framework import serializers
from vm.models import Instance, InstanceTemplate, Lease, Interface
from vm.models import Instance, InstanceTemplate, Lease, Interface, Node
from firewall.models import Vlan
from storage.models import Disk
class NodeSerializer(serializers.ModelSerializer):
class Meta:
model = Node
fields = [ 'id', 'name', 'priority', 'host', 'enabled', 'schedule_enabled',
'traits', 'overcommit', 'ram_weight', 'cpu_weight', 'time_stamp' ]
class InstanceTemplateSerializer(serializers.ModelSerializer):
class Meta:
model = InstanceTemplate
......@@ -42,7 +49,10 @@ class InstanceSerializer(serializers.ModelSerializer):
fields = ['id', 'name', 'description', 'status', 'owner', 'access_method', 'boot_menu', 'pw', 'is_base',
'lease', 'raw_data', 'cloud_init', 'ci_meta_data', 'ci_user_data', 'system', 'req_traits',
'has_agent', 'num_cores', 'ram_size', 'max_ram_size', 'arch', 'priority', 'disks', 'node', 'ipv4addr', 'ipv6addr']
extra_kwargs = {'disks': {'required': False}}
extra_kwargs = {
'disks': {'required': False, 'allow_empty': True,},
'req_traits': {'required': False, 'allow_empty': True,}
}
class InterfaceSerializer(serializers.ModelSerializer):
......@@ -58,10 +68,21 @@ class VlanSerializer(serializers.ModelSerializer):
class CreateDiskSerializer(serializers.Serializer):
size = serializers.IntegerField()
size = serializers.CharField(max_length=50)
name = serializers.CharField(max_length=100)
class ResizeDiskSerializer(serializers.Serializer):
size = serializers.CharField(max_length=50)
disk = serializers.IntegerField()
class DownloadDiskSerializer(serializers.Serializer):
url = serializers.CharField(max_length=500)
name = serializers.CharField(max_length=100)
\ No newline at end of file
name = serializers.CharField(max_length=100)
class VMDeploySerializer(serializers.Serializer):
node = serializers.IntegerField(required=False)
class Meta:
extra_kwargs = {'node': {'required': False, 'allow_null': True}}
\ No newline at end of file
......@@ -56,19 +56,22 @@ from .views import (
NodeActivityView,
UserList, TemplateREST, LeaseREST, DiskRest, InstanceREST,
InterfaceREST, InstanceFromTemplateREST, InstanceFTforUsersREST,
DownloadDiskREST, GetInstanceREST, GetInterfaceREST,
GetLeaseREST, GetDiskRest,
DownloadDiskREST, GetInstanceREST, GetInterfaceREST, ShutdownInstanceREST,
GetLeaseREST, GetDiskRest, DeployInstanceREST, CreateDiskREST,
VlanREST, ResizeDiskREST, GetVlanREST,
StorageDetail, DiskDetail,
MessageList, MessageDetail, MessageCreate, MessageDelete,
EnableTwoFactorView, DisableTwoFactorView,
AclUserGroupAutocomplete, AclUserAutocomplete,
RescheduleView, GroupImportView, GroupExportView,
)
from .views.node import node_ops
from .views.node import node_ops, NodeREST, GetNodeREST
from .views.vm import vm_ops, vm_mass_ops
urlpatterns = [
path('acpi/vm/', InstanceREST.as_view()),
path('acpi/node/', NodeREST.as_view()),
path('acpi/node/<int:pk>/', GetNodeREST.as_view()),
path('acpi/vm/<int:pk>/', GetInstanceREST.as_view()),
path('acpi/template/', TemplateREST.as_view()),
path('acpi/ft/', InstanceFromTemplateREST.as_view()),
......@@ -77,9 +80,15 @@ urlpatterns = [
path('acpi/disk/', DiskRest.as_view()),
path('acpi/disk/<int:pk>/', GetDiskRest.as_view()),
path('acpi/interface/', InterfaceREST.as_view()),
path('acpi/vlan/', VlanREST.as_view()),
path('acpi/vlan/<int:pk>/', GetVlanREST.as_view()),
path('acpi/interface/<int:pk>/', GetInterfaceREST.as_view()),
path('acpi/ftusers/', InstanceFTforUsersREST.as_view()),
path('acpi/vm/<int:pk>/downloaddisk/', DownloadDiskREST.as_view()),
path('acpi/vm/<int:pk>/createdisk/', CreateDiskREST.as_view()),
path('acpi/vm/<int:pk>/deploy/', DeployInstanceREST.as_view()),
path('acpi/vm/<int:pk>/shutdown/', ShutdownInstanceREST.as_view()),
path('acpi/vm/<int:pk>/resizedisk/', ResizeDiskREST.as_view()),
url(r'^$', IndexView.as_view(), name="dashboard.index"),
url(r"^profile/list/$", UserList.as_view(),
name="dashboard.views.user-list"),
......
......@@ -31,6 +31,12 @@ from django.template.loader import render_to_string
from django.utils.translation import ugettext as _
from django.views.generic import DetailView, TemplateView, View
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.parsers import JSONParser
from rest_framework.authentication import TokenAuthentication, BasicAuthentication
from rest_framework.permissions import IsAdminUser
from braces.views import LoginRequiredMixin, SuperuserRequiredMixin
from django_tables2 import SingleTableView
......@@ -45,6 +51,35 @@ from .util import AjaxOperationMixin, OperationView, GraphMixin, DeleteViewBase
from manager.mancelery import crontab_parser
from dashboard.serializers import NodeSerializer
class NodeREST(APIView):
authentication_classes = [TokenAuthentication,BasicAuthentication]
permission_classes = [IsAdminUser]
def get(self, request, format=None):
if request.query_params.get('name'):
try:
template = Node.objects.filter(name__istartswith=request.query_params.get('name')).get()
serializer = NodeSerializer(template, many=False)
return JsonResponse(serializer.data, safe=False)
except:
return JsonResponse({}, status=404)
templates = Node.objects.all()
serializer = NodeSerializer(templates, many=True)
return JsonResponse(serializer.data, safe=False)
class GetNodeREST(APIView):
authentication_classes = [TokenAuthentication,BasicAuthentication]
permission_classes = [IsAdminUser]
def get(self, request, pk, format=None):
interface = Node.objects.get(pk=pk)
serializer = NodeSerializer(interface, many=False)
return JsonResponse(serializer.data, safe=False)
def get_operations(instance, user):
ops = []
......
......@@ -20,6 +20,7 @@ from datetime import timedelta
import json
import logging
from string import Template
from xml.dom import NotFoundErr
from django.contrib import messages
from django.contrib.auth.models import User
......@@ -283,6 +284,13 @@ class LeaseREST(APIView):
permission_classes = [IsAdminUser]
def get(self, request, format=None):
if request.query_params.get('name'):
try:
template = Lease.objects.filter(name__istartswith=request.query_params.get('name')).get()
serializer = LeaseSerializer(template, many=False)
return JsonResponse(serializer.data, safe=False)
except:
return JsonResponse({}, status=404)
templates = Lease.objects.all()
serializer = LeaseSerializer(templates, many=True)
return JsonResponse(serializer.data, safe=False)
......
......@@ -21,6 +21,7 @@ import logging
from collections import OrderedDict
from os import getenv
from urllib import response
from xml.dom import ValidationErr
from django.conf import settings
from django.contrib import messages
......@@ -43,7 +44,7 @@ from django.views.generic import (
)
from braces.views import SuperuserRequiredMixin, LoginRequiredMixin
from vm.operations import DownloadDiskOperation
from vm.operations import DeployOperation, DestroyOperation, DownloadDiskOperation, ShutdownOperation, RenewOperation, ResizeDiskOperation
from common.models import (
create_readable, HumanReadableException, fetch_human_exception,
......@@ -78,6 +79,7 @@ from request.forms import LeaseRequestForm, TemplateRequestForm
from ..models import Favourite, pwgen
from manager.scheduler import has_traits
import re
try:
# Python 2: "unicode" is built-in
......@@ -95,7 +97,36 @@ from rest_framework.parsers import JSONParser
from rest_framework.authentication import TokenAuthentication, BasicAuthentication
from rest_framework.permissions import IsAdminUser
from dashboard.serializers import InstanceSerializer, InterfaceSerializer, CreateDiskSerializer, DownloadDiskSerializer
from dashboard.serializers import (
DiskSerializer, InstanceSerializer, InterfaceSerializer, CreateDiskSerializer, DownloadDiskSerializer,
VMDeploySerializer, VlanSerializer, ResizeDiskSerializer
)
class VlanREST(APIView):
authentication_classes = [TokenAuthentication,BasicAuthentication]
permission_classes = [IsAdminUser]
def get(self, request, format=None):
if request.query_params.get('name'):
try:
template = Vlan.objects.filter(name__istartswith=request.query_params.get('name')).get()
serializer = VlanSerializer(template, many=False)
return JsonResponse(serializer.data, safe=False)
except:
return JsonResponse({}, status=404)
templates = Vlan.objects.all()
serializer = VlanSerializer(templates, many=True)
return JsonResponse(serializer.data, safe=False)
class GetVlanREST(APIView):
authentication_classes = [TokenAuthentication,BasicAuthentication]
permission_classes = [IsAdminUser]
def get(self, request, pk, format=None):
interface = Vlan.objects.get(pk=pk)
serializer = VlanSerializer(interface, many=False)
return JsonResponse(serializer.data, safe=False)
class InterfaceREST(APIView):
......@@ -150,6 +181,8 @@ class InstanceREST(APIView):
with inst.activity(code_suffix='create',
readable_name=ugettext_noop("create instance (REST)"),
on_commit=__on_commit, user=inst.owner) as act:
lease = Lease.objects.get(pk=str(data['lease']))
RenewOperation(inst).call(user=request.user, lease=lease, force=True, save=True)
for net in networks:
Interface.create(instance=inst, vlan=net.vlan,
owner=inst.owner, managed=net.managed,
......@@ -173,6 +206,56 @@ class GetInstanceREST(APIView):
serializer = InstanceSerializer(instance, many=False)
return JsonResponse(serializer.data, safe=False)
def post(self, request, pk, format=None):
instance = Instance.objects.get(pk=pk)
data = JSONParser().parse(request)
deploy = VMDeploySerializer(data=data)
if deploy.is_valid():
if 'node' in data:
selected = Node.objects.get(pk=int(data['node']))
DeployOperation(instance).call(node=selected, user=instance.owner)
else:
DeployOperation(instance).call(node=None, user=instance.owner)
serializer = InstanceSerializer(instance, many=False)
return JsonResponse(serializer.data, safe=False)
return JsonResponse(deploy.errors, status=400)
def delete(self, request, pk, format=None):
instance = Instance.objects.get(pk=pk)
DestroyOperation(instance).call(user=instance.owner)
serializer = InstanceSerializer(instance, many=False)
return JsonResponse(serializer.data, status=401)
class DeployInstanceREST(APIView):
authentication_classes = [TokenAuthentication,BasicAuthentication]
permission_classes = [IsAdminUser]
def post(self, request, pk, format=None):
instance = Instance.objects.get(pk=pk)
data = JSONParser().parse(request)
deploy = VMDeploySerializer(data=data)
if deploy.is_valid():
if 'node' in data:
selected = Node.objects.get(pk=int(data['node']))
DeployOperation(instance).call(node=selected, user=instance.owner)
else:
DeployOperation(instance).call(node=None, user=instance.owner)
serializer = InstanceSerializer(instance, many=False)
return JsonResponse(serializer.data, safe=False)
return JsonResponse(deploy.errors, status=400)
class ShutdownInstanceREST(APIView):
authentication_classes = [TokenAuthentication,BasicAuthentication]
permission_classes = [IsAdminUser]
def post(self, request, pk, format=None):
instance = Instance.objects.get(pk=pk)
ShutdownOperation(instance).call(user=instance.owner)
serializer = InstanceSerializer(instance, many=False)
return JsonResponse(serializer.data, status=400)
class DownloadDiskREST(APIView):
authentication_classes = [TokenAuthentication,BasicAuthentication]
......@@ -186,11 +269,28 @@ class DownloadDiskREST(APIView):
disk_url = str(data['url'])
disk_name = str(data['name'])
instance = Instance.objects.get(pk=vm_id)
old_disks = list(instance.disks.all())
DownloadDiskOperation(instance)._async(name=disk_name, url=disk_url, user=instance.owner)
ret = InstanceSerializer(instance, many=False)
return JsonResponse(ret.data, status=201)
new_disks = instance.disks.all()
for d in new_disks:
if d not in old_disks:
ret = DiskSerializer(d, many=False)
return JsonResponse(ret.data, status=201)
return JsonResponse(serializer.errors, status=400)
def size_util(size: str):
size_dict = {
"GB": 1000000000,
"Gi": 1073741824,
"MB": 1000000,
"Mi": 1048576,
"KB": 1000,
"Ki": 1024,
}
res = re.search(r"(\d*)\s*(\w*)", size)
if res and res.group(1) and res.group(2):
return int(res.group(1)) * size_dict[str(res.group(2))]
raise ValidationErr()
class CreateDiskREST(APIView):
authentication_classes = [TokenAuthentication,BasicAuthentication]
......@@ -201,12 +301,35 @@ class CreateDiskREST(APIView):
serializer = CreateDiskSerializer(data=data)
if serializer.is_valid():
vm_id = pk
disk_size = int(data['size'])
disk_size = str(size_util(str(data['size'])))
disk_name = str(data['name'])
instance = Instance.objects.get(pk=vm_id)
old_disks = list(instance.disks.all())
instance.create_disk(size=disk_size, user=instance.owner,
name=disk_name, activity=None)
ret = InstanceSerializer(instance, many=False)
new_disks = instance.disks.all()
for d in new_disks:
if d not in old_disks:
ret = DiskSerializer(d, many=False)
return JsonResponse(ret.data, status=201)
return JsonResponse(serializer.errors, status=400)
class ResizeDiskREST(APIView):
authentication_classes = [TokenAuthentication,BasicAuthentication]
permission_classes = [IsAdminUser]
def post(self, request, pk, format=None):
data = JSONParser().parse(request)
serializer = ResizeDiskSerializer(data=data)
if serializer.is_valid():
vm_id = pk
disk_size = str(size_util(str(data['size'])))
disk_id = str(data['disk'])
instance = Instance.objects.get(pk=vm_id)
disk = Disk.objects.get(pk=disk_id)
ResizeDiskOperation(instance).call(disk=disk, size=disk_size, user=instance.owner)
ret = DiskSerializer(disk, many=False)
return JsonResponse(ret.data, status=201)
return JsonResponse(serializer.errors, status=400)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment