mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 19:26:48 +00:00
240 lines
9.1 KiB
Python
240 lines
9.1 KiB
Python
from admin.permissions import IsSuperUser
|
|
from computes import utils
|
|
from computes.models import Compute
|
|
from django.http import Http404
|
|
from django.shortcuts import get_object_or_404
|
|
from django.urls import reverse
|
|
from instances.models import Flavor, Instance
|
|
from instances.utils import migrate_instance
|
|
from instances.views import destroy as instance_destroy
|
|
from instances.views import (
|
|
force_off,
|
|
get_instance,
|
|
powercycle,
|
|
poweroff,
|
|
poweron,
|
|
resume,
|
|
suspend,
|
|
)
|
|
from drf_spectacular.utils import extend_schema
|
|
from operations import jobs
|
|
from operations.api.serializers import OperationSerializer
|
|
from rest_framework import permissions, status, viewsets
|
|
from rest_framework.decorators import action
|
|
from rest_framework.response import Response
|
|
from webvirtcloud.serializers import StatusSerializer
|
|
|
|
from .serializers import (
|
|
CreateInstanceSerializer,
|
|
FlavorSerializer,
|
|
InstanceDetailsSerializer,
|
|
InstanceSerializer,
|
|
MigrateSerializer,
|
|
)
|
|
|
|
|
|
def instance_action_response(action, request, pk, message):
|
|
response = action(request, pk)
|
|
if response.status_code >= 400:
|
|
return response
|
|
return Response({"status": message})
|
|
|
|
|
|
class InstancesViewSet(viewsets.ViewSet):
|
|
"""
|
|
A simple ViewSet for listing or retrieving ALL/Compute Instances.
|
|
"""
|
|
|
|
permission_classes = [permissions.IsAuthenticated]
|
|
serializer_class = InstanceSerializer
|
|
lookup_value_converter = "int"
|
|
|
|
def list(self, request):
|
|
|
|
if request.user.is_superuser or request.user.has_perm(
|
|
"instances.view_instances"
|
|
):
|
|
queryset = Instance.objects.all().prefetch_related("userinstance_set")
|
|
else:
|
|
queryset = Instance.objects.filter(
|
|
userinstance__user=request.user
|
|
).prefetch_related("userinstance_set")
|
|
serializer = InstanceSerializer(
|
|
queryset, many=True, context={"request": request}
|
|
)
|
|
|
|
return Response(serializer.data)
|
|
|
|
def retrieve(self, request, pk=None, compute_pk=None):
|
|
queryset = get_instance(request.user, pk)
|
|
serializer = InstanceSerializer(queryset, context={"request": request})
|
|
|
|
return Response(serializer.data)
|
|
|
|
|
|
class InstanceViewSet(viewsets.ViewSet):
|
|
"""
|
|
A simple ViewSet for listing or retrieving Compute Instances.
|
|
"""
|
|
|
|
permission_classes = [permissions.IsAuthenticated]
|
|
serializer_class = InstanceSerializer
|
|
lookup_value_converter = "int"
|
|
|
|
def list(self, request, compute_pk=None):
|
|
compute = get_object_or_404(Compute, pk=compute_pk)
|
|
|
|
is_admin = request.user.is_superuser or request.user.has_perm(
|
|
"instances.view_instances"
|
|
)
|
|
|
|
if not is_admin:
|
|
if not Instance.objects.filter(
|
|
compute=compute, userinstance__user=request.user
|
|
).exists():
|
|
return Response([])
|
|
|
|
utils.refresh_instance_database(compute)
|
|
|
|
if is_admin:
|
|
queryset = Instance.objects.filter(compute=compute).prefetch_related(
|
|
"userinstance_set"
|
|
)
|
|
else:
|
|
queryset = Instance.objects.filter(
|
|
compute=compute, userinstance__user=request.user
|
|
).prefetch_related("userinstance_set")
|
|
serializer = InstanceSerializer(
|
|
queryset, many=True, context={"request": request}
|
|
)
|
|
|
|
return Response(serializer.data)
|
|
|
|
@extend_schema(responses=InstanceDetailsSerializer)
|
|
def retrieve(self, request, pk=None, compute_pk=None):
|
|
queryset = get_instance(request.user, pk)
|
|
if compute_pk is not None and str(queryset.compute_id) != str(compute_pk):
|
|
raise Http404()
|
|
serializer = InstanceDetailsSerializer(queryset, context={"request": request})
|
|
|
|
return Response(serializer.data)
|
|
|
|
@extend_schema(responses=StatusSerializer)
|
|
def destroy(self, request, pk=None, compute_pk=None):
|
|
queryset = get_instance(request.user, pk, perm_type="delete")
|
|
if compute_pk is not None and str(queryset.compute_id) != str(compute_pk):
|
|
raise Http404()
|
|
return instance_action_response(instance_destroy, request, pk, "Instance is destroyed")
|
|
|
|
@extend_schema(request=None, responses=StatusSerializer)
|
|
@action(detail=True, methods=["post"])
|
|
def poweron(self, request, pk=None, compute_pk=None):
|
|
queryset = get_instance(request.user, pk, perm_type="power")
|
|
if compute_pk is not None and str(queryset.compute_id) != str(compute_pk):
|
|
raise Http404()
|
|
return instance_action_response(poweron, request, pk, "poweron command send")
|
|
|
|
@extend_schema(request=None, responses=StatusSerializer)
|
|
@action(detail=True, methods=["post"])
|
|
def poweroff(self, request, pk=None, compute_pk=None):
|
|
queryset = get_instance(request.user, pk, perm_type="power")
|
|
if compute_pk is not None and str(queryset.compute_id) != str(compute_pk):
|
|
raise Http404()
|
|
return instance_action_response(poweroff, request, pk, "poweroff command send")
|
|
|
|
@extend_schema(request=None, responses=StatusSerializer)
|
|
@action(detail=True, methods=["post"])
|
|
def powercycle(self, request, pk=None, compute_pk=None):
|
|
queryset = get_instance(request.user, pk, perm_type="power")
|
|
if compute_pk is not None and str(queryset.compute_id) != str(compute_pk):
|
|
raise Http404()
|
|
return instance_action_response(powercycle, request, pk, "powercycle command send")
|
|
|
|
@extend_schema(request=None, responses=StatusSerializer)
|
|
@action(detail=True, methods=["post"])
|
|
def forceoff(self, request, pk=None, compute_pk=None):
|
|
queryset = get_instance(request.user, pk, perm_type="power")
|
|
if compute_pk is not None and str(queryset.compute_id) != str(compute_pk):
|
|
raise Http404()
|
|
return instance_action_response(force_off, request, pk, "force off command send")
|
|
|
|
@extend_schema(request=None, responses=StatusSerializer)
|
|
@action(detail=True, methods=["post"])
|
|
def suspend(self, request, pk=None, compute_pk=None):
|
|
queryset = get_instance(request.user, pk)
|
|
if compute_pk is not None and str(queryset.compute_id) != str(compute_pk):
|
|
raise Http404()
|
|
return instance_action_response(suspend, request, pk, "suspend command send")
|
|
|
|
@extend_schema(request=None, responses=StatusSerializer)
|
|
@action(detail=True, methods=["post"])
|
|
def resume(self, request, pk=None, compute_pk=None):
|
|
queryset = get_instance(request.user, pk)
|
|
if compute_pk is not None and str(queryset.compute_id) != str(compute_pk):
|
|
raise Http404()
|
|
return instance_action_response(resume, request, pk, "resume command send")
|
|
|
|
|
|
class MigrateViewSet(viewsets.ViewSet):
|
|
"""
|
|
A viewset for migrating instances.
|
|
"""
|
|
|
|
permission_classes = [IsSuperUser]
|
|
serializer_class = MigrateSerializer
|
|
queryset = ""
|
|
|
|
@extend_schema(responses=StatusSerializer)
|
|
def create(self, request):
|
|
serializer = MigrateSerializer(data=request.data)
|
|
if serializer.is_valid():
|
|
instance = serializer.validated_data["instance"]
|
|
target_host = serializer.validated_data["target_compute"]
|
|
options = {
|
|
name: serializer.validated_data.get(name, False)
|
|
for name in ("live", "unsafe", "offline", "autoconverge", "compress")
|
|
}
|
|
# migrate_instance logs the outcome; it returns when it is done
|
|
mode = migrate_instance(target_host, instance, request.user, **options)
|
|
|
|
return Response({"status": f"instance is migrated ({mode})"})
|
|
else:
|
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
|
|
class FlavorViewSet(viewsets.ModelViewSet):
|
|
"""
|
|
API endpoint that allows flavor to be viewed or edited.
|
|
"""
|
|
|
|
queryset = Flavor.objects.all().order_by("id")
|
|
lookup_value_converter = "int"
|
|
serializer_class = FlavorSerializer
|
|
|
|
def get_permissions(self):
|
|
if self.action in ["list", "retrieve"]:
|
|
return [permissions.IsAuthenticated()]
|
|
return [IsSuperUser()]
|
|
|
|
|
|
class CreateInstanceViewSet(viewsets.ViewSet):
|
|
"""
|
|
A viewset for creating instances.
|
|
"""
|
|
|
|
permission_classes = [IsSuperUser]
|
|
serializer_class = CreateInstanceSerializer
|
|
queryset = ""
|
|
|
|
@extend_schema(responses={202: OperationSerializer, 400: dict})
|
|
def create(self, request, compute_pk=None, arch=None, machine=None):
|
|
serializer = CreateInstanceSerializer(data=request.data,
|
|
context={"compute_pk": compute_pk, "arch": arch, "machine": machine})
|
|
if not serializer.is_valid():
|
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
|
data = dict(serializer.validated_data)
|
|
key = data.pop("submission_key")
|
|
op = jobs.submit("instance.create", request.user, {**data, "compute": compute_pk, "arch": arch,
|
|
"machine": machine}, key)
|
|
return Response(OperationSerializer(op, context={"request": request}).data, status=status.HTTP_202_ACCEPTED,
|
|
headers={"Location": reverse("operation-detail", args=[op.pk])})
|