Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
b33d48e
upgraded rclone version
Jul 18, 2025
efa0435
using faster settings for rclone
Jul 18, 2025
7407dd7
Merge remote-tracking branch 'upstream/master' into pr-osparc-rclone-…
Aug 20, 2025
55c4340
removed unsued feature
Aug 21, 2025
12824e2
Merge remote-tracking branch 'upstream/master' into pr-osparc-rclone-…
Aug 21, 2025
9ff8d30
removed unused
Aug 21, 2025
720ee1b
moved config_file placement
Aug 22, 2025
e6b3828
Merge remote-tracking branch 'upstream/master' into pr-osparc-rclone-…
Aug 28, 2025
1b1cce4
Merge remote-tracking branch 'upstream/master' into pr-osparc-rclone-…
Aug 29, 2025
7d5c4b6
Merge remote-tracking branch 'upstream/master' into pr-osparc-rclone-…
Sep 1, 2025
7893b76
Merge remote-tracking branch 'upstream/master' into pr-osparc-rclone-…
Dec 8, 2025
36f9ebf
renamed
Dec 8, 2025
611e99a
working version
Dec 9, 2025
f3f9400
update upon changes and at regular intervals
Dec 9, 2025
66102a3
refactor
Dec 9, 2025
c11f078
rclone mount to simcore-sdk
Dec 10, 2025
d290037
moved away
Dec 10, 2025
0bca30e
refactored
Dec 10, 2025
52e32b2
refactor
Dec 10, 2025
fcec8a1
added migration
Dec 10, 2025
b844c13
added user_r_clone_mounting
Dec 10, 2025
3a986f0
added new interface
Dec 10, 2025
e2e5710
refactored
Dec 10, 2025
8fbbfe9
Merge remote-tracking branch 'upstream/master' into pr-osparc-rclone-…
Dec 10, 2025
106521a
adde some logging
Dec 10, 2025
fa5e997
refactor
Dec 10, 2025
091ac4f
required
Dec 12, 2025
c6871b3
added rlcone version in settings
Dec 12, 2025
3a70e9a
working version
Dec 12, 2025
a64f72a
added s3 entry to view contents
Dec 12, 2025
d63b13b
removed unused
Dec 12, 2025
5211629
added predicatable rclone mount names
Dec 12, 2025
9f30077
refacotred logic
Dec 12, 2025
1341290
does not require a special user
Dec 12, 2025
75a4c31
cleanup
Dec 12, 2025
f3b1183
refactor interface
Dec 12, 2025
1d10e02
extended settings
Dec 12, 2025
22d9f15
mount vfs cache volume
Dec 12, 2025
c6b7db2
renamed
Dec 12, 2025
7172274
fixed volume backup
Dec 12, 2025
97a9c80
rename logic
Dec 12, 2025
8240514
refactored handlers
Dec 12, 2025
8dcaa69
refactor
Dec 12, 2025
4f2d0d0
vfs cache volume added
Dec 12, 2025
08c7478
palce
Dec 12, 2025
9ab9a4a
reordered
Dec 12, 2025
9d06ae0
Merge remote-tracking branch 'upstream/master' into pr-osparc-rclone-…
Dec 12, 2025
ee1797f
renamed properly
Dec 15, 2025
80c4681
fixed wrong path
Dec 15, 2025
9fd8e06
added required paths
Dec 15, 2025
3d19f28
fixed broken mount point
Dec 15, 2025
d47e315
extracted docker utils
Dec 15, 2025
438bfb9
refactor
Dec 15, 2025
cace2f0
rename
Dec 15, 2025
917286e
add log level
Dec 15, 2025
7a1db83
refactor
Dec 15, 2025
53eda18
refactor
Dec 15, 2025
44e1058
restructured
Dec 15, 2025
30c5135
added shutdown upon error with rclone
Dec 16, 2025
b818c85
Merge remote-tracking branch 'upstream/master' into pr-osparc-rclone-…
Dec 16, 2025
1db6cd6
moved internls
Dec 16, 2025
3d43274
refactor
Dec 16, 2025
573a0f8
fixed migration
Dec 16, 2025
2fa41ae
refactor
Dec 16, 2025
84a177a
renamed
Dec 16, 2025
6f495be
refactor
Dec 16, 2025
84c981d
maybe acceptable settings
Dec 17, 2025
c48fa55
bumped rclone version
Dec 17, 2025
4cfcb45
refactor
Dec 17, 2025
331a091
rename
Dec 17, 2025
08b328d
fixed version
Dec 17, 2025
135cd7c
working settings
Dec 18, 2025
0985d7a
sensible settings and reverted settings layout
Dec 19, 2025
fd363da
removed unused
Dec 19, 2025
ef3e068
mount settings transferred via lables
Dec 19, 2025
52b9568
printable report
Dec 19, 2025
eca069b
refactor
Dec 19, 2025
49d82a0
added dependency
Dec 19, 2025
703245c
Merge remote-tracking branch 'upstream/master' into pr-osparc-rclone-…
Dec 19, 2025
392685c
updated tests
Dec 19, 2025
c307894
refactor
Dec 19, 2025
e1465d2
rename
Dec 19, 2025
b330de6
no negative numbers
Dec 19, 2025
fe7744d
refactor
Dec 19, 2025
e3090f2
Merge remote-tracking branch 'upstream/master' into pr-osparc-rclone-…
Dec 19, 2025
90ff87e
removed unused
Dec 19, 2025
64244e4
refactor
Dec 19, 2025
899e17b
added base mount test
Dec 19, 2025
6d38fbd
base working test
Dec 19, 2025
daf5a8a
current tests
Dec 19, 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
1 change: 1 addition & 0 deletions .env-devel
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ RESOURCE_USAGE_TRACKER_TRACING={}
R_CLONE_OPTION_BUFFER_SIZE=16M
R_CLONE_OPTION_RETRIES=3
R_CLONE_OPTION_TRANSFERS=5
R_CLONE_MOUNT_SETTINGS={}
R_CLONE_PROVIDER=MINIO

# simcore-user used in docker images
Expand Down
2 changes: 0 additions & 2 deletions .github/workflows/ci-testing-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1551,8 +1551,6 @@ jobs:
with:
python-version: ${{ matrix.python }}
cache-dependency-glob: "**/director-v2/requirements/ci.txt"
- name: setup rclone docker volume plugin
run: sudo ./ci/github/helpers/install_rclone_docker_volume_plugin.bash
- name: Download and load Docker images
uses: ./.github/actions/download-load-docker-images
with:
Expand Down
18 changes: 0 additions & 18 deletions ci/github/helpers/install_rclone_docker_volume_plugin.bash

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""added use_r_clone_mounting field

Revision ID: e4db35fe8054
Revises: ce69cc44246a
Create Date: 2025-12-16 11:43:36.941571+00:00

"""

import sqlalchemy as sa
from alembic import op

# revision identifiers, used by Alembic.
revision = "e4db35fe8054"
down_revision = "ce69cc44246a"
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column(
"groups_extra_properties",
sa.Column(
"use_r_clone_mounting",
sa.Boolean(),
server_default=sa.text("false"),
nullable=False,
),
)
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column("groups_extra_properties", "use_r_clone_mounting")
# ### end Alembic commands ###
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@
server_default=sa.sql.expression.false(),
doc="If true, will mount efs distributed file system when dynamic services starts",
),
sa.Column(
"use_r_clone_mounting",
sa.Boolean(),
nullable=False,
server_default=sa.sql.expression.false(),
doc="If true, will mount efs distributed file system when dynamic services starts",
),
sa.UniqueConstraint(
"group_id", "product_name", name="group_id_product_name_uniqueness"
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class GroupExtraProperties(FromRowMixin):
created: datetime.datetime
modified: datetime.datetime
enable_efs: bool
use_r_clone_mounting: bool


def _list_table_entries_ordered_by_group_type_stmt(user_id: int, product_name: str):
Expand Down
13 changes: 13 additions & 0 deletions packages/service-library/src/servicelib/r_clone_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager

from aiofiles import tempfile


@asynccontextmanager
async def config_file(config: str) -> AsyncIterator[str]:
async with tempfile.NamedTemporaryFile("w") as f:
await f.write(config)
await f.flush()
assert isinstance(f.name, str) # nosec
yield f.name
11 changes: 11 additions & 0 deletions packages/service-library/tests/tests_r_clone_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from pathlib import Path

from faker import Faker
from servicelib.r_clone_utils import config_file


async def test_config_file(faker: Faker) -> None:
text_to_write = faker.text()
async with config_file(text_to_write) as file_name:
assert text_to_write == Path(file_name).read_text()
assert Path(file_name).exists() is False
234 changes: 232 additions & 2 deletions packages/settings-library/src/settings_library/r_clone.py
Original file line number Diff line number Diff line change
@@ -1,38 +1,268 @@
from datetime import timedelta
from enum import StrEnum
from typing import Annotated
from pathlib import Path
from typing import Annotated, Final

from pydantic import Field, NonNegativeInt
from common_library.pydantic_validators import validate_numeric_string_as_timedelta
from pydantic import ByteSize, Field, NonNegativeInt, TypeAdapter

from .base import BaseCustomSettings
from .s3 import S3Settings

DEFAULT_VFS_CACHE_PATH: Final[Path] = Path("/vfs-cache")
DEFAULT_VFS_CACHE_MAX_SIZE: Final[str] = "500G"


_TRANSFER_COUNT: Final[NonNegativeInt] = 15
_TPSLIMIT: Final[NonNegativeInt] = 2000

_ONE_NANO_CPU: Final[NonNegativeInt] = int(1e9)


class S3Provider(StrEnum):
AWS = "AWS"
AWS_MOTO = "AWS_MOTO"
CEPH = "CEPH"
MINIO = "MINIO"


class RCloneMountSettings(BaseCustomSettings):
R_CLONE_MOUNT_TRANSFERS_COMPLETED_TIMEOUT: Annotated[
timedelta,
Field(
description="max amount of time to wait for rclone mount command to finish",
),
] = timedelta(minutes=60)

_validate_r_clone_mount_transfers_completed_timeout = (
validate_numeric_string_as_timedelta(
"R_CLONE_MOUNT_TRANSFERS_COMPLETED_TIMEOUT"
)
)

# CONTAINER
R_CLONE_MOUNT_CONTAINER_CONFIG_FILE_PATH: Annotated[
Path,
Field(
description="path inside the container where the rclone config file is located",
),
] = Path(
"/tmp/rclone.conf" # noqa: S108
)

R_CLONE_MOUNT_CONTAINER_SHOW_DEBUG_LOGS: Annotated[
bool,
Field(
description="whether to enable debug logs for the rclone mount command",
),
] = False

R_CLONE_MOUNT_CONTAINER_MEMORY_LIMIT: Annotated[
ByteSize, Field(description="memory limit for the rclone mount container")
] = TypeAdapter(ByteSize).validate_python("2GiB")

R_CLONE_MOUNT_CONTAINER_NANO_CPUS: Annotated[
NonNegativeInt, Field(description="CPU limit for the rclone mount container")
] = (1 * _ONE_NANO_CPU)

# CLI command `rclone mount`

R_CLONE_MOUNT_VFS_CACHE_PATH: Annotated[
Path,
Field(
description="`--cache-dir X`: sets the path to use for vfs cache",
),
] = DEFAULT_VFS_CACHE_PATH

R_CLONE_MOUNT_VFS_READ_AHEAD: Annotated[
str,
Field(
description="`--vfs-read-ahead X`: sets the read ahead buffer size",
),
] = "16M"

R_CLONE_MOUNT_VFS_CACHE_MAX_SIZE: Annotated[
str,
Field(
description="`--vfs-cache-max-size X`: sets the maximum size of the vfs cache",
),
] = DEFAULT_VFS_CACHE_MAX_SIZE

R_CLONE_MOUNT_VFS_CACHE_MIN_FREE_SPACE: Annotated[
str,
Field(
description="`--vfs-cache-min-free-space X`: sets the minimum free space to keep on disk",
),
] = "5G"

R_CLONE_MOUNT_CACHE_POLL_INTERVAL: Annotated[
str,
Field(
description="`--vfs-cache-poll-interval X`: sets the interval to poll the vfs cache",
),
] = "1m"

R_CLONE_MOUNT_VFS_WRITE_BACK: Annotated[
str,
Field(
description="`--vfs-write-back X`: sets the time to wait before writing back data to the remote",
),
] = "10s"

R_CLONE_MOUNT_DIR_CACHE_TIME: Annotated[
str,
Field(
description="`--dir-cache-time X`: time before directory is uploaded from remote if changed",
),
] = "10m"

R_CLONE_MOUNT_ATTR_TIMEOUT: Annotated[
str,
Field(
description="`--attr-timeout X`: sets the time to cache file attributes",
),
] = "1m"

R_CLONE_MOUNT_TPSLIMIT: Annotated[
NonNegativeInt,
Field(
description="`--tpslimit X`: sets the transactions per second limit",
),
] = _TPSLIMIT
R_CLONE_MOUNT_TPSLIMIT_BURST: Annotated[
NonNegativeInt,
Field(
description="`--tpslimit-burst X`: sets the burst limit for transactions per second",
),
] = (
_TPSLIMIT * 2
)

R_CLONE_MOUNT_MAX_BUFFER_MEMORY: Annotated[
str,
Field(
description="`--max-buffer-memory X`: sets the maximum buffer memory for rclone",
),
] = "16M"

R_CLONE_MOUNT_RETRIES: Annotated[
NonNegativeInt,
Field(
description="`--retries X`: sets the number of retries for rclone mount command",
),
] = 3

R_CLONE_MOUNT_RETRIES_SLEEP: Annotated[
str,
Field(
description="`--retries-sleep X`: sets the maximum sleep time between retries",
),
] = "30s"
R_CLONE_MOUNT_TRANSFERS: Annotated[
NonNegativeInt,
Field(
description="`--transfers X`: sets the number of parallel transfers for rclone mount command",
),
] = 15
R_CLONE_MOUNT_BUFFER_SIZE: Annotated[
str,
Field(
description="`--buffer-size X`: sets the buffer size for rclone mount command",
),
] = "16M"
R_CLONE_MOUNT_CHECKERS: Annotated[
NonNegativeInt,
Field(
description="`--checkers X`: sets the number of checkers for rclone mount command",
),
] = 8
R_CLONE_MOUNT_S3_UPLOAD_CONCURRENCY: Annotated[
NonNegativeInt,
Field(
description="`--s3-upload-concurrency X`: sets the number of concurrent uploads to S3",
),
] = 5
R_CLONE_MOUNT_S3_CHUNK_SIZE: Annotated[
str,
Field(
description="`--s3-chunk-size X`: sets the chunk size for S3",
),
] = "16M"
R_CLONE_MOUNT_ORDER_BY: Annotated[
str,
Field(
description="`--order-by X`: sets the order of file upload, e.g., 'size,mixed'",
),
] = "size,mixed"


class RCloneSettings(BaseCustomSettings):
R_CLONE_S3: Annotated[
S3Settings, Field(json_schema_extra={"auto_default_from_env": True})
]
R_CLONE_PROVIDER: S3Provider

R_CLONE_VERSION: Annotated[
str | None,
Field(
pattern=r"^\d+\.\d+\.\d+$",
description="version of rclone for the container image",
),
] = None

R_CLONE_MOUNT_SETTINGS: RCloneMountSettings = Field(
json_schema_extra={"auto_default_from_env": True}
)

R_CLONE_OPTION_TRANSFERS: Annotated[
# SEE https://rclone.org/docs/#transfers-n
NonNegativeInt,
Field(description="`--transfers X`: sets the amount of parallel transfers"),
] = 5

R_CLONE_OPTION_RETRIES: Annotated[
# SEE https://rclone.org/docs/#retries-int
NonNegativeInt,
Field(description="`--retries X`: times to retry each individual transfer"),
] = 3

R_CLONE_RETRIES_SLEEP: Annotated[
str,
Field(
description="`--retries-sleep X`: max time to sleep between retries (caps exponential backoff)"
),
] = "30s"

R_CLONE_OPTION_BUFFER_SIZE: Annotated[
# SEE https://rclone.org/docs/#buffer-size-size
str,
Field(
description="`--buffer-size X`: sets the amount of RAM to use for each individual transfer",
),
] = "16M"

R_CLONE_CHECKERS: Annotated[
NonNegativeInt,
Field(
description="`--checkers X`: sets the number checkers",
),
] = 8

R_CLONE_S3_UPLOAD_CONCURRENCY: Annotated[
NonNegativeInt,
Field(
description="`--s3-upload-concurrency X`: sets the number of concurrent uploads to S3",
),
] = 5

R_CLONE_CHUNK_SIZE: Annotated[
str,
Field(description="`--s3-chunk-size X`: sets the chunk size for S3"),
] = "16M"

R_CLONE_ORDER_BY: Annotated[
str,
Field(
description="`--order-by X`: sets the order of file upload, e.g., 'size,mixed'",
),
] = "size,mixed"
Loading
Loading