mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-09 03:36:48 +00:00
- Routers use path converters (use_regex_path=False): computes, instances and flavors take <int:...> ids, so non-numeric ids get 404 and drf-spectacular derives the parameter types itself. - Each method declares what it really returns: detail serializers, a shared StatusSerializer for status-only replies, no request body for actions. Instance properties used by the details serializer get return type hints. - The create-instance API drops the firmware field. Its only accepted value was "" (BIOS), which produced an empty, invalid enum, and the UEFI branch behind it was unreachable. Clients that still send it are unaffected; DRF ignores unknown fields. The schema now passes spectacular --validate --fail-on-warn; a test keeps it that way.
203 lines
6.9 KiB
Python
203 lines
6.9 KiB
Python
from admin.permissions import IsSuperUser
|
|
from appsettings.settings import app_settings
|
|
from computes.models import Compute
|
|
from django.shortcuts import get_object_or_404
|
|
from drf_spectacular.utils import extend_schema, inline_serializer
|
|
from rest_framework import serializers, status, viewsets
|
|
from rest_framework.decorators import action
|
|
from rest_framework.response import Response
|
|
from vrtManager.storage import wvmStorage, wvmStorages
|
|
from webvirtcloud.serializers import StatusSerializer
|
|
|
|
from .serializers import StorageSerializer, StoragesSerializer, VolumeSerializer
|
|
|
|
|
|
class StorageViewSet(viewsets.ViewSet):
|
|
"""
|
|
A viewset for listing retrieving storages.
|
|
"""
|
|
|
|
permission_classes = [IsSuperUser]
|
|
serializer_class = StoragesSerializer
|
|
lookup_value_converter = "str"
|
|
|
|
def list(self, request, compute_pk=None):
|
|
|
|
compute = get_object_or_404(Compute, pk=compute_pk)
|
|
|
|
conn = wvmStorages(
|
|
compute.hostname, compute.login, compute.password, compute.type
|
|
)
|
|
queryset = conn.get_storages_info()
|
|
|
|
serializer = StoragesSerializer(
|
|
queryset, many=True, context={"request": request}
|
|
)
|
|
|
|
return Response(serializer.data)
|
|
|
|
@extend_schema(responses=StorageSerializer)
|
|
def retrieve(self, request, pk=None, compute_pk=None):
|
|
compute = get_object_or_404(Compute, pk=compute_pk)
|
|
|
|
conn = wvmStorage(
|
|
compute.hostname, compute.login, compute.password, compute.type, pk
|
|
)
|
|
|
|
infoset = {
|
|
"state": conn.is_active(),
|
|
"size": conn.get_size()[0],
|
|
"free": conn.get_size()[1],
|
|
"status": conn.get_status(),
|
|
"path": conn.get_target_path(),
|
|
"type": conn.get_type(),
|
|
"autostart": conn.get_autostart(),
|
|
"volumes": conn.update_volumes(),
|
|
}
|
|
|
|
serializer = StorageSerializer(
|
|
infoset, many=False, context={"request": request}
|
|
)
|
|
return Response(serializer.data)
|
|
|
|
@extend_schema(request=None, responses=StatusSerializer)
|
|
@action(detail=True, methods=["post"])
|
|
def start(self, request, pk=None, compute_pk=None):
|
|
compute = get_object_or_404(Compute, pk=compute_pk)
|
|
|
|
conn = wvmStorage(
|
|
compute.hostname, compute.login, compute.password, compute.type, pk
|
|
)
|
|
ret = conn.start()
|
|
conn.close()
|
|
return Response({"status": "Pool start command send: " + str(ret)})
|
|
|
|
@extend_schema(request=None, responses=StatusSerializer)
|
|
@action(detail=True, methods=["post"])
|
|
def stop(self, request, pk=None, compute_pk=None):
|
|
compute = get_object_or_404(Compute, pk=compute_pk)
|
|
|
|
conn = wvmStorage(
|
|
compute.hostname, compute.login, compute.password, compute.type, pk
|
|
)
|
|
ret = conn.stop()
|
|
conn.close()
|
|
return Response({"status": "Pool stop command send: " + str(ret)})
|
|
|
|
@extend_schema(request=None, responses=StatusSerializer)
|
|
@action(detail=True, methods=["post"])
|
|
def refresh(self, request, pk=None, compute_pk=None):
|
|
compute = get_object_or_404(Compute, pk=compute_pk)
|
|
|
|
conn = wvmStorage(
|
|
compute.hostname, compute.login, compute.password, compute.type, pk
|
|
)
|
|
ret = conn.refresh()
|
|
conn.close()
|
|
return Response({"status": "Pool refresh command send: " + str(ret)})
|
|
|
|
@extend_schema(
|
|
request=None,
|
|
responses=inline_serializer("PoolXML", {"return": serializers.CharField()}),
|
|
)
|
|
@action(detail=True, methods=["post"])
|
|
def XML_description(self, request, pk=None, compute_pk=None):
|
|
compute = get_object_or_404(Compute, pk=compute_pk)
|
|
|
|
conn = wvmStorage(
|
|
compute.hostname, compute.login, compute.password, compute.type, pk
|
|
)
|
|
ret = conn._XMLDesc(0)
|
|
conn.close()
|
|
return Response({"return": str(ret)})
|
|
|
|
|
|
class VolumeViewSet(viewsets.ViewSet):
|
|
|
|
"""
|
|
A simple ViewSet for listing or retrieving Storage Volumes.
|
|
"""
|
|
|
|
permission_classes = [IsSuperUser]
|
|
serializer_class = VolumeSerializer
|
|
lookup_value_converter = "str"
|
|
|
|
def list(self, request, storage_pk=None, compute_pk=None):
|
|
|
|
compute = get_object_or_404(Compute, pk=compute_pk)
|
|
|
|
conn = wvmStorage(
|
|
compute.hostname, compute.login, compute.password, compute.type, storage_pk
|
|
)
|
|
state = conn.is_active()
|
|
|
|
if state:
|
|
conn.refresh()
|
|
volume_queryset = conn.update_volumes()
|
|
else:
|
|
volume_queryset = None
|
|
conn.close()
|
|
serializer = VolumeSerializer(
|
|
volume_queryset, many=True, context={"request": request}
|
|
)
|
|
|
|
return Response(serializer.data)
|
|
|
|
def retrieve(self, request, storage_pk=None, compute_pk=None, pk=None):
|
|
compute = get_object_or_404(Compute, pk=compute_pk)
|
|
|
|
conn = wvmStorage(
|
|
compute.hostname, compute.login, compute.password, compute.type, storage_pk
|
|
)
|
|
state = conn.is_active()
|
|
|
|
volume_queryset = conn.get_volume_details(pk) if state else None
|
|
conn.close()
|
|
serializer = VolumeSerializer(
|
|
volume_queryset, many=False, context={"request": request}
|
|
)
|
|
|
|
return Response(serializer.data)
|
|
|
|
@extend_schema(responses=StatusSerializer)
|
|
def create(self, request, storage_pk=None, compute_pk=None):
|
|
compute = get_object_or_404(Compute, pk=compute_pk)
|
|
|
|
conn = wvmStorage(
|
|
compute.hostname, compute.login, compute.password, compute.type, storage_pk
|
|
)
|
|
|
|
serializer = VolumeSerializer(data=request.data)
|
|
if serializer.is_valid():
|
|
state = conn.is_active()
|
|
if state:
|
|
conn.refresh()
|
|
ret = conn.create_volume(
|
|
serializer.validated_data["name"],
|
|
serializer.validated_data["size"],
|
|
serializer.validated_data["type"],
|
|
serializer.validated_data["meta_prealloc"],
|
|
int(app_settings.INSTANCE_VOLUME_DEFAULT_OWNER_UID),
|
|
int(app_settings.INSTANCE_VOLUME_DEFAULT_OWNER_GID),
|
|
)
|
|
conn.close()
|
|
return Response({"status": "Volume: " + ret + " is created"})
|
|
else:
|
|
return Response({"status": "Pool is not active"})
|
|
else:
|
|
return Response({"status": "Data is not right for create volume"})
|
|
|
|
@extend_schema(responses=StatusSerializer)
|
|
def destroy(self, request, storage_pk=None, compute_pk=None, pk=None):
|
|
compute = get_object_or_404(Compute, pk=compute_pk)
|
|
|
|
conn = wvmStorage(
|
|
compute.hostname, compute.login, compute.password, compute.type, storage_pk
|
|
)
|
|
|
|
if conn.is_active():
|
|
conn.del_volume(pk)
|
|
conn.close()
|
|
return Response({"status": "Volume: " + pk + " is deleted"})
|
|
else:
|
|
return Response({"status": "Pool is not active"})
|