diff --git a/scaleway-async/scaleway_async/block/v1/__init__.py b/scaleway-async/scaleway_async/block/v1/__init__.py new file mode 100644 index 000000000..1e48ec134 --- /dev/null +++ b/scaleway-async/scaleway_async/block/v1/__init__.py @@ -0,0 +1,75 @@ +# This file was automatically generated. DO NOT EDIT. +# If you have any remark or suggestion do not hesitate to open an issue. +from .types import ListSnapshotsRequestOrderBy +from .types import ListVolumesRequestOrderBy +from .types import ReferenceStatus +from .content import REFERENCE_TRANSIENT_STATUSES +from .types import ReferenceType +from .types import SnapshotStatus +from .content import SNAPSHOT_TRANSIENT_STATUSES +from .types import StorageClass +from .types import VolumeStatus +from .content import VOLUME_TRANSIENT_STATUSES +from .types import Reference +from .types import SnapshotParentVolume +from .types import VolumeSpecifications +from .types import CreateVolumeRequestFromEmpty +from .types import CreateVolumeRequestFromSnapshot +from .types import Snapshot +from .types import VolumeType +from .types import Volume +from .types import CreateSnapshotRequest +from .types import CreateVolumeRequest +from .types import DeleteSnapshotRequest +from .types import DeleteVolumeRequest +from .types import ExportSnapshotToObjectStorageRequest +from .types import GetSnapshotRequest +from .types import GetVolumeRequest +from .types import ImportSnapshotFromObjectStorageRequest +from .types import ListSnapshotsRequest +from .types import ListSnapshotsResponse +from .types import ListVolumeTypesRequest +from .types import ListVolumeTypesResponse +from .types import ListVolumesRequest +from .types import ListVolumesResponse +from .types import UpdateSnapshotRequest +from .types import UpdateVolumeRequest +from .api import BlockV1API + +__all__ = [ + "ListSnapshotsRequestOrderBy", + "ListVolumesRequestOrderBy", + "ReferenceStatus", + "REFERENCE_TRANSIENT_STATUSES", + "ReferenceType", + "SnapshotStatus", + "SNAPSHOT_TRANSIENT_STATUSES", + "StorageClass", + "VolumeStatus", + "VOLUME_TRANSIENT_STATUSES", + "Reference", + "SnapshotParentVolume", + "VolumeSpecifications", + "CreateVolumeRequestFromEmpty", + "CreateVolumeRequestFromSnapshot", + "Snapshot", + "VolumeType", + "Volume", + "CreateSnapshotRequest", + "CreateVolumeRequest", + "DeleteSnapshotRequest", + "DeleteVolumeRequest", + "ExportSnapshotToObjectStorageRequest", + "GetSnapshotRequest", + "GetVolumeRequest", + "ImportSnapshotFromObjectStorageRequest", + "ListSnapshotsRequest", + "ListSnapshotsResponse", + "ListVolumeTypesRequest", + "ListVolumeTypesResponse", + "ListVolumesRequest", + "ListVolumesResponse", + "UpdateSnapshotRequest", + "UpdateVolumeRequest", + "BlockV1API", +] diff --git a/scaleway-async/scaleway_async/block/v1/api.py b/scaleway-async/scaleway_async/block/v1/api.py new file mode 100644 index 000000000..da4caa99d --- /dev/null +++ b/scaleway-async/scaleway_async/block/v1/api.py @@ -0,0 +1,837 @@ +# This file was automatically generated. DO NOT EDIT. +# If you have any remark or suggestion do not hesitate to open an issue. + +from typing import Awaitable, List, Optional, Union + +from scaleway_core.api import API +from scaleway_core.bridge import ( + Zone as ScwZone, +) +from scaleway_core.utils import ( + WaitForOptions, + random_name, + validate_path_param, + fetch_all_pages_async, + wait_for_resource_async, +) +from .types import ( + ListSnapshotsRequestOrderBy, + ListVolumesRequestOrderBy, + CreateSnapshotRequest, + CreateVolumeRequest, + CreateVolumeRequestFromEmpty, + CreateVolumeRequestFromSnapshot, + ExportSnapshotToObjectStorageRequest, + ImportSnapshotFromObjectStorageRequest, + ListSnapshotsResponse, + ListVolumeTypesResponse, + ListVolumesResponse, + Snapshot, + UpdateSnapshotRequest, + UpdateVolumeRequest, + Volume, + VolumeType, +) +from .content import ( + SNAPSHOT_TRANSIENT_STATUSES, + VOLUME_TRANSIENT_STATUSES, +) +from .marshalling import ( + unmarshal_Snapshot, + unmarshal_Volume, + unmarshal_ListSnapshotsResponse, + unmarshal_ListVolumeTypesResponse, + unmarshal_ListVolumesResponse, + marshal_CreateSnapshotRequest, + marshal_CreateVolumeRequest, + marshal_ExportSnapshotToObjectStorageRequest, + marshal_ImportSnapshotFromObjectStorageRequest, + marshal_UpdateSnapshotRequest, + marshal_UpdateVolumeRequest, +) + + +class BlockV1API(API): + """ + This API allows you to manage your Block Storage volumes. + """ + + async def list_volume_types( + self, + *, + zone: Optional[ScwZone] = None, + page: Optional[int] = None, + page_size: Optional[int] = None, + ) -> ListVolumeTypesResponse: + """ + List volume types. + List all available volume types in a specified zone. The volume types listed are ordered by name in ascending order. + :param zone: Zone to target. If none is passed will use default zone from the config. + :param page: Page number. + :param page_size: Page size, defines how many entries are returned in one page, must be lower or equal to 100. + :return: :class:`ListVolumeTypesResponse ` + + Usage: + :: + + result = await api.list_volume_types() + """ + + param_zone = validate_path_param("zone", zone or self.client.default_zone) + + res = self._request( + "GET", + f"/block/v1/zones/{param_zone}/volume-types", + params={ + "page": page, + "page_size": page_size or self.client.default_page_size, + }, + ) + + self._throw_on_error(res) + return unmarshal_ListVolumeTypesResponse(res.json()) + + async def list_volume_types_all( + self, + *, + zone: Optional[ScwZone] = None, + page: Optional[int] = None, + page_size: Optional[int] = None, + ) -> List[VolumeType]: + """ + List volume types. + List all available volume types in a specified zone. The volume types listed are ordered by name in ascending order. + :param zone: Zone to target. If none is passed will use default zone from the config. + :param page: Page number. + :param page_size: Page size, defines how many entries are returned in one page, must be lower or equal to 100. + :return: :class:`List[VolumeType] ` + + Usage: + :: + + result = await api.list_volume_types_all() + """ + + return await fetch_all_pages_async( + type=ListVolumeTypesResponse, + key="volume_types", + fetcher=self.list_volume_types, + args={ + "zone": zone, + "page": page, + "page_size": page_size, + }, + ) + + async def list_volumes( + self, + *, + zone: Optional[ScwZone] = None, + order_by: Optional[ListVolumesRequestOrderBy] = None, + project_id: Optional[str] = None, + organization_id: Optional[str] = None, + page: Optional[int] = None, + page_size: Optional[int] = None, + name: Optional[str] = None, + product_resource_id: Optional[str] = None, + tags: Optional[List[str]] = None, + ) -> ListVolumesResponse: + """ + List volumes. + List all existing volumes in a specified zone. By default, the volumes listed are ordered by creation date in ascending order. This can be modified via the `order_by` field. + :param zone: Zone to target. If none is passed will use default zone from the config. + :param order_by: Criteria to use when ordering the list. + :param project_id: Filter by Project ID. + :param organization_id: Filter by Organization ID. + :param page: Page number. + :param page_size: Page size, defines how many entries are returned in one page, must be lower or equal to 100. + :param name: Filter the return volumes by their names. + :param product_resource_id: Filter by a product resource ID linked to this volume (such as an Instance ID). + :param tags: Filter by tags. Only volumes with one or more matching tags will be returned. + :return: :class:`ListVolumesResponse ` + + Usage: + :: + + result = await api.list_volumes() + """ + + param_zone = validate_path_param("zone", zone or self.client.default_zone) + + res = self._request( + "GET", + f"/block/v1/zones/{param_zone}/volumes", + params={ + "name": name, + "order_by": order_by, + "organization_id": organization_id + or self.client.default_organization_id, + "page": page, + "page_size": page_size or self.client.default_page_size, + "product_resource_id": product_resource_id, + "project_id": project_id or self.client.default_project_id, + "tags": tags, + }, + ) + + self._throw_on_error(res) + return unmarshal_ListVolumesResponse(res.json()) + + async def list_volumes_all( + self, + *, + zone: Optional[ScwZone] = None, + order_by: Optional[ListVolumesRequestOrderBy] = None, + project_id: Optional[str] = None, + organization_id: Optional[str] = None, + page: Optional[int] = None, + page_size: Optional[int] = None, + name: Optional[str] = None, + product_resource_id: Optional[str] = None, + tags: Optional[List[str]] = None, + ) -> List[Volume]: + """ + List volumes. + List all existing volumes in a specified zone. By default, the volumes listed are ordered by creation date in ascending order. This can be modified via the `order_by` field. + :param zone: Zone to target. If none is passed will use default zone from the config. + :param order_by: Criteria to use when ordering the list. + :param project_id: Filter by Project ID. + :param organization_id: Filter by Organization ID. + :param page: Page number. + :param page_size: Page size, defines how many entries are returned in one page, must be lower or equal to 100. + :param name: Filter the return volumes by their names. + :param product_resource_id: Filter by a product resource ID linked to this volume (such as an Instance ID). + :param tags: Filter by tags. Only volumes with one or more matching tags will be returned. + :return: :class:`List[Volume] ` + + Usage: + :: + + result = await api.list_volumes_all() + """ + + return await fetch_all_pages_async( + type=ListVolumesResponse, + key="volumes", + fetcher=self.list_volumes, + args={ + "zone": zone, + "order_by": order_by, + "project_id": project_id, + "organization_id": organization_id, + "page": page, + "page_size": page_size, + "name": name, + "product_resource_id": product_resource_id, + "tags": tags, + }, + ) + + async def create_volume( + self, + *, + zone: Optional[ScwZone] = None, + name: Optional[str] = None, + perf_iops: Optional[int] = None, + project_id: Optional[str] = None, + from_empty: Optional[CreateVolumeRequestFromEmpty] = None, + from_snapshot: Optional[CreateVolumeRequestFromSnapshot] = None, + tags: Optional[List[str]] = None, + ) -> Volume: + """ + Create a volume. + To create a new volume from scratch, you must specify `from_empty` and the `size`. + To create a volume from an existing snapshot, specify `from_snapshot` and the `snapshot_id` in the request payload instead, size is optional and can be specified if you need to extend the original size. The volume will take on the same volume class and underlying IOPS limitations as the original snapshot. + :param zone: Zone to target. If none is passed will use default zone from the config. + :param name: Name of the volume. + :param perf_iops: The maximum IO/s expected, according to the different options available in stock (`5000 | 15000`). + One-Of ('requirements'): at most one of 'perf_iops' could be set. + :param project_id: UUID of the project the volume belongs to. + :param from_empty: Specify the size of the new volume if creating a new one from scratch. + One-Of ('from'): at most one of 'from_empty', 'from_snapshot' could be set. + :param from_snapshot: Specify the snapshot ID of the original snapshot. + One-Of ('from'): at most one of 'from_empty', 'from_snapshot' could be set. + :param tags: List of tags assigned to the volume. + :return: :class:`Volume ` + + Usage: + :: + + result = await api.create_volume() + """ + + param_zone = validate_path_param("zone", zone or self.client.default_zone) + + res = self._request( + "POST", + f"/block/v1/zones/{param_zone}/volumes", + body=marshal_CreateVolumeRequest( + CreateVolumeRequest( + zone=zone, + name=name or random_name(prefix="vol"), + project_id=project_id, + tags=tags, + from_empty=from_empty, + from_snapshot=from_snapshot, + perf_iops=perf_iops, + ), + self.client, + ), + ) + + self._throw_on_error(res) + return unmarshal_Volume(res.json()) + + async def get_volume( + self, + *, + volume_id: str, + zone: Optional[ScwZone] = None, + ) -> Volume: + """ + Get a volume. + Retrieve technical information about a specific volume. Details such as size, type, and status are returned in the response. + :param volume_id: UUID of the volume. + :param zone: Zone to target. If none is passed will use default zone from the config. + :return: :class:`Volume ` + + Usage: + :: + + result = await api.get_volume( + volume_id="example", + ) + """ + + param_zone = validate_path_param("zone", zone or self.client.default_zone) + param_volume_id = validate_path_param("volume_id", volume_id) + + res = self._request( + "GET", + f"/block/v1/zones/{param_zone}/volumes/{param_volume_id}", + ) + + self._throw_on_error(res) + return unmarshal_Volume(res.json()) + + async def wait_for_volume( + self, + *, + volume_id: str, + zone: Optional[ScwZone] = None, + options: Optional[WaitForOptions[Volume, Union[bool, Awaitable[bool]]]] = None, + ) -> Volume: + """ + Get a volume. + Retrieve technical information about a specific volume. Details such as size, type, and status are returned in the response. + :param volume_id: UUID of the volume. + :param zone: Zone to target. If none is passed will use default zone from the config. + :return: :class:`Volume ` + + Usage: + :: + + result = await api.get_volume( + volume_id="example", + ) + """ + + if not options: + options = WaitForOptions() + + if not options.stop: + options.stop = lambda res: res.status not in VOLUME_TRANSIENT_STATUSES + + return await wait_for_resource_async( + fetcher=self.get_volume, + options=options, + args={ + "volume_id": volume_id, + "zone": zone, + }, + ) + + async def delete_volume( + self, + *, + volume_id: str, + zone: Optional[ScwZone] = None, + ) -> None: + """ + Delete a detached volume. + You must specify the `volume_id` of the volume you want to delete. The volume must not be in the `in_use` status. + :param volume_id: UUID of the volume. + :param zone: Zone to target. If none is passed will use default zone from the config. + + Usage: + :: + + result = await api.delete_volume( + volume_id="example", + ) + """ + + param_zone = validate_path_param("zone", zone or self.client.default_zone) + param_volume_id = validate_path_param("volume_id", volume_id) + + res = self._request( + "DELETE", + f"/block/v1/zones/{param_zone}/volumes/{param_volume_id}", + ) + + self._throw_on_error(res) + + async def update_volume( + self, + *, + volume_id: str, + zone: Optional[ScwZone] = None, + name: Optional[str] = None, + size: Optional[int] = None, + tags: Optional[List[str]] = None, + perf_iops: Optional[int] = None, + ) -> Volume: + """ + Update a volume. + Update the technical details of a volume, such as its name, tags, or its new size and `volume_type` (within the same Block Storage class). + You can only resize a volume to a larger size. It is currently not possible to change your Block Storage Class. + :param volume_id: UUID of the volume. + :param zone: Zone to target. If none is passed will use default zone from the config. + :param name: When defined, is the new name of the volume. + :param size: Size in bytes of the volume, with a granularity of 1 GB (10^9 bytes). + Must be compliant with the minimum (1GB) and maximum (10TB) allowed size. + :param tags: List of tags assigned to the volume. + :param perf_iops: The selected value must be available for the volume's current storage class. + :return: :class:`Volume ` + + Usage: + :: + + result = await api.update_volume( + volume_id="example", + ) + """ + + param_zone = validate_path_param("zone", zone or self.client.default_zone) + param_volume_id = validate_path_param("volume_id", volume_id) + + res = self._request( + "PATCH", + f"/block/v1/zones/{param_zone}/volumes/{param_volume_id}", + body=marshal_UpdateVolumeRequest( + UpdateVolumeRequest( + volume_id=volume_id, + zone=zone, + name=name, + size=size, + tags=tags, + perf_iops=perf_iops, + ), + self.client, + ), + ) + + self._throw_on_error(res) + return unmarshal_Volume(res.json()) + + async def list_snapshots( + self, + *, + zone: Optional[ScwZone] = None, + order_by: Optional[ListSnapshotsRequestOrderBy] = None, + project_id: Optional[str] = None, + organization_id: Optional[str] = None, + page: Optional[int] = None, + page_size: Optional[int] = None, + volume_id: Optional[str] = None, + name: Optional[str] = None, + tags: Optional[List[str]] = None, + ) -> ListSnapshotsResponse: + """ + List all snapshots. + List all available snapshots in a specified zone. By default, the snapshots listed are ordered by creation date in ascending order. This can be modified via the `order_by` field. + :param zone: Zone to target. If none is passed will use default zone from the config. + :param order_by: Criteria to use when ordering the list. + :param project_id: Filter by Project ID. + :param organization_id: Filter by Organization ID. + :param page: Page number. + :param page_size: Page size, defines how many entries are returned in one page, must be lower or equal to 100. + :param volume_id: Filter snapshots by the ID of the original volume. + :param name: Filter snapshots by their names. + :param tags: Filter by tags. Only snapshots with one or more matching tags will be returned. + :return: :class:`ListSnapshotsResponse ` + + Usage: + :: + + result = await api.list_snapshots() + """ + + param_zone = validate_path_param("zone", zone or self.client.default_zone) + + res = self._request( + "GET", + f"/block/v1/zones/{param_zone}/snapshots", + params={ + "name": name, + "order_by": order_by, + "organization_id": organization_id + or self.client.default_organization_id, + "page": page, + "page_size": page_size or self.client.default_page_size, + "project_id": project_id or self.client.default_project_id, + "tags": tags, + "volume_id": volume_id, + }, + ) + + self._throw_on_error(res) + return unmarshal_ListSnapshotsResponse(res.json()) + + async def list_snapshots_all( + self, + *, + zone: Optional[ScwZone] = None, + order_by: Optional[ListSnapshotsRequestOrderBy] = None, + project_id: Optional[str] = None, + organization_id: Optional[str] = None, + page: Optional[int] = None, + page_size: Optional[int] = None, + volume_id: Optional[str] = None, + name: Optional[str] = None, + tags: Optional[List[str]] = None, + ) -> List[Snapshot]: + """ + List all snapshots. + List all available snapshots in a specified zone. By default, the snapshots listed are ordered by creation date in ascending order. This can be modified via the `order_by` field. + :param zone: Zone to target. If none is passed will use default zone from the config. + :param order_by: Criteria to use when ordering the list. + :param project_id: Filter by Project ID. + :param organization_id: Filter by Organization ID. + :param page: Page number. + :param page_size: Page size, defines how many entries are returned in one page, must be lower or equal to 100. + :param volume_id: Filter snapshots by the ID of the original volume. + :param name: Filter snapshots by their names. + :param tags: Filter by tags. Only snapshots with one or more matching tags will be returned. + :return: :class:`List[Snapshot] ` + + Usage: + :: + + result = await api.list_snapshots_all() + """ + + return await fetch_all_pages_async( + type=ListSnapshotsResponse, + key="snapshots", + fetcher=self.list_snapshots, + args={ + "zone": zone, + "order_by": order_by, + "project_id": project_id, + "organization_id": organization_id, + "page": page, + "page_size": page_size, + "volume_id": volume_id, + "name": name, + "tags": tags, + }, + ) + + async def get_snapshot( + self, + *, + snapshot_id: str, + zone: Optional[ScwZone] = None, + ) -> Snapshot: + """ + Get a snapshot. + Retrieve technical information about a specific snapshot. Details such as size, volume type, and status are returned in the response. + :param snapshot_id: UUID of the snapshot. + :param zone: Zone to target. If none is passed will use default zone from the config. + :return: :class:`Snapshot ` + + Usage: + :: + + result = await api.get_snapshot( + snapshot_id="example", + ) + """ + + param_zone = validate_path_param("zone", zone or self.client.default_zone) + param_snapshot_id = validate_path_param("snapshot_id", snapshot_id) + + res = self._request( + "GET", + f"/block/v1/zones/{param_zone}/snapshots/{param_snapshot_id}", + ) + + self._throw_on_error(res) + return unmarshal_Snapshot(res.json()) + + async def wait_for_snapshot( + self, + *, + snapshot_id: str, + zone: Optional[ScwZone] = None, + options: Optional[ + WaitForOptions[Snapshot, Union[bool, Awaitable[bool]]] + ] = None, + ) -> Snapshot: + """ + Get a snapshot. + Retrieve technical information about a specific snapshot. Details such as size, volume type, and status are returned in the response. + :param snapshot_id: UUID of the snapshot. + :param zone: Zone to target. If none is passed will use default zone from the config. + :return: :class:`Snapshot ` + + Usage: + :: + + result = await api.get_snapshot( + snapshot_id="example", + ) + """ + + if not options: + options = WaitForOptions() + + if not options.stop: + options.stop = lambda res: res.status not in SNAPSHOT_TRANSIENT_STATUSES + + return await wait_for_resource_async( + fetcher=self.get_snapshot, + options=options, + args={ + "snapshot_id": snapshot_id, + "zone": zone, + }, + ) + + async def create_snapshot( + self, + *, + volume_id: str, + zone: Optional[ScwZone] = None, + name: Optional[str] = None, + project_id: Optional[str] = None, + tags: Optional[List[str]] = None, + ) -> Snapshot: + """ + Create a snapshot of a volume. + To create a snapshot, the volume must be in the `in_use` or the `available` status. + If your volume is in a transient state, you need to wait until the end of the current operation. + :param volume_id: UUID of the volume to snapshot. + :param zone: Zone to target. If none is passed will use default zone from the config. + :param name: Name of the snapshot. + :param project_id: UUID of the project to which the volume and the snapshot belong. + :param tags: List of tags assigned to the snapshot. + :return: :class:`Snapshot ` + + Usage: + :: + + result = await api.create_snapshot( + volume_id="example", + ) + """ + + param_zone = validate_path_param("zone", zone or self.client.default_zone) + + res = self._request( + "POST", + f"/block/v1/zones/{param_zone}/snapshots", + body=marshal_CreateSnapshotRequest( + CreateSnapshotRequest( + volume_id=volume_id, + zone=zone, + name=name or random_name(prefix="snp"), + project_id=project_id, + tags=tags, + ), + self.client, + ), + ) + + self._throw_on_error(res) + return unmarshal_Snapshot(res.json()) + + async def import_snapshot_from_object_storage( + self, + *, + bucket: str, + key: str, + name: str, + zone: Optional[ScwZone] = None, + project_id: Optional[str] = None, + tags: Optional[List[str]] = None, + size: Optional[int] = None, + ) -> Snapshot: + """ + Import a snapshot from a Scaleway Object Storage bucket. + The bucket must contain a QCOW2 image. + The bucket can be imported into any Availability Zone as long as it is in the same region as the bucket. + :param bucket: Scaleway Object Storage bucket where the object is stored. + :param key: The object key inside the given bucket. + :param name: Name of the snapshot. + :param zone: Zone to target. If none is passed will use default zone from the config. + :param project_id: UUID of the Project to which the volume and the snapshot belong. + :param tags: List of tags assigned to the snapshot. + :param size: Size of the snapshot. + :return: :class:`Snapshot ` + + Usage: + :: + + result = await api.import_snapshot_from_object_storage( + bucket="example", + key="example", + name="example", + ) + """ + + param_zone = validate_path_param("zone", zone or self.client.default_zone) + + res = self._request( + "POST", + f"/block/v1/zones/{param_zone}/snapshots/import-from-object-storage", + body=marshal_ImportSnapshotFromObjectStorageRequest( + ImportSnapshotFromObjectStorageRequest( + bucket=bucket, + key=key, + name=name, + zone=zone, + project_id=project_id, + tags=tags, + size=size, + ), + self.client, + ), + ) + + self._throw_on_error(res) + return unmarshal_Snapshot(res.json()) + + async def export_snapshot_to_object_storage( + self, + *, + snapshot_id: str, + bucket: str, + key: str, + zone: Optional[ScwZone] = None, + ) -> Snapshot: + """ + Export a snapshot to a Scaleway Object Storage bucket. + The snapshot is exported in QCOW2 format. + The snapshot must not be in transient state. + :param snapshot_id: UUID of the snapshot. + :param bucket: Scaleway Object Storage bucket where the object is stored. + :param key: The object key inside the given bucket. + :param zone: Zone to target. If none is passed will use default zone from the config. + :return: :class:`Snapshot ` + + Usage: + :: + + result = await api.export_snapshot_to_object_storage( + snapshot_id="example", + bucket="example", + key="example", + ) + """ + + param_zone = validate_path_param("zone", zone or self.client.default_zone) + param_snapshot_id = validate_path_param("snapshot_id", snapshot_id) + + res = self._request( + "POST", + f"/block/v1/zones/{param_zone}/snapshots/{param_snapshot_id}/export-to-object-storage", + body=marshal_ExportSnapshotToObjectStorageRequest( + ExportSnapshotToObjectStorageRequest( + snapshot_id=snapshot_id, + bucket=bucket, + key=key, + zone=zone, + ), + self.client, + ), + ) + + self._throw_on_error(res) + return unmarshal_Snapshot(res.json()) + + async def delete_snapshot( + self, + *, + snapshot_id: str, + zone: Optional[ScwZone] = None, + ) -> None: + """ + Delete a snapshot. + You must specify the `snapshot_id` of the snapshot you want to delete. The snapshot must not be in use. + :param snapshot_id: UUID of the snapshot. + :param zone: Zone to target. If none is passed will use default zone from the config. + + Usage: + :: + + result = await api.delete_snapshot( + snapshot_id="example", + ) + """ + + param_zone = validate_path_param("zone", zone or self.client.default_zone) + param_snapshot_id = validate_path_param("snapshot_id", snapshot_id) + + res = self._request( + "DELETE", + f"/block/v1/zones/{param_zone}/snapshots/{param_snapshot_id}", + ) + + self._throw_on_error(res) + + async def update_snapshot( + self, + *, + snapshot_id: str, + zone: Optional[ScwZone] = None, + name: Optional[str] = None, + tags: Optional[List[str]] = None, + ) -> Snapshot: + """ + Update a snapshot. + Update the name or tags of the snapshot. + :param snapshot_id: UUID of the snapshot. + :param zone: Zone to target. If none is passed will use default zone from the config. + :param name: When defined, is the name of the snapshot. + :param tags: List of tags assigned to the snapshot. + :return: :class:`Snapshot ` + + Usage: + :: + + result = await api.update_snapshot( + snapshot_id="example", + ) + """ + + param_zone = validate_path_param("zone", zone or self.client.default_zone) + param_snapshot_id = validate_path_param("snapshot_id", snapshot_id) + + res = self._request( + "PATCH", + f"/block/v1/zones/{param_zone}/snapshots/{param_snapshot_id}", + body=marshal_UpdateSnapshotRequest( + UpdateSnapshotRequest( + snapshot_id=snapshot_id, + zone=zone, + name=name, + tags=tags, + ), + self.client, + ), + ) + + self._throw_on_error(res) + return unmarshal_Snapshot(res.json()) diff --git a/scaleway-async/scaleway_async/block/v1/content.py b/scaleway-async/scaleway_async/block/v1/content.py new file mode 100644 index 000000000..a6cf1ee67 --- /dev/null +++ b/scaleway-async/scaleway_async/block/v1/content.py @@ -0,0 +1,36 @@ +# This file was automatically generated. DO NOT EDIT. +# If you have any remark or suggestion do not hesitate to open an issue. +from typing import List + +from .types import ( + ReferenceStatus, + SnapshotStatus, + VolumeStatus, +) + +REFERENCE_TRANSIENT_STATUSES: List[ReferenceStatus] = [ + ReferenceStatus.ATTACHING, + ReferenceStatus.DETACHING, + ReferenceStatus.CREATING, +] +""" +Lists transient statutes of the enum :class:`ReferenceStatus `. +""" +SNAPSHOT_TRANSIENT_STATUSES: List[SnapshotStatus] = [ + SnapshotStatus.CREATING, + SnapshotStatus.DELETING, + SnapshotStatus.EXPORTING, +] +""" +Lists transient statutes of the enum :class:`SnapshotStatus `. +""" +VOLUME_TRANSIENT_STATUSES: List[VolumeStatus] = [ + VolumeStatus.CREATING, + VolumeStatus.DELETING, + VolumeStatus.RESIZING, + VolumeStatus.SNAPSHOTTING, + VolumeStatus.UPDATING, +] +""" +Lists transient statutes of the enum :class:`VolumeStatus `. +""" diff --git a/scaleway-async/scaleway_async/block/v1/marshalling.py b/scaleway-async/scaleway_async/block/v1/marshalling.py new file mode 100644 index 000000000..d1aef6680 --- /dev/null +++ b/scaleway-async/scaleway_async/block/v1/marshalling.py @@ -0,0 +1,521 @@ +# This file was automatically generated. DO NOT EDIT. +# If you have any remark or suggestion do not hesitate to open an issue. + +from typing import Any, Dict +from dateutil import parser + +from scaleway_core.profile import ProfileDefaults +from scaleway_core.bridge import ( + unmarshal_Money, +) +from scaleway_core.utils import ( + OneOfPossibility, + resolve_one_of, +) +from .types import ( + Reference, + SnapshotParentVolume, + Snapshot, + VolumeSpecifications, + Volume, + ListSnapshotsResponse, + VolumeType, + ListVolumeTypesResponse, + ListVolumesResponse, + CreateSnapshotRequest, + CreateVolumeRequestFromEmpty, + CreateVolumeRequestFromSnapshot, + CreateVolumeRequest, + ExportSnapshotToObjectStorageRequest, + ImportSnapshotFromObjectStorageRequest, + UpdateSnapshotRequest, + UpdateVolumeRequest, +) + + +def unmarshal_Reference(data: Any) -> Reference: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'Reference' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("id", None) + if field is not None: + args["id"] = field + + field = data.get("product_resource_type", None) + if field is not None: + args["product_resource_type"] = field + + field = data.get("product_resource_id", None) + if field is not None: + args["product_resource_id"] = field + + field = data.get("type", None) + if field is not None: + args["type_"] = field + + field = data.get("status", None) + if field is not None: + args["status"] = field + + field = data.get("created_at", None) + if field is not None: + args["created_at"] = parser.isoparse(field) if isinstance(field, str) else field + else: + args["created_at"] = None + + return Reference(**args) + + +def unmarshal_SnapshotParentVolume(data: Any) -> SnapshotParentVolume: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'SnapshotParentVolume' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("id", None) + if field is not None: + args["id"] = field + + field = data.get("name", None) + if field is not None: + args["name"] = field + + field = data.get("type", None) + if field is not None: + args["type_"] = field + + field = data.get("status", None) + if field is not None: + args["status"] = field + + return SnapshotParentVolume(**args) + + +def unmarshal_Snapshot(data: Any) -> Snapshot: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'Snapshot' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("id", None) + if field is not None: + args["id"] = field + + field = data.get("name", None) + if field is not None: + args["name"] = field + + field = data.get("size", None) + if field is not None: + args["size"] = field + + field = data.get("project_id", None) + if field is not None: + args["project_id"] = field + + field = data.get("references", None) + if field is not None: + args["references"] = ( + [unmarshal_Reference(v) for v in field] if field is not None else None + ) + + field = data.get("status", None) + if field is not None: + args["status"] = field + + field = data.get("tags", None) + if field is not None: + args["tags"] = field + + field = data.get("zone", None) + if field is not None: + args["zone"] = field + + field = data.get("class", None) + if field is not None: + args["class_"] = field + + field = data.get("parent_volume", None) + if field is not None: + args["parent_volume"] = unmarshal_SnapshotParentVolume(field) + else: + args["parent_volume"] = None + + field = data.get("created_at", None) + if field is not None: + args["created_at"] = parser.isoparse(field) if isinstance(field, str) else field + else: + args["created_at"] = None + + field = data.get("updated_at", None) + if field is not None: + args["updated_at"] = parser.isoparse(field) if isinstance(field, str) else field + else: + args["updated_at"] = None + + return Snapshot(**args) + + +def unmarshal_VolumeSpecifications(data: Any) -> VolumeSpecifications: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'VolumeSpecifications' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("class", None) + if field is not None: + args["class_"] = field + + field = data.get("perf_iops", None) + if field is not None: + args["perf_iops"] = field + else: + args["perf_iops"] = None + + return VolumeSpecifications(**args) + + +def unmarshal_Volume(data: Any) -> Volume: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'Volume' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("id", None) + if field is not None: + args["id"] = field + + field = data.get("name", None) + if field is not None: + args["name"] = field + + field = data.get("type", None) + if field is not None: + args["type_"] = field + + field = data.get("size", None) + if field is not None: + args["size"] = field + + field = data.get("project_id", None) + if field is not None: + args["project_id"] = field + + field = data.get("references", None) + if field is not None: + args["references"] = ( + [unmarshal_Reference(v) for v in field] if field is not None else None + ) + + field = data.get("created_at", None) + if field is not None: + args["created_at"] = parser.isoparse(field) if isinstance(field, str) else field + else: + args["created_at"] = None + + field = data.get("updated_at", None) + if field is not None: + args["updated_at"] = parser.isoparse(field) if isinstance(field, str) else field + else: + args["updated_at"] = None + + field = data.get("parent_snapshot_id", None) + if field is not None: + args["parent_snapshot_id"] = field + else: + args["parent_snapshot_id"] = None + + field = data.get("status", None) + if field is not None: + args["status"] = field + + field = data.get("tags", None) + if field is not None: + args["tags"] = field + + field = data.get("zone", None) + if field is not None: + args["zone"] = field + + field = data.get("specs", None) + if field is not None: + args["specs"] = unmarshal_VolumeSpecifications(field) + else: + args["specs"] = None + + field = data.get("last_detached_at", None) + if field is not None: + args["last_detached_at"] = ( + parser.isoparse(field) if isinstance(field, str) else field + ) + else: + args["last_detached_at"] = None + + return Volume(**args) + + +def unmarshal_ListSnapshotsResponse(data: Any) -> ListSnapshotsResponse: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'ListSnapshotsResponse' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("snapshots", None) + if field is not None: + args["snapshots"] = ( + [unmarshal_Snapshot(v) for v in field] if field is not None else None + ) + + field = data.get("total_count", None) + if field is not None: + args["total_count"] = field + + return ListSnapshotsResponse(**args) + + +def unmarshal_VolumeType(data: Any) -> VolumeType: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'VolumeType' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("type", None) + if field is not None: + args["type_"] = field + + field = data.get("pricing", None) + if field is not None: + args["pricing"] = unmarshal_Money(field) + else: + args["pricing"] = None + + field = data.get("snapshot_pricing", None) + if field is not None: + args["snapshot_pricing"] = unmarshal_Money(field) + else: + args["snapshot_pricing"] = None + + field = data.get("specs", None) + if field is not None: + args["specs"] = unmarshal_VolumeSpecifications(field) + else: + args["specs"] = None + + return VolumeType(**args) + + +def unmarshal_ListVolumeTypesResponse(data: Any) -> ListVolumeTypesResponse: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'ListVolumeTypesResponse' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("volume_types", None) + if field is not None: + args["volume_types"] = ( + [unmarshal_VolumeType(v) for v in field] if field is not None else None + ) + + field = data.get("total_count", None) + if field is not None: + args["total_count"] = field + + return ListVolumeTypesResponse(**args) + + +def unmarshal_ListVolumesResponse(data: Any) -> ListVolumesResponse: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'ListVolumesResponse' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("volumes", None) + if field is not None: + args["volumes"] = ( + [unmarshal_Volume(v) for v in field] if field is not None else None + ) + + field = data.get("total_count", None) + if field is not None: + args["total_count"] = field + + return ListVolumesResponse(**args) + + +def marshal_CreateSnapshotRequest( + request: CreateSnapshotRequest, + defaults: ProfileDefaults, +) -> Dict[str, Any]: + output: Dict[str, Any] = {} + + if request.volume_id is not None: + output["volume_id"] = request.volume_id + + if request.name is not None: + output["name"] = request.name + + if request.project_id is not None: + output["project_id"] = request.project_id or defaults.default_project_id + + if request.tags is not None: + output["tags"] = request.tags + + return output + + +def marshal_CreateVolumeRequestFromEmpty( + request: CreateVolumeRequestFromEmpty, + defaults: ProfileDefaults, +) -> Dict[str, Any]: + output: Dict[str, Any] = {} + + if request.size is not None: + output["size"] = request.size + + return output + + +def marshal_CreateVolumeRequestFromSnapshot( + request: CreateVolumeRequestFromSnapshot, + defaults: ProfileDefaults, +) -> Dict[str, Any]: + output: Dict[str, Any] = {} + + if request.snapshot_id is not None: + output["snapshot_id"] = request.snapshot_id + + if request.size is not None: + output["size"] = request.size + + return output + + +def marshal_CreateVolumeRequest( + request: CreateVolumeRequest, + defaults: ProfileDefaults, +) -> Dict[str, Any]: + output: Dict[str, Any] = {} + output.update( + resolve_one_of( + [ + OneOfPossibility("from_empty", request.from_empty), + OneOfPossibility("from_snapshot", request.from_snapshot), + ] + ), + ) + output.update( + resolve_one_of( + [ + OneOfPossibility("perf_iops", request.perf_iops), + ] + ), + ) + + if request.name is not None: + output["name"] = request.name + + if request.project_id is not None: + output["project_id"] = request.project_id or defaults.default_project_id + + if request.tags is not None: + output["tags"] = request.tags + + return output + + +def marshal_ExportSnapshotToObjectStorageRequest( + request: ExportSnapshotToObjectStorageRequest, + defaults: ProfileDefaults, +) -> Dict[str, Any]: + output: Dict[str, Any] = {} + + if request.bucket is not None: + output["bucket"] = request.bucket + + if request.key is not None: + output["key"] = request.key + + return output + + +def marshal_ImportSnapshotFromObjectStorageRequest( + request: ImportSnapshotFromObjectStorageRequest, + defaults: ProfileDefaults, +) -> Dict[str, Any]: + output: Dict[str, Any] = {} + + if request.bucket is not None: + output["bucket"] = request.bucket + + if request.key is not None: + output["key"] = request.key + + if request.name is not None: + output["name"] = request.name + + if request.project_id is not None: + output["project_id"] = request.project_id or defaults.default_project_id + + if request.tags is not None: + output["tags"] = request.tags + + if request.size is not None: + output["size"] = request.size + + return output + + +def marshal_UpdateSnapshotRequest( + request: UpdateSnapshotRequest, + defaults: ProfileDefaults, +) -> Dict[str, Any]: + output: Dict[str, Any] = {} + + if request.name is not None: + output["name"] = request.name + + if request.tags is not None: + output["tags"] = request.tags + + return output + + +def marshal_UpdateVolumeRequest( + request: UpdateVolumeRequest, + defaults: ProfileDefaults, +) -> Dict[str, Any]: + output: Dict[str, Any] = {} + + if request.name is not None: + output["name"] = request.name + + if request.size is not None: + output["size"] = request.size + + if request.tags is not None: + output["tags"] = request.tags + + if request.perf_iops is not None: + output["perf_iops"] = request.perf_iops + + return output diff --git a/scaleway-async/scaleway_async/block/v1/types.py b/scaleway-async/scaleway_async/block/v1/types.py new file mode 100644 index 000000000..d666ce94c --- /dev/null +++ b/scaleway-async/scaleway_async/block/v1/types.py @@ -0,0 +1,731 @@ +# This file was automatically generated. DO NOT EDIT. +# If you have any remark or suggestion do not hesitate to open an issue. +from __future__ import annotations + +from dataclasses import dataclass +from datetime import datetime +from enum import Enum +from typing import List, Optional + +from scaleway_core.bridge import ( + Money, + Zone as ScwZone, +) +from scaleway_core.utils import ( + StrEnumMeta, +) + + +class ListSnapshotsRequestOrderBy(str, Enum, metaclass=StrEnumMeta): + CREATED_AT_ASC = "created_at_asc" + CREATED_AT_DESC = "created_at_desc" + NAME_ASC = "name_asc" + NAME_DESC = "name_desc" + + def __str__(self) -> str: + return str(self.value) + + +class ListVolumesRequestOrderBy(str, Enum, metaclass=StrEnumMeta): + CREATED_AT_ASC = "created_at_asc" + CREATED_AT_DESC = "created_at_desc" + NAME_ASC = "name_asc" + NAME_DESC = "name_desc" + + def __str__(self) -> str: + return str(self.value) + + +class ReferenceStatus(str, Enum, metaclass=StrEnumMeta): + UNKNOWN_STATUS = "unknown_status" + ATTACHING = "attaching" + ATTACHED = "attached" + DETACHING = "detaching" + DETACHED = "detached" + CREATING = "creating" + ERROR = "error" + + def __str__(self) -> str: + return str(self.value) + + +class ReferenceType(str, Enum, metaclass=StrEnumMeta): + UNKNOWN_TYPE = "unknown_type" + LINK = "link" + EXCLUSIVE = "exclusive" + READ_ONLY = "read_only" + + def __str__(self) -> str: + return str(self.value) + + +class SnapshotStatus(str, Enum, metaclass=StrEnumMeta): + UNKNOWN_STATUS = "unknown_status" + CREATING = "creating" + AVAILABLE = "available" + ERROR = "error" + DELETING = "deleting" + DELETED = "deleted" + IN_USE = "in_use" + LOCKED = "locked" + EXPORTING = "exporting" + + def __str__(self) -> str: + return str(self.value) + + +class StorageClass(str, Enum, metaclass=StrEnumMeta): + UNKNOWN_STORAGE_CLASS = "unknown_storage_class" + UNSPECIFIED = "unspecified" + BSSD = "bssd" + SBS = "sbs" + + def __str__(self) -> str: + return str(self.value) + + +class VolumeStatus(str, Enum, metaclass=StrEnumMeta): + UNKNOWN_STATUS = "unknown_status" + CREATING = "creating" + AVAILABLE = "available" + IN_USE = "in_use" + DELETING = "deleting" + DELETED = "deleted" + RESIZING = "resizing" + ERROR = "error" + SNAPSHOTTING = "snapshotting" + LOCKED = "locked" + UPDATING = "updating" + + def __str__(self) -> str: + return str(self.value) + + +@dataclass +class Reference: + id: str + """ + UUID of the reference. + """ + + product_resource_type: str + """ + Type of resource to which the reference is associated. + """ + + product_resource_id: str + """ + UUID of the product resource it refers to (according to the product_resource_type). + """ + + type_: ReferenceType + """ + Type of reference (link, exclusive, read_only). + """ + + status: ReferenceStatus + """ + Status of the reference. Statuses include `attaching`, `attached`, and `detaching`. + """ + + created_at: Optional[datetime] + """ + Creation date of the reference. + """ + + +@dataclass +class SnapshotParentVolume: + id: str + """ + Parent volume UUID (volume from which the snapshot originates). + """ + + name: str + """ + Name of the parent volume. + """ + + type_: str + """ + Volume type of the parent volume. + """ + + status: VolumeStatus + """ + Current status the parent volume. + """ + + +@dataclass +class VolumeSpecifications: + class_: StorageClass + """ + The storage class of the volume. + """ + + perf_iops: Optional[int] + """ + The maximum IO/s expected, according to the different options available in stock (`5000 | 15000`). + """ + + +@dataclass +class CreateVolumeRequestFromEmpty: + size: int + """ + Must be compliant with the minimum (1 GB) and maximum (10 TB) allowed size. + """ + + +@dataclass +class CreateVolumeRequestFromSnapshot: + snapshot_id: str + """ + Source snapshot from which volume will be created. + """ + + size: Optional[int] + """ + Must be compliant with the minimum (1 GB) and maximum (10 TB) allowed size. +Size is optional and is used only if a resize of the volume is requested, otherwise original snapshot size will be used. + """ + + +@dataclass +class Snapshot: + id: str + """ + UUID of the snapshot. + """ + + name: str + """ + Name of the snapshot. + """ + + size: int + """ + Size in bytes of the snapshot. + """ + + project_id: str + """ + UUID of the project the snapshot belongs to. + """ + + references: List[Reference] + """ + List of the references to the snapshot. + """ + + status: SnapshotStatus + """ + Current status of the snapshot (available, in_use, ...). + """ + + tags: List[str] + """ + List of tags assigned to the volume. + """ + + zone: ScwZone + """ + Snapshot zone. + """ + + class_: StorageClass + """ + Storage class of the snapshot. + """ + + parent_volume: Optional[SnapshotParentVolume] + """ + If the parent volume was deleted, value is null. + """ + + created_at: Optional[datetime] + """ + Creation date of the snapshot. + """ + + updated_at: Optional[datetime] + """ + Last modification date of the properties of a snapshot. + """ + + +@dataclass +class VolumeType: + type_: str + """ + Volume type. + """ + + pricing: Optional[Money] + """ + Price of the volume billed in GB/hour. + """ + + snapshot_pricing: Optional[Money] + """ + Price of the snapshot billed in GB/hour. + """ + + specs: Optional[VolumeSpecifications] + """ + Volume specifications of the volume type. + """ + + +@dataclass +class Volume: + id: str + """ + UUID of the volume. + """ + + name: str + """ + Name of the volume. + """ + + type_: str + """ + Volume type. + """ + + size: int + """ + Volume size in bytes. + """ + + project_id: str + """ + UUID of the project to which the volume belongs. + """ + + references: List[Reference] + """ + List of the references to the volume. + """ + + created_at: Optional[datetime] + """ + Creation date of the volume. + """ + + updated_at: Optional[datetime] + """ + Last update of the properties of a volume. + """ + + parent_snapshot_id: Optional[str] + """ + When a volume is created from a snapshot, is the UUID of the snapshot from which the volume has been created. + """ + + status: VolumeStatus + """ + Current status of the volume (available, in_use, ...). + """ + + tags: List[str] + """ + List of tags assigned to the volume. + """ + + zone: ScwZone + """ + Volume zone. + """ + + specs: Optional[VolumeSpecifications] + """ + Specifications of the volume. + """ + + last_detached_at: Optional[datetime] + """ + Last time the volume was detached. + """ + + +@dataclass +class CreateSnapshotRequest: + volume_id: str + """ + UUID of the volume to snapshot. + """ + + zone: Optional[ScwZone] + """ + Zone to target. If none is passed will use default zone from the config. + """ + + name: Optional[str] + """ + Name of the snapshot. + """ + + project_id: Optional[str] + """ + UUID of the project to which the volume and the snapshot belong. + """ + + tags: Optional[List[str]] + """ + List of tags assigned to the snapshot. + """ + + +@dataclass +class CreateVolumeRequest: + zone: Optional[ScwZone] + """ + Zone to target. If none is passed will use default zone from the config. + """ + + name: Optional[str] + """ + Name of the volume. + """ + + project_id: Optional[str] + """ + UUID of the project the volume belongs to. + """ + + tags: Optional[List[str]] + """ + List of tags assigned to the volume. + """ + + from_empty: Optional[CreateVolumeRequestFromEmpty] + + from_snapshot: Optional[CreateVolumeRequestFromSnapshot] + + perf_iops: Optional[int] + + +@dataclass +class DeleteSnapshotRequest: + snapshot_id: str + """ + UUID of the snapshot. + """ + + zone: Optional[ScwZone] + """ + Zone to target. If none is passed will use default zone from the config. + """ + + +@dataclass +class DeleteVolumeRequest: + volume_id: str + """ + UUID of the volume. + """ + + zone: Optional[ScwZone] + """ + Zone to target. If none is passed will use default zone from the config. + """ + + +@dataclass +class ExportSnapshotToObjectStorageRequest: + snapshot_id: str + """ + UUID of the snapshot. + """ + + bucket: str + """ + Scaleway Object Storage bucket where the object is stored. + """ + + key: str + """ + The object key inside the given bucket. + """ + + zone: Optional[ScwZone] + """ + Zone to target. If none is passed will use default zone from the config. + """ + + +@dataclass +class GetSnapshotRequest: + snapshot_id: str + """ + UUID of the snapshot. + """ + + zone: Optional[ScwZone] + """ + Zone to target. If none is passed will use default zone from the config. + """ + + +@dataclass +class GetVolumeRequest: + volume_id: str + """ + UUID of the volume. + """ + + zone: Optional[ScwZone] + """ + Zone to target. If none is passed will use default zone from the config. + """ + + +@dataclass +class ImportSnapshotFromObjectStorageRequest: + bucket: str + """ + Scaleway Object Storage bucket where the object is stored. + """ + + key: str + """ + The object key inside the given bucket. + """ + + name: str + """ + Name of the snapshot. + """ + + zone: Optional[ScwZone] + """ + Zone to target. If none is passed will use default zone from the config. + """ + + project_id: Optional[str] + """ + UUID of the Project to which the volume and the snapshot belong. + """ + + tags: Optional[List[str]] + """ + List of tags assigned to the snapshot. + """ + + size: Optional[int] + """ + Size of the snapshot. + """ + + +@dataclass +class ListSnapshotsRequest: + zone: Optional[ScwZone] + """ + Zone to target. If none is passed will use default zone from the config. + """ + + order_by: Optional[ListSnapshotsRequestOrderBy] + """ + Criteria to use when ordering the list. + """ + + project_id: Optional[str] + """ + Filter by Project ID. + """ + + organization_id: Optional[str] + """ + Filter by Organization ID. + """ + + page: Optional[int] + """ + Page number. + """ + + page_size: Optional[int] + """ + Page size, defines how many entries are returned in one page, must be lower or equal to 100. + """ + + volume_id: Optional[str] + """ + Filter snapshots by the ID of the original volume. + """ + + name: Optional[str] + """ + Filter snapshots by their names. + """ + + tags: Optional[List[str]] + """ + Filter by tags. Only snapshots with one or more matching tags will be returned. + """ + + +@dataclass +class ListSnapshotsResponse: + snapshots: List[Snapshot] + """ + Paginated returned list of snapshots. + """ + + total_count: int + """ + Total number of snpashots in the project. + """ + + +@dataclass +class ListVolumeTypesRequest: + zone: Optional[ScwZone] + """ + Zone to target. If none is passed will use default zone from the config. + """ + + page: Optional[int] + """ + Page number. + """ + + page_size: Optional[int] + """ + Page size, defines how many entries are returned in one page, must be lower or equal to 100. + """ + + +@dataclass +class ListVolumeTypesResponse: + volume_types: List[VolumeType] + """ + Returns paginated list of volume-types. + """ + + total_count: int + """ + Total number of volume-types currently available in stock. + """ + + +@dataclass +class ListVolumesRequest: + zone: Optional[ScwZone] + """ + Zone to target. If none is passed will use default zone from the config. + """ + + order_by: Optional[ListVolumesRequestOrderBy] + """ + Criteria to use when ordering the list. + """ + + project_id: Optional[str] + """ + Filter by Project ID. + """ + + organization_id: Optional[str] + """ + Filter by Organization ID. + """ + + page: Optional[int] + """ + Page number. + """ + + page_size: Optional[int] + """ + Page size, defines how many entries are returned in one page, must be lower or equal to 100. + """ + + name: Optional[str] + """ + Filter the return volumes by their names. + """ + + product_resource_id: Optional[str] + """ + Filter by a product resource ID linked to this volume (such as an Instance ID). + """ + + tags: Optional[List[str]] + """ + Filter by tags. Only volumes with one or more matching tags will be returned. + """ + + +@dataclass +class ListVolumesResponse: + volumes: List[Volume] + """ + Paginated returned list of volumes. + """ + + total_count: int + """ + Total number of volumes in the project. + """ + + +@dataclass +class UpdateSnapshotRequest: + snapshot_id: str + """ + UUID of the snapshot. + """ + + zone: Optional[ScwZone] + """ + Zone to target. If none is passed will use default zone from the config. + """ + + name: Optional[str] + """ + When defined, is the name of the snapshot. + """ + + tags: Optional[List[str]] + """ + List of tags assigned to the snapshot. + """ + + +@dataclass +class UpdateVolumeRequest: + volume_id: str + """ + UUID of the volume. + """ + + zone: Optional[ScwZone] + """ + Zone to target. If none is passed will use default zone from the config. + """ + + name: Optional[str] + """ + When defined, is the new name of the volume. + """ + + size: Optional[int] + """ + Size in bytes of the volume, with a granularity of 1 GB (10^9 bytes). +Must be compliant with the minimum (1GB) and maximum (10TB) allowed size. + """ + + tags: Optional[List[str]] + """ + List of tags assigned to the volume. + """ + + perf_iops: Optional[int] + """ + The selected value must be available for the volume's current storage class. + """ diff --git a/scaleway/scaleway/block/v1/__init__.py b/scaleway/scaleway/block/v1/__init__.py new file mode 100644 index 000000000..1e48ec134 --- /dev/null +++ b/scaleway/scaleway/block/v1/__init__.py @@ -0,0 +1,75 @@ +# This file was automatically generated. DO NOT EDIT. +# If you have any remark or suggestion do not hesitate to open an issue. +from .types import ListSnapshotsRequestOrderBy +from .types import ListVolumesRequestOrderBy +from .types import ReferenceStatus +from .content import REFERENCE_TRANSIENT_STATUSES +from .types import ReferenceType +from .types import SnapshotStatus +from .content import SNAPSHOT_TRANSIENT_STATUSES +from .types import StorageClass +from .types import VolumeStatus +from .content import VOLUME_TRANSIENT_STATUSES +from .types import Reference +from .types import SnapshotParentVolume +from .types import VolumeSpecifications +from .types import CreateVolumeRequestFromEmpty +from .types import CreateVolumeRequestFromSnapshot +from .types import Snapshot +from .types import VolumeType +from .types import Volume +from .types import CreateSnapshotRequest +from .types import CreateVolumeRequest +from .types import DeleteSnapshotRequest +from .types import DeleteVolumeRequest +from .types import ExportSnapshotToObjectStorageRequest +from .types import GetSnapshotRequest +from .types import GetVolumeRequest +from .types import ImportSnapshotFromObjectStorageRequest +from .types import ListSnapshotsRequest +from .types import ListSnapshotsResponse +from .types import ListVolumeTypesRequest +from .types import ListVolumeTypesResponse +from .types import ListVolumesRequest +from .types import ListVolumesResponse +from .types import UpdateSnapshotRequest +from .types import UpdateVolumeRequest +from .api import BlockV1API + +__all__ = [ + "ListSnapshotsRequestOrderBy", + "ListVolumesRequestOrderBy", + "ReferenceStatus", + "REFERENCE_TRANSIENT_STATUSES", + "ReferenceType", + "SnapshotStatus", + "SNAPSHOT_TRANSIENT_STATUSES", + "StorageClass", + "VolumeStatus", + "VOLUME_TRANSIENT_STATUSES", + "Reference", + "SnapshotParentVolume", + "VolumeSpecifications", + "CreateVolumeRequestFromEmpty", + "CreateVolumeRequestFromSnapshot", + "Snapshot", + "VolumeType", + "Volume", + "CreateSnapshotRequest", + "CreateVolumeRequest", + "DeleteSnapshotRequest", + "DeleteVolumeRequest", + "ExportSnapshotToObjectStorageRequest", + "GetSnapshotRequest", + "GetVolumeRequest", + "ImportSnapshotFromObjectStorageRequest", + "ListSnapshotsRequest", + "ListSnapshotsResponse", + "ListVolumeTypesRequest", + "ListVolumeTypesResponse", + "ListVolumesRequest", + "ListVolumesResponse", + "UpdateSnapshotRequest", + "UpdateVolumeRequest", + "BlockV1API", +] diff --git a/scaleway/scaleway/block/v1/api.py b/scaleway/scaleway/block/v1/api.py new file mode 100644 index 000000000..508e9d164 --- /dev/null +++ b/scaleway/scaleway/block/v1/api.py @@ -0,0 +1,835 @@ +# This file was automatically generated. DO NOT EDIT. +# If you have any remark or suggestion do not hesitate to open an issue. + +from typing import List, Optional + +from scaleway_core.api import API +from scaleway_core.bridge import ( + Zone as ScwZone, +) +from scaleway_core.utils import ( + WaitForOptions, + random_name, + validate_path_param, + fetch_all_pages, + wait_for_resource, +) +from .types import ( + ListSnapshotsRequestOrderBy, + ListVolumesRequestOrderBy, + CreateSnapshotRequest, + CreateVolumeRequest, + CreateVolumeRequestFromEmpty, + CreateVolumeRequestFromSnapshot, + ExportSnapshotToObjectStorageRequest, + ImportSnapshotFromObjectStorageRequest, + ListSnapshotsResponse, + ListVolumeTypesResponse, + ListVolumesResponse, + Snapshot, + UpdateSnapshotRequest, + UpdateVolumeRequest, + Volume, + VolumeType, +) +from .content import ( + SNAPSHOT_TRANSIENT_STATUSES, + VOLUME_TRANSIENT_STATUSES, +) +from .marshalling import ( + unmarshal_Snapshot, + unmarshal_Volume, + unmarshal_ListSnapshotsResponse, + unmarshal_ListVolumeTypesResponse, + unmarshal_ListVolumesResponse, + marshal_CreateSnapshotRequest, + marshal_CreateVolumeRequest, + marshal_ExportSnapshotToObjectStorageRequest, + marshal_ImportSnapshotFromObjectStorageRequest, + marshal_UpdateSnapshotRequest, + marshal_UpdateVolumeRequest, +) + + +class BlockV1API(API): + """ + This API allows you to manage your Block Storage volumes. + """ + + def list_volume_types( + self, + *, + zone: Optional[ScwZone] = None, + page: Optional[int] = None, + page_size: Optional[int] = None, + ) -> ListVolumeTypesResponse: + """ + List volume types. + List all available volume types in a specified zone. The volume types listed are ordered by name in ascending order. + :param zone: Zone to target. If none is passed will use default zone from the config. + :param page: Page number. + :param page_size: Page size, defines how many entries are returned in one page, must be lower or equal to 100. + :return: :class:`ListVolumeTypesResponse ` + + Usage: + :: + + result = api.list_volume_types() + """ + + param_zone = validate_path_param("zone", zone or self.client.default_zone) + + res = self._request( + "GET", + f"/block/v1/zones/{param_zone}/volume-types", + params={ + "page": page, + "page_size": page_size or self.client.default_page_size, + }, + ) + + self._throw_on_error(res) + return unmarshal_ListVolumeTypesResponse(res.json()) + + def list_volume_types_all( + self, + *, + zone: Optional[ScwZone] = None, + page: Optional[int] = None, + page_size: Optional[int] = None, + ) -> List[VolumeType]: + """ + List volume types. + List all available volume types in a specified zone. The volume types listed are ordered by name in ascending order. + :param zone: Zone to target. If none is passed will use default zone from the config. + :param page: Page number. + :param page_size: Page size, defines how many entries are returned in one page, must be lower or equal to 100. + :return: :class:`List[VolumeType] ` + + Usage: + :: + + result = api.list_volume_types_all() + """ + + return fetch_all_pages( + type=ListVolumeTypesResponse, + key="volume_types", + fetcher=self.list_volume_types, + args={ + "zone": zone, + "page": page, + "page_size": page_size, + }, + ) + + def list_volumes( + self, + *, + zone: Optional[ScwZone] = None, + order_by: Optional[ListVolumesRequestOrderBy] = None, + project_id: Optional[str] = None, + organization_id: Optional[str] = None, + page: Optional[int] = None, + page_size: Optional[int] = None, + name: Optional[str] = None, + product_resource_id: Optional[str] = None, + tags: Optional[List[str]] = None, + ) -> ListVolumesResponse: + """ + List volumes. + List all existing volumes in a specified zone. By default, the volumes listed are ordered by creation date in ascending order. This can be modified via the `order_by` field. + :param zone: Zone to target. If none is passed will use default zone from the config. + :param order_by: Criteria to use when ordering the list. + :param project_id: Filter by Project ID. + :param organization_id: Filter by Organization ID. + :param page: Page number. + :param page_size: Page size, defines how many entries are returned in one page, must be lower or equal to 100. + :param name: Filter the return volumes by their names. + :param product_resource_id: Filter by a product resource ID linked to this volume (such as an Instance ID). + :param tags: Filter by tags. Only volumes with one or more matching tags will be returned. + :return: :class:`ListVolumesResponse ` + + Usage: + :: + + result = api.list_volumes() + """ + + param_zone = validate_path_param("zone", zone or self.client.default_zone) + + res = self._request( + "GET", + f"/block/v1/zones/{param_zone}/volumes", + params={ + "name": name, + "order_by": order_by, + "organization_id": organization_id + or self.client.default_organization_id, + "page": page, + "page_size": page_size or self.client.default_page_size, + "product_resource_id": product_resource_id, + "project_id": project_id or self.client.default_project_id, + "tags": tags, + }, + ) + + self._throw_on_error(res) + return unmarshal_ListVolumesResponse(res.json()) + + def list_volumes_all( + self, + *, + zone: Optional[ScwZone] = None, + order_by: Optional[ListVolumesRequestOrderBy] = None, + project_id: Optional[str] = None, + organization_id: Optional[str] = None, + page: Optional[int] = None, + page_size: Optional[int] = None, + name: Optional[str] = None, + product_resource_id: Optional[str] = None, + tags: Optional[List[str]] = None, + ) -> List[Volume]: + """ + List volumes. + List all existing volumes in a specified zone. By default, the volumes listed are ordered by creation date in ascending order. This can be modified via the `order_by` field. + :param zone: Zone to target. If none is passed will use default zone from the config. + :param order_by: Criteria to use when ordering the list. + :param project_id: Filter by Project ID. + :param organization_id: Filter by Organization ID. + :param page: Page number. + :param page_size: Page size, defines how many entries are returned in one page, must be lower or equal to 100. + :param name: Filter the return volumes by their names. + :param product_resource_id: Filter by a product resource ID linked to this volume (such as an Instance ID). + :param tags: Filter by tags. Only volumes with one or more matching tags will be returned. + :return: :class:`List[Volume] ` + + Usage: + :: + + result = api.list_volumes_all() + """ + + return fetch_all_pages( + type=ListVolumesResponse, + key="volumes", + fetcher=self.list_volumes, + args={ + "zone": zone, + "order_by": order_by, + "project_id": project_id, + "organization_id": organization_id, + "page": page, + "page_size": page_size, + "name": name, + "product_resource_id": product_resource_id, + "tags": tags, + }, + ) + + def create_volume( + self, + *, + zone: Optional[ScwZone] = None, + name: Optional[str] = None, + perf_iops: Optional[int] = None, + project_id: Optional[str] = None, + from_empty: Optional[CreateVolumeRequestFromEmpty] = None, + from_snapshot: Optional[CreateVolumeRequestFromSnapshot] = None, + tags: Optional[List[str]] = None, + ) -> Volume: + """ + Create a volume. + To create a new volume from scratch, you must specify `from_empty` and the `size`. + To create a volume from an existing snapshot, specify `from_snapshot` and the `snapshot_id` in the request payload instead, size is optional and can be specified if you need to extend the original size. The volume will take on the same volume class and underlying IOPS limitations as the original snapshot. + :param zone: Zone to target. If none is passed will use default zone from the config. + :param name: Name of the volume. + :param perf_iops: The maximum IO/s expected, according to the different options available in stock (`5000 | 15000`). + One-Of ('requirements'): at most one of 'perf_iops' could be set. + :param project_id: UUID of the project the volume belongs to. + :param from_empty: Specify the size of the new volume if creating a new one from scratch. + One-Of ('from'): at most one of 'from_empty', 'from_snapshot' could be set. + :param from_snapshot: Specify the snapshot ID of the original snapshot. + One-Of ('from'): at most one of 'from_empty', 'from_snapshot' could be set. + :param tags: List of tags assigned to the volume. + :return: :class:`Volume ` + + Usage: + :: + + result = api.create_volume() + """ + + param_zone = validate_path_param("zone", zone or self.client.default_zone) + + res = self._request( + "POST", + f"/block/v1/zones/{param_zone}/volumes", + body=marshal_CreateVolumeRequest( + CreateVolumeRequest( + zone=zone, + name=name or random_name(prefix="vol"), + project_id=project_id, + tags=tags, + from_empty=from_empty, + from_snapshot=from_snapshot, + perf_iops=perf_iops, + ), + self.client, + ), + ) + + self._throw_on_error(res) + return unmarshal_Volume(res.json()) + + def get_volume( + self, + *, + volume_id: str, + zone: Optional[ScwZone] = None, + ) -> Volume: + """ + Get a volume. + Retrieve technical information about a specific volume. Details such as size, type, and status are returned in the response. + :param volume_id: UUID of the volume. + :param zone: Zone to target. If none is passed will use default zone from the config. + :return: :class:`Volume ` + + Usage: + :: + + result = api.get_volume( + volume_id="example", + ) + """ + + param_zone = validate_path_param("zone", zone or self.client.default_zone) + param_volume_id = validate_path_param("volume_id", volume_id) + + res = self._request( + "GET", + f"/block/v1/zones/{param_zone}/volumes/{param_volume_id}", + ) + + self._throw_on_error(res) + return unmarshal_Volume(res.json()) + + def wait_for_volume( + self, + *, + volume_id: str, + zone: Optional[ScwZone] = None, + options: Optional[WaitForOptions[Volume, bool]] = None, + ) -> Volume: + """ + Get a volume. + Retrieve technical information about a specific volume. Details such as size, type, and status are returned in the response. + :param volume_id: UUID of the volume. + :param zone: Zone to target. If none is passed will use default zone from the config. + :return: :class:`Volume ` + + Usage: + :: + + result = api.get_volume( + volume_id="example", + ) + """ + + if not options: + options = WaitForOptions() + + if not options.stop: + options.stop = lambda res: res.status not in VOLUME_TRANSIENT_STATUSES + + return wait_for_resource( + fetcher=self.get_volume, + options=options, + args={ + "volume_id": volume_id, + "zone": zone, + }, + ) + + def delete_volume( + self, + *, + volume_id: str, + zone: Optional[ScwZone] = None, + ) -> None: + """ + Delete a detached volume. + You must specify the `volume_id` of the volume you want to delete. The volume must not be in the `in_use` status. + :param volume_id: UUID of the volume. + :param zone: Zone to target. If none is passed will use default zone from the config. + + Usage: + :: + + result = api.delete_volume( + volume_id="example", + ) + """ + + param_zone = validate_path_param("zone", zone or self.client.default_zone) + param_volume_id = validate_path_param("volume_id", volume_id) + + res = self._request( + "DELETE", + f"/block/v1/zones/{param_zone}/volumes/{param_volume_id}", + ) + + self._throw_on_error(res) + + def update_volume( + self, + *, + volume_id: str, + zone: Optional[ScwZone] = None, + name: Optional[str] = None, + size: Optional[int] = None, + tags: Optional[List[str]] = None, + perf_iops: Optional[int] = None, + ) -> Volume: + """ + Update a volume. + Update the technical details of a volume, such as its name, tags, or its new size and `volume_type` (within the same Block Storage class). + You can only resize a volume to a larger size. It is currently not possible to change your Block Storage Class. + :param volume_id: UUID of the volume. + :param zone: Zone to target. If none is passed will use default zone from the config. + :param name: When defined, is the new name of the volume. + :param size: Size in bytes of the volume, with a granularity of 1 GB (10^9 bytes). + Must be compliant with the minimum (1GB) and maximum (10TB) allowed size. + :param tags: List of tags assigned to the volume. + :param perf_iops: The selected value must be available for the volume's current storage class. + :return: :class:`Volume ` + + Usage: + :: + + result = api.update_volume( + volume_id="example", + ) + """ + + param_zone = validate_path_param("zone", zone or self.client.default_zone) + param_volume_id = validate_path_param("volume_id", volume_id) + + res = self._request( + "PATCH", + f"/block/v1/zones/{param_zone}/volumes/{param_volume_id}", + body=marshal_UpdateVolumeRequest( + UpdateVolumeRequest( + volume_id=volume_id, + zone=zone, + name=name, + size=size, + tags=tags, + perf_iops=perf_iops, + ), + self.client, + ), + ) + + self._throw_on_error(res) + return unmarshal_Volume(res.json()) + + def list_snapshots( + self, + *, + zone: Optional[ScwZone] = None, + order_by: Optional[ListSnapshotsRequestOrderBy] = None, + project_id: Optional[str] = None, + organization_id: Optional[str] = None, + page: Optional[int] = None, + page_size: Optional[int] = None, + volume_id: Optional[str] = None, + name: Optional[str] = None, + tags: Optional[List[str]] = None, + ) -> ListSnapshotsResponse: + """ + List all snapshots. + List all available snapshots in a specified zone. By default, the snapshots listed are ordered by creation date in ascending order. This can be modified via the `order_by` field. + :param zone: Zone to target. If none is passed will use default zone from the config. + :param order_by: Criteria to use when ordering the list. + :param project_id: Filter by Project ID. + :param organization_id: Filter by Organization ID. + :param page: Page number. + :param page_size: Page size, defines how many entries are returned in one page, must be lower or equal to 100. + :param volume_id: Filter snapshots by the ID of the original volume. + :param name: Filter snapshots by their names. + :param tags: Filter by tags. Only snapshots with one or more matching tags will be returned. + :return: :class:`ListSnapshotsResponse ` + + Usage: + :: + + result = api.list_snapshots() + """ + + param_zone = validate_path_param("zone", zone or self.client.default_zone) + + res = self._request( + "GET", + f"/block/v1/zones/{param_zone}/snapshots", + params={ + "name": name, + "order_by": order_by, + "organization_id": organization_id + or self.client.default_organization_id, + "page": page, + "page_size": page_size or self.client.default_page_size, + "project_id": project_id or self.client.default_project_id, + "tags": tags, + "volume_id": volume_id, + }, + ) + + self._throw_on_error(res) + return unmarshal_ListSnapshotsResponse(res.json()) + + def list_snapshots_all( + self, + *, + zone: Optional[ScwZone] = None, + order_by: Optional[ListSnapshotsRequestOrderBy] = None, + project_id: Optional[str] = None, + organization_id: Optional[str] = None, + page: Optional[int] = None, + page_size: Optional[int] = None, + volume_id: Optional[str] = None, + name: Optional[str] = None, + tags: Optional[List[str]] = None, + ) -> List[Snapshot]: + """ + List all snapshots. + List all available snapshots in a specified zone. By default, the snapshots listed are ordered by creation date in ascending order. This can be modified via the `order_by` field. + :param zone: Zone to target. If none is passed will use default zone from the config. + :param order_by: Criteria to use when ordering the list. + :param project_id: Filter by Project ID. + :param organization_id: Filter by Organization ID. + :param page: Page number. + :param page_size: Page size, defines how many entries are returned in one page, must be lower or equal to 100. + :param volume_id: Filter snapshots by the ID of the original volume. + :param name: Filter snapshots by their names. + :param tags: Filter by tags. Only snapshots with one or more matching tags will be returned. + :return: :class:`List[Snapshot] ` + + Usage: + :: + + result = api.list_snapshots_all() + """ + + return fetch_all_pages( + type=ListSnapshotsResponse, + key="snapshots", + fetcher=self.list_snapshots, + args={ + "zone": zone, + "order_by": order_by, + "project_id": project_id, + "organization_id": organization_id, + "page": page, + "page_size": page_size, + "volume_id": volume_id, + "name": name, + "tags": tags, + }, + ) + + def get_snapshot( + self, + *, + snapshot_id: str, + zone: Optional[ScwZone] = None, + ) -> Snapshot: + """ + Get a snapshot. + Retrieve technical information about a specific snapshot. Details such as size, volume type, and status are returned in the response. + :param snapshot_id: UUID of the snapshot. + :param zone: Zone to target. If none is passed will use default zone from the config. + :return: :class:`Snapshot ` + + Usage: + :: + + result = api.get_snapshot( + snapshot_id="example", + ) + """ + + param_zone = validate_path_param("zone", zone or self.client.default_zone) + param_snapshot_id = validate_path_param("snapshot_id", snapshot_id) + + res = self._request( + "GET", + f"/block/v1/zones/{param_zone}/snapshots/{param_snapshot_id}", + ) + + self._throw_on_error(res) + return unmarshal_Snapshot(res.json()) + + def wait_for_snapshot( + self, + *, + snapshot_id: str, + zone: Optional[ScwZone] = None, + options: Optional[WaitForOptions[Snapshot, bool]] = None, + ) -> Snapshot: + """ + Get a snapshot. + Retrieve technical information about a specific snapshot. Details such as size, volume type, and status are returned in the response. + :param snapshot_id: UUID of the snapshot. + :param zone: Zone to target. If none is passed will use default zone from the config. + :return: :class:`Snapshot ` + + Usage: + :: + + result = api.get_snapshot( + snapshot_id="example", + ) + """ + + if not options: + options = WaitForOptions() + + if not options.stop: + options.stop = lambda res: res.status not in SNAPSHOT_TRANSIENT_STATUSES + + return wait_for_resource( + fetcher=self.get_snapshot, + options=options, + args={ + "snapshot_id": snapshot_id, + "zone": zone, + }, + ) + + def create_snapshot( + self, + *, + volume_id: str, + zone: Optional[ScwZone] = None, + name: Optional[str] = None, + project_id: Optional[str] = None, + tags: Optional[List[str]] = None, + ) -> Snapshot: + """ + Create a snapshot of a volume. + To create a snapshot, the volume must be in the `in_use` or the `available` status. + If your volume is in a transient state, you need to wait until the end of the current operation. + :param volume_id: UUID of the volume to snapshot. + :param zone: Zone to target. If none is passed will use default zone from the config. + :param name: Name of the snapshot. + :param project_id: UUID of the project to which the volume and the snapshot belong. + :param tags: List of tags assigned to the snapshot. + :return: :class:`Snapshot ` + + Usage: + :: + + result = api.create_snapshot( + volume_id="example", + ) + """ + + param_zone = validate_path_param("zone", zone or self.client.default_zone) + + res = self._request( + "POST", + f"/block/v1/zones/{param_zone}/snapshots", + body=marshal_CreateSnapshotRequest( + CreateSnapshotRequest( + volume_id=volume_id, + zone=zone, + name=name or random_name(prefix="snp"), + project_id=project_id, + tags=tags, + ), + self.client, + ), + ) + + self._throw_on_error(res) + return unmarshal_Snapshot(res.json()) + + def import_snapshot_from_object_storage( + self, + *, + bucket: str, + key: str, + name: str, + zone: Optional[ScwZone] = None, + project_id: Optional[str] = None, + tags: Optional[List[str]] = None, + size: Optional[int] = None, + ) -> Snapshot: + """ + Import a snapshot from a Scaleway Object Storage bucket. + The bucket must contain a QCOW2 image. + The bucket can be imported into any Availability Zone as long as it is in the same region as the bucket. + :param bucket: Scaleway Object Storage bucket where the object is stored. + :param key: The object key inside the given bucket. + :param name: Name of the snapshot. + :param zone: Zone to target. If none is passed will use default zone from the config. + :param project_id: UUID of the Project to which the volume and the snapshot belong. + :param tags: List of tags assigned to the snapshot. + :param size: Size of the snapshot. + :return: :class:`Snapshot ` + + Usage: + :: + + result = api.import_snapshot_from_object_storage( + bucket="example", + key="example", + name="example", + ) + """ + + param_zone = validate_path_param("zone", zone or self.client.default_zone) + + res = self._request( + "POST", + f"/block/v1/zones/{param_zone}/snapshots/import-from-object-storage", + body=marshal_ImportSnapshotFromObjectStorageRequest( + ImportSnapshotFromObjectStorageRequest( + bucket=bucket, + key=key, + name=name, + zone=zone, + project_id=project_id, + tags=tags, + size=size, + ), + self.client, + ), + ) + + self._throw_on_error(res) + return unmarshal_Snapshot(res.json()) + + def export_snapshot_to_object_storage( + self, + *, + snapshot_id: str, + bucket: str, + key: str, + zone: Optional[ScwZone] = None, + ) -> Snapshot: + """ + Export a snapshot to a Scaleway Object Storage bucket. + The snapshot is exported in QCOW2 format. + The snapshot must not be in transient state. + :param snapshot_id: UUID of the snapshot. + :param bucket: Scaleway Object Storage bucket where the object is stored. + :param key: The object key inside the given bucket. + :param zone: Zone to target. If none is passed will use default zone from the config. + :return: :class:`Snapshot ` + + Usage: + :: + + result = api.export_snapshot_to_object_storage( + snapshot_id="example", + bucket="example", + key="example", + ) + """ + + param_zone = validate_path_param("zone", zone or self.client.default_zone) + param_snapshot_id = validate_path_param("snapshot_id", snapshot_id) + + res = self._request( + "POST", + f"/block/v1/zones/{param_zone}/snapshots/{param_snapshot_id}/export-to-object-storage", + body=marshal_ExportSnapshotToObjectStorageRequest( + ExportSnapshotToObjectStorageRequest( + snapshot_id=snapshot_id, + bucket=bucket, + key=key, + zone=zone, + ), + self.client, + ), + ) + + self._throw_on_error(res) + return unmarshal_Snapshot(res.json()) + + def delete_snapshot( + self, + *, + snapshot_id: str, + zone: Optional[ScwZone] = None, + ) -> None: + """ + Delete a snapshot. + You must specify the `snapshot_id` of the snapshot you want to delete. The snapshot must not be in use. + :param snapshot_id: UUID of the snapshot. + :param zone: Zone to target. If none is passed will use default zone from the config. + + Usage: + :: + + result = api.delete_snapshot( + snapshot_id="example", + ) + """ + + param_zone = validate_path_param("zone", zone or self.client.default_zone) + param_snapshot_id = validate_path_param("snapshot_id", snapshot_id) + + res = self._request( + "DELETE", + f"/block/v1/zones/{param_zone}/snapshots/{param_snapshot_id}", + ) + + self._throw_on_error(res) + + def update_snapshot( + self, + *, + snapshot_id: str, + zone: Optional[ScwZone] = None, + name: Optional[str] = None, + tags: Optional[List[str]] = None, + ) -> Snapshot: + """ + Update a snapshot. + Update the name or tags of the snapshot. + :param snapshot_id: UUID of the snapshot. + :param zone: Zone to target. If none is passed will use default zone from the config. + :param name: When defined, is the name of the snapshot. + :param tags: List of tags assigned to the snapshot. + :return: :class:`Snapshot ` + + Usage: + :: + + result = api.update_snapshot( + snapshot_id="example", + ) + """ + + param_zone = validate_path_param("zone", zone or self.client.default_zone) + param_snapshot_id = validate_path_param("snapshot_id", snapshot_id) + + res = self._request( + "PATCH", + f"/block/v1/zones/{param_zone}/snapshots/{param_snapshot_id}", + body=marshal_UpdateSnapshotRequest( + UpdateSnapshotRequest( + snapshot_id=snapshot_id, + zone=zone, + name=name, + tags=tags, + ), + self.client, + ), + ) + + self._throw_on_error(res) + return unmarshal_Snapshot(res.json()) diff --git a/scaleway/scaleway/block/v1/content.py b/scaleway/scaleway/block/v1/content.py new file mode 100644 index 000000000..a6cf1ee67 --- /dev/null +++ b/scaleway/scaleway/block/v1/content.py @@ -0,0 +1,36 @@ +# This file was automatically generated. DO NOT EDIT. +# If you have any remark or suggestion do not hesitate to open an issue. +from typing import List + +from .types import ( + ReferenceStatus, + SnapshotStatus, + VolumeStatus, +) + +REFERENCE_TRANSIENT_STATUSES: List[ReferenceStatus] = [ + ReferenceStatus.ATTACHING, + ReferenceStatus.DETACHING, + ReferenceStatus.CREATING, +] +""" +Lists transient statutes of the enum :class:`ReferenceStatus `. +""" +SNAPSHOT_TRANSIENT_STATUSES: List[SnapshotStatus] = [ + SnapshotStatus.CREATING, + SnapshotStatus.DELETING, + SnapshotStatus.EXPORTING, +] +""" +Lists transient statutes of the enum :class:`SnapshotStatus `. +""" +VOLUME_TRANSIENT_STATUSES: List[VolumeStatus] = [ + VolumeStatus.CREATING, + VolumeStatus.DELETING, + VolumeStatus.RESIZING, + VolumeStatus.SNAPSHOTTING, + VolumeStatus.UPDATING, +] +""" +Lists transient statutes of the enum :class:`VolumeStatus `. +""" diff --git a/scaleway/scaleway/block/v1/marshalling.py b/scaleway/scaleway/block/v1/marshalling.py new file mode 100644 index 000000000..d1aef6680 --- /dev/null +++ b/scaleway/scaleway/block/v1/marshalling.py @@ -0,0 +1,521 @@ +# This file was automatically generated. DO NOT EDIT. +# If you have any remark or suggestion do not hesitate to open an issue. + +from typing import Any, Dict +from dateutil import parser + +from scaleway_core.profile import ProfileDefaults +from scaleway_core.bridge import ( + unmarshal_Money, +) +from scaleway_core.utils import ( + OneOfPossibility, + resolve_one_of, +) +from .types import ( + Reference, + SnapshotParentVolume, + Snapshot, + VolumeSpecifications, + Volume, + ListSnapshotsResponse, + VolumeType, + ListVolumeTypesResponse, + ListVolumesResponse, + CreateSnapshotRequest, + CreateVolumeRequestFromEmpty, + CreateVolumeRequestFromSnapshot, + CreateVolumeRequest, + ExportSnapshotToObjectStorageRequest, + ImportSnapshotFromObjectStorageRequest, + UpdateSnapshotRequest, + UpdateVolumeRequest, +) + + +def unmarshal_Reference(data: Any) -> Reference: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'Reference' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("id", None) + if field is not None: + args["id"] = field + + field = data.get("product_resource_type", None) + if field is not None: + args["product_resource_type"] = field + + field = data.get("product_resource_id", None) + if field is not None: + args["product_resource_id"] = field + + field = data.get("type", None) + if field is not None: + args["type_"] = field + + field = data.get("status", None) + if field is not None: + args["status"] = field + + field = data.get("created_at", None) + if field is not None: + args["created_at"] = parser.isoparse(field) if isinstance(field, str) else field + else: + args["created_at"] = None + + return Reference(**args) + + +def unmarshal_SnapshotParentVolume(data: Any) -> SnapshotParentVolume: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'SnapshotParentVolume' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("id", None) + if field is not None: + args["id"] = field + + field = data.get("name", None) + if field is not None: + args["name"] = field + + field = data.get("type", None) + if field is not None: + args["type_"] = field + + field = data.get("status", None) + if field is not None: + args["status"] = field + + return SnapshotParentVolume(**args) + + +def unmarshal_Snapshot(data: Any) -> Snapshot: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'Snapshot' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("id", None) + if field is not None: + args["id"] = field + + field = data.get("name", None) + if field is not None: + args["name"] = field + + field = data.get("size", None) + if field is not None: + args["size"] = field + + field = data.get("project_id", None) + if field is not None: + args["project_id"] = field + + field = data.get("references", None) + if field is not None: + args["references"] = ( + [unmarshal_Reference(v) for v in field] if field is not None else None + ) + + field = data.get("status", None) + if field is not None: + args["status"] = field + + field = data.get("tags", None) + if field is not None: + args["tags"] = field + + field = data.get("zone", None) + if field is not None: + args["zone"] = field + + field = data.get("class", None) + if field is not None: + args["class_"] = field + + field = data.get("parent_volume", None) + if field is not None: + args["parent_volume"] = unmarshal_SnapshotParentVolume(field) + else: + args["parent_volume"] = None + + field = data.get("created_at", None) + if field is not None: + args["created_at"] = parser.isoparse(field) if isinstance(field, str) else field + else: + args["created_at"] = None + + field = data.get("updated_at", None) + if field is not None: + args["updated_at"] = parser.isoparse(field) if isinstance(field, str) else field + else: + args["updated_at"] = None + + return Snapshot(**args) + + +def unmarshal_VolumeSpecifications(data: Any) -> VolumeSpecifications: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'VolumeSpecifications' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("class", None) + if field is not None: + args["class_"] = field + + field = data.get("perf_iops", None) + if field is not None: + args["perf_iops"] = field + else: + args["perf_iops"] = None + + return VolumeSpecifications(**args) + + +def unmarshal_Volume(data: Any) -> Volume: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'Volume' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("id", None) + if field is not None: + args["id"] = field + + field = data.get("name", None) + if field is not None: + args["name"] = field + + field = data.get("type", None) + if field is not None: + args["type_"] = field + + field = data.get("size", None) + if field is not None: + args["size"] = field + + field = data.get("project_id", None) + if field is not None: + args["project_id"] = field + + field = data.get("references", None) + if field is not None: + args["references"] = ( + [unmarshal_Reference(v) for v in field] if field is not None else None + ) + + field = data.get("created_at", None) + if field is not None: + args["created_at"] = parser.isoparse(field) if isinstance(field, str) else field + else: + args["created_at"] = None + + field = data.get("updated_at", None) + if field is not None: + args["updated_at"] = parser.isoparse(field) if isinstance(field, str) else field + else: + args["updated_at"] = None + + field = data.get("parent_snapshot_id", None) + if field is not None: + args["parent_snapshot_id"] = field + else: + args["parent_snapshot_id"] = None + + field = data.get("status", None) + if field is not None: + args["status"] = field + + field = data.get("tags", None) + if field is not None: + args["tags"] = field + + field = data.get("zone", None) + if field is not None: + args["zone"] = field + + field = data.get("specs", None) + if field is not None: + args["specs"] = unmarshal_VolumeSpecifications(field) + else: + args["specs"] = None + + field = data.get("last_detached_at", None) + if field is not None: + args["last_detached_at"] = ( + parser.isoparse(field) if isinstance(field, str) else field + ) + else: + args["last_detached_at"] = None + + return Volume(**args) + + +def unmarshal_ListSnapshotsResponse(data: Any) -> ListSnapshotsResponse: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'ListSnapshotsResponse' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("snapshots", None) + if field is not None: + args["snapshots"] = ( + [unmarshal_Snapshot(v) for v in field] if field is not None else None + ) + + field = data.get("total_count", None) + if field is not None: + args["total_count"] = field + + return ListSnapshotsResponse(**args) + + +def unmarshal_VolumeType(data: Any) -> VolumeType: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'VolumeType' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("type", None) + if field is not None: + args["type_"] = field + + field = data.get("pricing", None) + if field is not None: + args["pricing"] = unmarshal_Money(field) + else: + args["pricing"] = None + + field = data.get("snapshot_pricing", None) + if field is not None: + args["snapshot_pricing"] = unmarshal_Money(field) + else: + args["snapshot_pricing"] = None + + field = data.get("specs", None) + if field is not None: + args["specs"] = unmarshal_VolumeSpecifications(field) + else: + args["specs"] = None + + return VolumeType(**args) + + +def unmarshal_ListVolumeTypesResponse(data: Any) -> ListVolumeTypesResponse: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'ListVolumeTypesResponse' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("volume_types", None) + if field is not None: + args["volume_types"] = ( + [unmarshal_VolumeType(v) for v in field] if field is not None else None + ) + + field = data.get("total_count", None) + if field is not None: + args["total_count"] = field + + return ListVolumeTypesResponse(**args) + + +def unmarshal_ListVolumesResponse(data: Any) -> ListVolumesResponse: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'ListVolumesResponse' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("volumes", None) + if field is not None: + args["volumes"] = ( + [unmarshal_Volume(v) for v in field] if field is not None else None + ) + + field = data.get("total_count", None) + if field is not None: + args["total_count"] = field + + return ListVolumesResponse(**args) + + +def marshal_CreateSnapshotRequest( + request: CreateSnapshotRequest, + defaults: ProfileDefaults, +) -> Dict[str, Any]: + output: Dict[str, Any] = {} + + if request.volume_id is not None: + output["volume_id"] = request.volume_id + + if request.name is not None: + output["name"] = request.name + + if request.project_id is not None: + output["project_id"] = request.project_id or defaults.default_project_id + + if request.tags is not None: + output["tags"] = request.tags + + return output + + +def marshal_CreateVolumeRequestFromEmpty( + request: CreateVolumeRequestFromEmpty, + defaults: ProfileDefaults, +) -> Dict[str, Any]: + output: Dict[str, Any] = {} + + if request.size is not None: + output["size"] = request.size + + return output + + +def marshal_CreateVolumeRequestFromSnapshot( + request: CreateVolumeRequestFromSnapshot, + defaults: ProfileDefaults, +) -> Dict[str, Any]: + output: Dict[str, Any] = {} + + if request.snapshot_id is not None: + output["snapshot_id"] = request.snapshot_id + + if request.size is not None: + output["size"] = request.size + + return output + + +def marshal_CreateVolumeRequest( + request: CreateVolumeRequest, + defaults: ProfileDefaults, +) -> Dict[str, Any]: + output: Dict[str, Any] = {} + output.update( + resolve_one_of( + [ + OneOfPossibility("from_empty", request.from_empty), + OneOfPossibility("from_snapshot", request.from_snapshot), + ] + ), + ) + output.update( + resolve_one_of( + [ + OneOfPossibility("perf_iops", request.perf_iops), + ] + ), + ) + + if request.name is not None: + output["name"] = request.name + + if request.project_id is not None: + output["project_id"] = request.project_id or defaults.default_project_id + + if request.tags is not None: + output["tags"] = request.tags + + return output + + +def marshal_ExportSnapshotToObjectStorageRequest( + request: ExportSnapshotToObjectStorageRequest, + defaults: ProfileDefaults, +) -> Dict[str, Any]: + output: Dict[str, Any] = {} + + if request.bucket is not None: + output["bucket"] = request.bucket + + if request.key is not None: + output["key"] = request.key + + return output + + +def marshal_ImportSnapshotFromObjectStorageRequest( + request: ImportSnapshotFromObjectStorageRequest, + defaults: ProfileDefaults, +) -> Dict[str, Any]: + output: Dict[str, Any] = {} + + if request.bucket is not None: + output["bucket"] = request.bucket + + if request.key is not None: + output["key"] = request.key + + if request.name is not None: + output["name"] = request.name + + if request.project_id is not None: + output["project_id"] = request.project_id or defaults.default_project_id + + if request.tags is not None: + output["tags"] = request.tags + + if request.size is not None: + output["size"] = request.size + + return output + + +def marshal_UpdateSnapshotRequest( + request: UpdateSnapshotRequest, + defaults: ProfileDefaults, +) -> Dict[str, Any]: + output: Dict[str, Any] = {} + + if request.name is not None: + output["name"] = request.name + + if request.tags is not None: + output["tags"] = request.tags + + return output + + +def marshal_UpdateVolumeRequest( + request: UpdateVolumeRequest, + defaults: ProfileDefaults, +) -> Dict[str, Any]: + output: Dict[str, Any] = {} + + if request.name is not None: + output["name"] = request.name + + if request.size is not None: + output["size"] = request.size + + if request.tags is not None: + output["tags"] = request.tags + + if request.perf_iops is not None: + output["perf_iops"] = request.perf_iops + + return output diff --git a/scaleway/scaleway/block/v1/types.py b/scaleway/scaleway/block/v1/types.py new file mode 100644 index 000000000..d666ce94c --- /dev/null +++ b/scaleway/scaleway/block/v1/types.py @@ -0,0 +1,731 @@ +# This file was automatically generated. DO NOT EDIT. +# If you have any remark or suggestion do not hesitate to open an issue. +from __future__ import annotations + +from dataclasses import dataclass +from datetime import datetime +from enum import Enum +from typing import List, Optional + +from scaleway_core.bridge import ( + Money, + Zone as ScwZone, +) +from scaleway_core.utils import ( + StrEnumMeta, +) + + +class ListSnapshotsRequestOrderBy(str, Enum, metaclass=StrEnumMeta): + CREATED_AT_ASC = "created_at_asc" + CREATED_AT_DESC = "created_at_desc" + NAME_ASC = "name_asc" + NAME_DESC = "name_desc" + + def __str__(self) -> str: + return str(self.value) + + +class ListVolumesRequestOrderBy(str, Enum, metaclass=StrEnumMeta): + CREATED_AT_ASC = "created_at_asc" + CREATED_AT_DESC = "created_at_desc" + NAME_ASC = "name_asc" + NAME_DESC = "name_desc" + + def __str__(self) -> str: + return str(self.value) + + +class ReferenceStatus(str, Enum, metaclass=StrEnumMeta): + UNKNOWN_STATUS = "unknown_status" + ATTACHING = "attaching" + ATTACHED = "attached" + DETACHING = "detaching" + DETACHED = "detached" + CREATING = "creating" + ERROR = "error" + + def __str__(self) -> str: + return str(self.value) + + +class ReferenceType(str, Enum, metaclass=StrEnumMeta): + UNKNOWN_TYPE = "unknown_type" + LINK = "link" + EXCLUSIVE = "exclusive" + READ_ONLY = "read_only" + + def __str__(self) -> str: + return str(self.value) + + +class SnapshotStatus(str, Enum, metaclass=StrEnumMeta): + UNKNOWN_STATUS = "unknown_status" + CREATING = "creating" + AVAILABLE = "available" + ERROR = "error" + DELETING = "deleting" + DELETED = "deleted" + IN_USE = "in_use" + LOCKED = "locked" + EXPORTING = "exporting" + + def __str__(self) -> str: + return str(self.value) + + +class StorageClass(str, Enum, metaclass=StrEnumMeta): + UNKNOWN_STORAGE_CLASS = "unknown_storage_class" + UNSPECIFIED = "unspecified" + BSSD = "bssd" + SBS = "sbs" + + def __str__(self) -> str: + return str(self.value) + + +class VolumeStatus(str, Enum, metaclass=StrEnumMeta): + UNKNOWN_STATUS = "unknown_status" + CREATING = "creating" + AVAILABLE = "available" + IN_USE = "in_use" + DELETING = "deleting" + DELETED = "deleted" + RESIZING = "resizing" + ERROR = "error" + SNAPSHOTTING = "snapshotting" + LOCKED = "locked" + UPDATING = "updating" + + def __str__(self) -> str: + return str(self.value) + + +@dataclass +class Reference: + id: str + """ + UUID of the reference. + """ + + product_resource_type: str + """ + Type of resource to which the reference is associated. + """ + + product_resource_id: str + """ + UUID of the product resource it refers to (according to the product_resource_type). + """ + + type_: ReferenceType + """ + Type of reference (link, exclusive, read_only). + """ + + status: ReferenceStatus + """ + Status of the reference. Statuses include `attaching`, `attached`, and `detaching`. + """ + + created_at: Optional[datetime] + """ + Creation date of the reference. + """ + + +@dataclass +class SnapshotParentVolume: + id: str + """ + Parent volume UUID (volume from which the snapshot originates). + """ + + name: str + """ + Name of the parent volume. + """ + + type_: str + """ + Volume type of the parent volume. + """ + + status: VolumeStatus + """ + Current status the parent volume. + """ + + +@dataclass +class VolumeSpecifications: + class_: StorageClass + """ + The storage class of the volume. + """ + + perf_iops: Optional[int] + """ + The maximum IO/s expected, according to the different options available in stock (`5000 | 15000`). + """ + + +@dataclass +class CreateVolumeRequestFromEmpty: + size: int + """ + Must be compliant with the minimum (1 GB) and maximum (10 TB) allowed size. + """ + + +@dataclass +class CreateVolumeRequestFromSnapshot: + snapshot_id: str + """ + Source snapshot from which volume will be created. + """ + + size: Optional[int] + """ + Must be compliant with the minimum (1 GB) and maximum (10 TB) allowed size. +Size is optional and is used only if a resize of the volume is requested, otherwise original snapshot size will be used. + """ + + +@dataclass +class Snapshot: + id: str + """ + UUID of the snapshot. + """ + + name: str + """ + Name of the snapshot. + """ + + size: int + """ + Size in bytes of the snapshot. + """ + + project_id: str + """ + UUID of the project the snapshot belongs to. + """ + + references: List[Reference] + """ + List of the references to the snapshot. + """ + + status: SnapshotStatus + """ + Current status of the snapshot (available, in_use, ...). + """ + + tags: List[str] + """ + List of tags assigned to the volume. + """ + + zone: ScwZone + """ + Snapshot zone. + """ + + class_: StorageClass + """ + Storage class of the snapshot. + """ + + parent_volume: Optional[SnapshotParentVolume] + """ + If the parent volume was deleted, value is null. + """ + + created_at: Optional[datetime] + """ + Creation date of the snapshot. + """ + + updated_at: Optional[datetime] + """ + Last modification date of the properties of a snapshot. + """ + + +@dataclass +class VolumeType: + type_: str + """ + Volume type. + """ + + pricing: Optional[Money] + """ + Price of the volume billed in GB/hour. + """ + + snapshot_pricing: Optional[Money] + """ + Price of the snapshot billed in GB/hour. + """ + + specs: Optional[VolumeSpecifications] + """ + Volume specifications of the volume type. + """ + + +@dataclass +class Volume: + id: str + """ + UUID of the volume. + """ + + name: str + """ + Name of the volume. + """ + + type_: str + """ + Volume type. + """ + + size: int + """ + Volume size in bytes. + """ + + project_id: str + """ + UUID of the project to which the volume belongs. + """ + + references: List[Reference] + """ + List of the references to the volume. + """ + + created_at: Optional[datetime] + """ + Creation date of the volume. + """ + + updated_at: Optional[datetime] + """ + Last update of the properties of a volume. + """ + + parent_snapshot_id: Optional[str] + """ + When a volume is created from a snapshot, is the UUID of the snapshot from which the volume has been created. + """ + + status: VolumeStatus + """ + Current status of the volume (available, in_use, ...). + """ + + tags: List[str] + """ + List of tags assigned to the volume. + """ + + zone: ScwZone + """ + Volume zone. + """ + + specs: Optional[VolumeSpecifications] + """ + Specifications of the volume. + """ + + last_detached_at: Optional[datetime] + """ + Last time the volume was detached. + """ + + +@dataclass +class CreateSnapshotRequest: + volume_id: str + """ + UUID of the volume to snapshot. + """ + + zone: Optional[ScwZone] + """ + Zone to target. If none is passed will use default zone from the config. + """ + + name: Optional[str] + """ + Name of the snapshot. + """ + + project_id: Optional[str] + """ + UUID of the project to which the volume and the snapshot belong. + """ + + tags: Optional[List[str]] + """ + List of tags assigned to the snapshot. + """ + + +@dataclass +class CreateVolumeRequest: + zone: Optional[ScwZone] + """ + Zone to target. If none is passed will use default zone from the config. + """ + + name: Optional[str] + """ + Name of the volume. + """ + + project_id: Optional[str] + """ + UUID of the project the volume belongs to. + """ + + tags: Optional[List[str]] + """ + List of tags assigned to the volume. + """ + + from_empty: Optional[CreateVolumeRequestFromEmpty] + + from_snapshot: Optional[CreateVolumeRequestFromSnapshot] + + perf_iops: Optional[int] + + +@dataclass +class DeleteSnapshotRequest: + snapshot_id: str + """ + UUID of the snapshot. + """ + + zone: Optional[ScwZone] + """ + Zone to target. If none is passed will use default zone from the config. + """ + + +@dataclass +class DeleteVolumeRequest: + volume_id: str + """ + UUID of the volume. + """ + + zone: Optional[ScwZone] + """ + Zone to target. If none is passed will use default zone from the config. + """ + + +@dataclass +class ExportSnapshotToObjectStorageRequest: + snapshot_id: str + """ + UUID of the snapshot. + """ + + bucket: str + """ + Scaleway Object Storage bucket where the object is stored. + """ + + key: str + """ + The object key inside the given bucket. + """ + + zone: Optional[ScwZone] + """ + Zone to target. If none is passed will use default zone from the config. + """ + + +@dataclass +class GetSnapshotRequest: + snapshot_id: str + """ + UUID of the snapshot. + """ + + zone: Optional[ScwZone] + """ + Zone to target. If none is passed will use default zone from the config. + """ + + +@dataclass +class GetVolumeRequest: + volume_id: str + """ + UUID of the volume. + """ + + zone: Optional[ScwZone] + """ + Zone to target. If none is passed will use default zone from the config. + """ + + +@dataclass +class ImportSnapshotFromObjectStorageRequest: + bucket: str + """ + Scaleway Object Storage bucket where the object is stored. + """ + + key: str + """ + The object key inside the given bucket. + """ + + name: str + """ + Name of the snapshot. + """ + + zone: Optional[ScwZone] + """ + Zone to target. If none is passed will use default zone from the config. + """ + + project_id: Optional[str] + """ + UUID of the Project to which the volume and the snapshot belong. + """ + + tags: Optional[List[str]] + """ + List of tags assigned to the snapshot. + """ + + size: Optional[int] + """ + Size of the snapshot. + """ + + +@dataclass +class ListSnapshotsRequest: + zone: Optional[ScwZone] + """ + Zone to target. If none is passed will use default zone from the config. + """ + + order_by: Optional[ListSnapshotsRequestOrderBy] + """ + Criteria to use when ordering the list. + """ + + project_id: Optional[str] + """ + Filter by Project ID. + """ + + organization_id: Optional[str] + """ + Filter by Organization ID. + """ + + page: Optional[int] + """ + Page number. + """ + + page_size: Optional[int] + """ + Page size, defines how many entries are returned in one page, must be lower or equal to 100. + """ + + volume_id: Optional[str] + """ + Filter snapshots by the ID of the original volume. + """ + + name: Optional[str] + """ + Filter snapshots by their names. + """ + + tags: Optional[List[str]] + """ + Filter by tags. Only snapshots with one or more matching tags will be returned. + """ + + +@dataclass +class ListSnapshotsResponse: + snapshots: List[Snapshot] + """ + Paginated returned list of snapshots. + """ + + total_count: int + """ + Total number of snpashots in the project. + """ + + +@dataclass +class ListVolumeTypesRequest: + zone: Optional[ScwZone] + """ + Zone to target. If none is passed will use default zone from the config. + """ + + page: Optional[int] + """ + Page number. + """ + + page_size: Optional[int] + """ + Page size, defines how many entries are returned in one page, must be lower or equal to 100. + """ + + +@dataclass +class ListVolumeTypesResponse: + volume_types: List[VolumeType] + """ + Returns paginated list of volume-types. + """ + + total_count: int + """ + Total number of volume-types currently available in stock. + """ + + +@dataclass +class ListVolumesRequest: + zone: Optional[ScwZone] + """ + Zone to target. If none is passed will use default zone from the config. + """ + + order_by: Optional[ListVolumesRequestOrderBy] + """ + Criteria to use when ordering the list. + """ + + project_id: Optional[str] + """ + Filter by Project ID. + """ + + organization_id: Optional[str] + """ + Filter by Organization ID. + """ + + page: Optional[int] + """ + Page number. + """ + + page_size: Optional[int] + """ + Page size, defines how many entries are returned in one page, must be lower or equal to 100. + """ + + name: Optional[str] + """ + Filter the return volumes by their names. + """ + + product_resource_id: Optional[str] + """ + Filter by a product resource ID linked to this volume (such as an Instance ID). + """ + + tags: Optional[List[str]] + """ + Filter by tags. Only volumes with one or more matching tags will be returned. + """ + + +@dataclass +class ListVolumesResponse: + volumes: List[Volume] + """ + Paginated returned list of volumes. + """ + + total_count: int + """ + Total number of volumes in the project. + """ + + +@dataclass +class UpdateSnapshotRequest: + snapshot_id: str + """ + UUID of the snapshot. + """ + + zone: Optional[ScwZone] + """ + Zone to target. If none is passed will use default zone from the config. + """ + + name: Optional[str] + """ + When defined, is the name of the snapshot. + """ + + tags: Optional[List[str]] + """ + List of tags assigned to the snapshot. + """ + + +@dataclass +class UpdateVolumeRequest: + volume_id: str + """ + UUID of the volume. + """ + + zone: Optional[ScwZone] + """ + Zone to target. If none is passed will use default zone from the config. + """ + + name: Optional[str] + """ + When defined, is the new name of the volume. + """ + + size: Optional[int] + """ + Size in bytes of the volume, with a granularity of 1 GB (10^9 bytes). +Must be compliant with the minimum (1GB) and maximum (10TB) allowed size. + """ + + tags: Optional[List[str]] + """ + List of tags assigned to the volume. + """ + + perf_iops: Optional[int] + """ + The selected value must be available for the volume's current storage class. + """