mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 11:16:47 +00:00
fix(api): a volume's size is GiB to create and bytes to read, each documented
One serializer created volumes and read them: size was GiB in a request and bytes in an answer, the same field in the schema. A client that sent back a size it read asked for a volume 2**30 times as large. A new volume is CreateVolumeSerializer (size in GiB); a volume read is VolumeSerializer (allocation and size in bytes), and the schema says so, as for the pools' size and free space.
This commit is contained in:
parent
0610c23a34
commit
470cc9860e
3 changed files with 30 additions and 10 deletions
|
|
@ -7,7 +7,7 @@ class StoragesSerializer(serializers.Serializer):
|
|||
name = serializers.CharField(max_length=20)
|
||||
status = serializers.IntegerField()
|
||||
type = serializers.CharField(max_length=100)
|
||||
size = serializers.IntegerField()
|
||||
size = serializers.IntegerField(help_text="Capacity in bytes")
|
||||
volumes = serializers.IntegerField()
|
||||
|
||||
|
||||
|
|
@ -15,8 +15,8 @@ class StorageSerializer(serializers.Serializer):
|
|||
"""A storage pool's details."""
|
||||
|
||||
state = serializers.IntegerField()
|
||||
size = serializers.IntegerField()
|
||||
free = serializers.IntegerField()
|
||||
size = serializers.IntegerField(help_text="Capacity in bytes")
|
||||
free = serializers.IntegerField(help_text="Free space in bytes")
|
||||
status = serializers.CharField(max_length=128)
|
||||
path = serializers.CharField(max_length=128)
|
||||
type = serializers.CharField(max_length=128)
|
||||
|
|
@ -26,10 +26,20 @@ class StorageSerializer(serializers.Serializer):
|
|||
|
||||
|
||||
class VolumeSerializer(serializers.Serializer):
|
||||
# what the web form (storages.forms.CreateVolumeForm) takes
|
||||
"""A volume as the API reads it."""
|
||||
|
||||
name = serializers.CharField()
|
||||
type = serializers.CharField()
|
||||
allocation = serializers.IntegerField(help_text="Bytes the volume takes in its pool")
|
||||
size = serializers.IntegerField(help_text="Capacity in bytes")
|
||||
|
||||
|
||||
class CreateVolumeSerializer(serializers.Serializer):
|
||||
"""A new volume, as the web form (storages.forms.CreateVolumeForm) takes it:
|
||||
its size in GiB, where a volume read back tells bytes."""
|
||||
|
||||
name = serializers.RegexField(r"^[a-zA-Z0-9._-]+$", max_length=120)
|
||||
type = serializers.ChoiceField(choices=[("qcow2", "qcow2 (recommended)"), ("qcow", "qcow"), ("raw", "raw")],
|
||||
label="Format")
|
||||
allocation = serializers.IntegerField(read_only=True)
|
||||
size = serializers.IntegerField(min_value=1) # GiB
|
||||
meta_prealloc = serializers.BooleanField(write_only=True, default=False)
|
||||
size = serializers.IntegerField(min_value=1, help_text="Capacity in GiB")
|
||||
meta_prealloc = serializers.BooleanField(default=False)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ from rest_framework.response import Response
|
|||
from vrtManager.storage import wvmStorage, wvmStorages
|
||||
from webvirtcloud.serializers import ErrorSerializer, StatusSerializer
|
||||
|
||||
from .serializers import StorageSerializer, StoragesSerializer, VolumeSerializer
|
||||
from .serializers import CreateVolumeSerializer, StorageSerializer, StoragesSerializer, VolumeSerializer
|
||||
|
||||
|
||||
class StorageViewSet(viewsets.ViewSet):
|
||||
|
|
@ -170,7 +170,7 @@ class VolumeViewSet(viewsets.ViewSet):
|
|||
|
||||
return Response(serializer.data)
|
||||
|
||||
@extend_schema(responses={200: StatusSerializer, 400: dict, 409: ErrorSerializer})
|
||||
@extend_schema(request=CreateVolumeSerializer, responses={200: StatusSerializer, 400: dict, 409: ErrorSerializer})
|
||||
def create(self, request, storage_pk=None, compute_pk=None):
|
||||
compute = get_object_or_404(Compute, pk=compute_pk)
|
||||
|
||||
|
|
@ -178,7 +178,7 @@ class VolumeViewSet(viewsets.ViewSet):
|
|||
compute.hostname, compute.login, compute.password, compute.type, storage_pk
|
||||
)
|
||||
|
||||
serializer = VolumeSerializer(data=request.data)
|
||||
serializer = CreateVolumeSerializer(data=request.data)
|
||||
if serializer.is_valid():
|
||||
subject, action = f"Storage pool {storage_pk}", f"add volume {serializer.validated_data['name']}"
|
||||
state = conn.is_active()
|
||||
|
|
|
|||
|
|
@ -36,6 +36,16 @@ class APISchemaTestCase(TestCase):
|
|||
self.assertEqual(getattr(client, method)("/api/v1/nothere/").status_code, 404)
|
||||
self.assertEqual(client.get("/api/schema/").status_code, 200)
|
||||
|
||||
def test_a_volume_s_size_is_gib_to_create_and_bytes_to_read(self):
|
||||
# one serializer had both: a size read back and sent again asked 2**30 times as much
|
||||
schema = SchemaGenerator().get_schema(request=None, public=True)
|
||||
create = schema["paths"]["/api/v1/computes/{compute_pk}/storages/{storage_pk}/volumes/"]["post"]
|
||||
self.assertEqual(create["requestBody"]["content"]["application/json"]["schema"]["$ref"],
|
||||
"#/components/schemas/CreateVolume")
|
||||
components = schema["components"]["schemas"]
|
||||
self.assertEqual(components["CreateVolume"]["properties"]["size"]["description"], "Capacity in GiB")
|
||||
self.assertEqual(components["Volume"]["properties"]["size"]["description"], "Capacity in bytes")
|
||||
|
||||
def test_a_refusal_s_body_is_documented_with_its_409(self):
|
||||
schema = SchemaGenerator().get_schema(request=None, public=True)
|
||||
poweron = schema["paths"]["/api/v1/computes/{compute_pk}/instances/{id}/poweron/"]["post"]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue