Skip to content
Merged
Show file tree
Hide file tree
Changes from 66 commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
156a19a
factor out tasks part in storage rpc api
bisgaard-itis Feb 14, 2025
64c137d
use 'async_jobs' terminology and refactor rpc client for reusability
bisgaard-itis Feb 14, 2025
f6e73e3
further refactoring
bisgaard-itis Feb 14, 2025
50fa599
make async job rpc client more reusable
bisgaard-itis Feb 14, 2025
1ce7158
tasks -> async jobs
bisgaard-itis Feb 15, 2025
1229e92
tasks -> async_job
bisgaard-itis Feb 15, 2025
ce064ce
start adding data-export endpoints in webserver
bisgaard-itis Feb 15, 2025
223631e
further renaming
bisgaard-itis Feb 16, 2025
0bd94d6
create openapi-specs make target for webserver to ensure github workf…
bisgaard-itis Feb 16, 2025
b43b22d
add webserver endpoint for triggering data export
bisgaard-itis Feb 16, 2025
9795838
add webserver endpoint for getting async job status
bisgaard-itis Feb 16, 2025
224dfe2
minor fix
bisgaard-itis Feb 17, 2025
3fb022e
add initial test
bisgaard-itis Feb 17, 2025
ac06db4
pass login and permission in test
bisgaard-itis Feb 17, 2025
249967e
add get status test
bisgaard-itis Feb 17, 2025
8b154af
add location id in webserver endpoint
bisgaard-itis Feb 17, 2025
ac20937
task_id -> job_id
bisgaard-itis Feb 17, 2025
527e7a6
cleanup
bisgaard-itis Feb 17, 2025
999907e
add test for abort endpoint
bisgaard-itis Feb 17, 2025
520c043
add test for endpoint of getting result
bisgaard-itis Feb 17, 2025
1b42a8f
update webserver openapi specs
bisgaard-itis Feb 17, 2025
a649c71
start adding exceptions and propagating them
bisgaard-itis Feb 17, 2025
4ad6aac
add exception handling to endpoint for triggering data export
bisgaard-itis Feb 18, 2025
33b5ccf
remove 'data_export' from async jobs model lib section
bisgaard-itis Feb 18, 2025
661b3b2
add exception handling for remaining endpoints
bisgaard-itis Feb 18, 2025
6972cf5
merge master into 7197-add-zipping-endpoints-in-storage
bisgaard-itis Feb 18, 2025
e19eea7
update openapi specs of webserver
bisgaard-itis Feb 18, 2025
311ba29
add user id to data export endpoint
bisgaard-itis Feb 18, 2025
d614e7e
fix typecheck
bisgaard-itis Feb 18, 2025
db55e79
fix openapi spec test
bisgaard-itis Feb 18, 2025
8bd254d
merge master into 7197-add-zipping-endpoints-in-storage
bisgaard-itis Feb 18, 2025
1718df8
@sanderegg fix absolute imports
bisgaard-itis Feb 18, 2025
7faf55f
@sanderegg @pcrespov remove 'rpc' from classnames
bisgaard-itis Feb 18, 2025
434602f
task_progress -> progress
bisgaard-itis Feb 18, 2025
fd777ab
rename storage schemas exposed via webserver
bisgaard-itis Feb 18, 2025
400a6c1
use ProgressReport
bisgaard-itis Feb 18, 2025
3383265
restructuring
bisgaard-itis Feb 18, 2025
b0f8a7f
services/webserver api version: 0.58.0 → 0.59.0
bisgaard-itis Feb 18, 2025
8acc41c
storage/_handlers.py -> storage/_rest.py
bisgaard-itis Feb 18, 2025
df04839
merge master into 7197-add-zipping-endpoints-in-storage
bisgaard-itis Feb 18, 2025
c3758bd
update opena api specs
bisgaard-itis Feb 18, 2025
ccff359
@pcrespov streamline to_rpc_schema methods
bisgaard-itis Feb 19, 2025
09a3650
merge master into 7197-add-zipping-endpoints-in-storage
bisgaard-itis Feb 19, 2025
b01e479
add rpc method for getting jobs associated with user
bisgaard-itis Feb 19, 2025
eec16d8
add webserver rest endpoint for getting user jobs
bisgaard-itis Feb 19, 2025
432dbb3
add test of rest endpoint for getting jobs associated with user
bisgaard-itis Feb 19, 2025
8e6162d
minor cleanup
bisgaard-itis Feb 19, 2025
4dfe2d0
merge master into 7197-add-zipping-endpoints-in-storage
bisgaard-itis Feb 19, 2025
f817a52
move thing around
bisgaard-itis Feb 19, 2025
6a19215
make pylint happy
bisgaard-itis Feb 19, 2025
8356158
update openapi specs
bisgaard-itis Feb 19, 2025
da0f6ea
fix webserver mocks
bisgaard-itis Feb 19, 2025
63bc45c
cleanup
bisgaard-itis Feb 19, 2025
8821e57
merge master into 7197-add-zipping-endpoints-in-storage
bisgaard-itis Feb 19, 2025
e5ff440
make pylint happy
bisgaard-itis Feb 19, 2025
f0848a4
export get async jobs method in webserver openapi specs
bisgaard-itis Feb 19, 2025
98da41b
Update api/specs/web-server/_storage.py
bisgaard-itis Feb 19, 2025
83a8941
Update api/specs/web-server/_storage.py
bisgaard-itis Feb 19, 2025
bc49fb0
Update api/specs/web-server/_storage.py
bisgaard-itis Feb 19, 2025
e1488a8
Update api/specs/web-server/_storage.py
bisgaard-itis Feb 19, 2025
247d64f
Update api/specs/web-server/_storage.py
bisgaard-itis Feb 19, 2025
61d0683
use AsyncJobId consistently @GitHK
bisgaard-itis Feb 19, 2025
6132f82
update openapi specs
bisgaard-itis Feb 19, 2025
e50c1aa
make list jobs endpoint generic
bisgaard-itis Feb 19, 2025
57e2576
propagate changes to webserver
bisgaard-itis Feb 19, 2025
25265cb
make pylint happy
bisgaard-itis Feb 19, 2025
dd3fdf9
make submit job endpoint generic @GitHK
bisgaard-itis Feb 20, 2025
fe8f33e
factor out RequestContext and forward product name to storage @matusd…
bisgaard-itis Feb 20, 2025
666ed11
merge master into 7197-add-zipping-endpoints-in-storage
bisgaard-itis Feb 20, 2025
38030ab
fix test in storage
bisgaard-itis Feb 20, 2025
2be7088
merge master into 7197-add-zipping-endpoints-in-storage
bisgaard-itis Feb 20, 2025
63ccfa2
Merge branch 'master' into 7197-add-zipping-endpoints-in-storage
bisgaard-itis Feb 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions api/specs/web-server/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@ install-dev install: _check_venv_active
.PHONY: all
all: _check_venv_active install
python openapi.py

.PHONY: openapi-specs
openapi-specs: all
60 changes: 57 additions & 3 deletions api/specs/web-server/_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@


from typing import TypeAlias
from uuid import UUID

from fastapi import APIRouter, Query, status
from models_library.generics import Envelope
from models_library.projects_nodes_io import LocationID
from models_library.storage_schemas import (
from models_library.api_schemas_storage.storage_schemas import (
FileLocation,
FileMetaDataGet,
FileUploadCompleteFutureResponse,
Expand All @@ -19,6 +18,15 @@
LinkType,
PresignedLink,
)
from models_library.api_schemas_webserver.storage import (
DataExportPost,
StorageAsyncJobGet,
StorageAsyncJobResult,
StorageAsyncJobStatus,
)
from models_library.generics import Envelope
from models_library.projects_nodes_io import LocationID
from models_library.users import UserID
from pydantic import AnyUrl, ByteSize
from simcore_service_webserver._meta import API_VTAG
from simcore_service_webserver.storage.schemas import DatasetMetaData, FileMetaData
Expand Down Expand Up @@ -167,3 +175,49 @@ async def is_completed_upload_file(
location_id: LocationID, file_id: StorageFileIDStr, future_id: str
):
"""Returns state of upload completion"""


# data export
@router.post(
"/storage/locations/{location_id}/export-data",
response_model=Envelope[StorageAsyncJobGet],
name="export_data",
description="Export data",
)
async def export_data(data_export: DataExportPost, location_id: LocationID):
"""Trigger data export. Returns async job id for getting status and results"""


@router.get(
"/storage/async-jobs/{job_id}/status",
response_model=Envelope[StorageAsyncJobStatus],
name="get_async_job_status",
)
async def get_async_job_status(storage_async_job_get: StorageAsyncJobGet, job_id: UUID):
"""Get async job status"""


@router.post(
"/storage/async-jobs/{job_id}:abort",
name="abort_async_job",
)
async def abort_async_job(storage_async_job_get: StorageAsyncJobGet, job_id: UUID):
"""aborts execution of an async job"""


@router.get(
"/storage/async-jobs/{job_id}/result",
response_model=Envelope[StorageAsyncJobResult],
name="get_async_job_result",
)
async def get_async_job_result(storage_async_job_get: StorageAsyncJobGet, job_id: UUID):
"""Get the result of the async job"""


@router.get(
"/storage/async-jobs",
response_model=Envelope[list[StorageAsyncJobGet]],
name="get_async_jobs",
)
async def get_async_jobs(user_id: UserID):
"""Retrunsa list of async jobs for the user"""
6 changes: 5 additions & 1 deletion packages/aws-library/src/aws_library/s3/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,13 @@
from boto3.s3.transfer import TransferConfig
from botocore import exceptions as botocore_exc
from botocore.client import Config
from models_library.api_schemas_storage.storage_schemas import (
ETag,
S3BucketName,
UploadedPart,
)
from models_library.basic_types import SHA256Str
from models_library.bytes_iters import BytesIter, DataSize
from models_library.storage_schemas import ETag, S3BucketName, UploadedPart
from pydantic import AnyUrl, ByteSize, TypeAdapter
from servicelib.bytes_iters import DEFAULT_READ_CHUNK_SIZE, BytesStreamer
from servicelib.logging_utils import log_catch, log_context
Expand Down
2 changes: 1 addition & 1 deletion packages/aws-library/src/aws_library/s3/_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
from dataclasses import dataclass
from typing import TypeAlias

from models_library.api_schemas_storage.storage_schemas import ETag
from models_library.basic_types import SHA256Str
from models_library.storage_schemas import ETag
from pydantic import AnyUrl, BaseModel, ByteSize
from types_aiobotocore_s3.type_defs import HeadObjectOutputTypeDef, ObjectTypeDef

Expand Down
5 changes: 4 additions & 1 deletion packages/aws-library/tests/test_s3_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@
)
from aws_library.s3._models import MultiPartUploadLinks
from faker import Faker
from models_library.api_schemas_storage.storage_schemas import (
S3BucketName,
UploadedPart,
)
from models_library.basic_types import SHA256Str
from models_library.storage_schemas import S3BucketName, UploadedPart
from moto.server import ThreadedMotoServer
from pydantic import AnyUrl, ByteSize, TypeAdapter
from pytest_benchmark.plugin import BenchmarkFixture
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@
from typing import Any, TypeAlias
from uuid import UUID

from pydantic import BaseModel, Field, PositiveFloat, model_validator
from models_library.users import UserID
from pydantic import BaseModel, model_validator
from typing_extensions import Self

TaskRpcId: TypeAlias = UUID
from ..progress_bar import ProgressReport

AsyncJobId: TypeAlias = UUID

class TaskRpcStatus(BaseModel):
task_id: TaskRpcId
task_progress: PositiveFloat = Field(..., ge=0.0, le=1.0)

class AsyncJobStatus(BaseModel):
job_id: AsyncJobId
progress: ProgressReport
done: bool
started: datetime
stopped: datetime | None
Expand All @@ -26,11 +29,22 @@ def _check_consistency(self) -> Self:
return self


class TaskRpcResult(BaseModel):
class AsyncJobResult(BaseModel):
result: Any | None
error: Any | None


class TaskRpcGet(BaseModel):
task_id: TaskRpcId
task_name: str
class AsyncJobGet(BaseModel):
job_id: AsyncJobId
job_name: str


class AsyncJobAbort(BaseModel):
result: bool
job_id: AsyncJobId


class AsyncJobAccessData(BaseModel):
"""Data for controlling access to an async job"""

user_id: UserID | None
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from common_library.errors_classes import OsparcErrorMixin


class BaseAsyncjobRpcError(OsparcErrorMixin, RuntimeError):
pass


class StatusError(BaseAsyncjobRpcError):
msg_template: str = "Could not get status of job {job_id}"


class ResultError(BaseAsyncjobRpcError):
msg_template: str = "Could not get results of job {job_id}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# pylint: disable=R6301
from pathlib import Path

from common_library.errors_classes import OsparcErrorMixin
from models_library.projects_nodes_io import LocationID
from models_library.users import UserID
from pydantic import BaseModel, Field


class DataExportTaskStartInput(BaseModel):
user_id: UserID
location_id: LocationID
paths: list[Path] = Field(..., min_length=1)


### Exceptions


class StorageRpcError(OsparcErrorMixin, RuntimeError):
pass


class InvalidFileIdentifierError(StorageRpcError):
msg_template: str = "Could not find the file {file_id}"


class AccessRightError(StorageRpcError):
msg_template: str = "User {user_id} does not have access to file {file_id}"


class DataExportError(StorageRpcError):
msg_template: str = "Could not complete data export job with id {job_id}"

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

from datetime import datetime
from enum import Enum

# /data-export
from typing import Annotated, Any, Literal, Self, TypeAlias
from uuid import UUID

Expand All @@ -26,10 +28,10 @@
)
from pydantic.networks import AnyUrl

from .basic_regex import DATCORE_DATASET_NAME_RE, S3_BUCKET_NAME_RE
from .basic_types import SHA256Str
from .generics import ListModel
from .projects_nodes_io import (
from ..basic_regex import DATCORE_DATASET_NAME_RE, S3_BUCKET_NAME_RE
from ..basic_types import SHA256Str
from ..generics import ListModel
from ..projects_nodes_io import (
LocationID,
LocationName,
NodeID,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from datetime import datetime
from pathlib import Path
from typing import Any

from ..api_schemas_rpc_async_jobs.async_jobs import (
AsyncJobGet,
AsyncJobId,
AsyncJobResult,
AsyncJobStatus,
)
from ..api_schemas_storage.data_export_async_jobs import DataExportTaskStartInput
from ..progress_bar import ProgressReport
from ..projects_nodes_io import LocationID
from ..users import UserID
from ._base import InputSchema, OutputSchema


class DataExportPost(InputSchema):
paths: list[Path]

def to_rpc_schema(
self, user_id: UserID, location_id: LocationID
) -> DataExportTaskStartInput:
return DataExportTaskStartInput(
paths=self.paths, user_id=user_id, location_id=location_id
)


class StorageAsyncJobGet(OutputSchema):
job_id: AsyncJobId

@classmethod
def from_rpc_schema(cls, async_job_rpc_get: AsyncJobGet) -> "StorageAsyncJobGet":
return StorageAsyncJobGet(job_id=async_job_rpc_get.job_id)


class StorageAsyncJobStatus(OutputSchema):
job_id: AsyncJobId
progress: ProgressReport
done: bool
started: datetime
stopped: datetime | None

@classmethod
def from_rpc_schema(
cls, async_job_rpc_status: AsyncJobStatus
) -> "StorageAsyncJobStatus":
return StorageAsyncJobStatus(
job_id=async_job_rpc_status.job_id,
progress=async_job_rpc_status.progress,
done=async_job_rpc_status.done,
started=async_job_rpc_status.started,
stopped=async_job_rpc_status.stopped,
)


class StorageAsyncJobResult(OutputSchema):
result: Any | None
error: Any | None

@classmethod
def from_rpc_schema(
cls, async_job_rpc_result: AsyncJobResult
) -> "StorageAsyncJobResult":
return StorageAsyncJobResult(
result=async_job_rpc_result.result, error=async_job_rpc_result.error
)
6 changes: 5 additions & 1 deletion packages/pytest-simcore/src/pytest_simcore/helpers/s3.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@
import orjson
from aws_library.s3 import MultiPartUploadLinks
from fastapi import status
from models_library.storage_schemas import ETag, FileUploadSchema, UploadedPart
from models_library.api_schemas_storage.storage_schemas import (
ETag,
FileUploadSchema,
UploadedPart,
)
from pydantic import AnyUrl, ByteSize, TypeAdapter
from servicelib.utils import limited_as_completed, logged_gather
from types_aiobotocore_s3 import S3Client
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@
from aioresponses.core import CallbackResult
from faker import Faker
from models_library.api_schemas_directorv2.comp_tasks import ComputationGet
from models_library.generics import Envelope
from models_library.projects_pipeline import ComputationTask
from models_library.projects_state import RunningState
from models_library.storage_schemas import (
from models_library.api_schemas_storage.storage_schemas import (
FileMetaDataGet,
FileUploadCompleteFutureResponse,
FileUploadCompleteResponse,
Expand All @@ -25,6 +22,9 @@
LinkType,
PresignedLink,
)
from models_library.generics import Envelope
from models_library.projects_pipeline import ComputationTask
from models_library.projects_state import RunningState
from models_library.utils.fastapi_encoders import jsonable_encoder
from pydantic import AnyUrl, ByteSize, TypeAdapter
from servicelib.aiohttp import status
Expand Down
Loading
Loading