Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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 bases/renku_data_services/data_api/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ def register_all_handlers(app: Sanic, dm: DependencyManager) -> Sanic:
session_repo=dm.session_repo,
session_secret_repo=dm.project_session_secret_repo,
metrics=dm.metrics,
project_storage_k8s=dm.project_storage_k8s,
)
project_session_secrets = ProjectSessionSecretBP(
name="project_session_secrets",
Expand Down Expand Up @@ -229,6 +230,7 @@ def register_all_handlers(app: Sanic, dm: DependencyManager) -> Sanic:
internal_token_mint=dm.internal_token_mint,
resource_usage_service=dm.resource_usage_service,
resource_requests_repo=dm.resource_requests_repo,
authz=dm.authz,
)
platform_config = PlatformConfigBP(
name="platform_config",
Expand Down Expand Up @@ -278,6 +280,7 @@ def register_all_handlers(app: Sanic, dm: DependencyManager) -> Sanic:
data_service_base_url=dm.config.nb_config.data_service_url,
k8s_client=dm.k8s_client,
deposit_config=dm.config.deposit_config,
project_storage_k8s=dm.project_storage_k8s,
)
notifications = NotificationsBP(
name="notifications",
Expand Down
4 changes: 3 additions & 1 deletion bases/renku_data_services/data_api/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
)
from renku_data_services.app_config.logging import Config as LoggingConfig
from renku_data_services.authz.config import AuthzConfig
from renku_data_services.data_connectors.config import DepositConfig
from renku_data_services.data_connectors.config import DepositConfig, ProjectStorageConfig
from renku_data_services.db_config.config import DBConfig
from renku_data_services.notebooks.config import NotebooksConfig
from renku_data_services.secrets.config import PublicSecretsConfig
Expand Down Expand Up @@ -48,6 +48,7 @@ class Config:
version: str
alertmanager_webhook_role: str
deposit_config: DepositConfig
project_storage_config: ProjectStorageConfig

@classmethod
def from_env(cls, db: DBConfig | None = None) -> Self:
Expand Down Expand Up @@ -95,4 +96,5 @@ def from_env(cls, db: DBConfig | None = None) -> Self:
log_cfg=LoggingConfig.from_env(),
alertmanager_webhook_role=os.environ.get("ALERTMANAGER_WEBHOOK_ROLE", "alertmanager-webhook"),
deposit_config=DepositConfig.from_env(nb_config.sessions.renku_url),
project_storage_config=ProjectStorageConfig.from_env(),
)
5 changes: 5 additions & 0 deletions bases/renku_data_services/data_api/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
)
from renku_data_services.data_connectors.deposits.envidat import EnvidatClient
from renku_data_services.data_connectors.deposits.zenodo import ZenodoAPIClient
from renku_data_services.data_connectors.project_storage_k8s import ProjectStorageK8s
from renku_data_services.git.gitlab import DummyGitlabAPI, EmptyGitlabAPI, GitlabAPI
from renku_data_services.k8s.client_interfaces import K8sClient
from renku_data_services.k8s.clients import (
Expand Down Expand Up @@ -175,6 +176,7 @@ class DependencyManager:
secret_client: K8sSecretClient
internal_token_mint: RenkuSelfTokenMint
internal_scope_verifier: ScopeVerifier
project_storage_k8s: ProjectStorageK8s

spec: dict[str, Any] = field(init=False, repr=False, default_factory=dict)
app_name: str = "renku_data_services"
Expand Down Expand Up @@ -364,6 +366,7 @@ def from_env(cls) -> DependencyManager:
resource_requests_repo=resource_requests_repo,
member_repo=member_repo,
)
project_storage_k8s = ProjectStorageK8s(config.nb_config.k8s_v2_client)
reprovisioning_repo = ReprovisioningRepository(session_maker=config.db.async_session_maker)

git_repositories_repo = GitRepositoriesRepository(
Expand Down Expand Up @@ -420,6 +423,7 @@ def from_env(cls) -> DependencyManager:
project_repo=project_repo,
group_repo=group_repo,
search_updates_repo=search_updates_repo,
project_storage_config=config.project_storage_config,
)
data_connector_secret_repo = DataConnectorSecretRepository(
session_maker=config.db.async_session_maker,
Expand Down Expand Up @@ -513,4 +517,5 @@ def from_env(cls) -> DependencyManager:
secret_client=secret_client,
internal_token_mint=internal_token_mint,
internal_scope_verifier=internal_scope_verifier,
project_storage_k8s=project_storage_k8s,
)
108 changes: 108 additions & 0 deletions components/renku_data_services/base_models/bytesize.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
"""Byte size model with unit conversions."""

from __future__ import annotations

from dataclasses import dataclass


@dataclass(frozen=True, order=True)
class ByteSize:
"""Represents a size in bytes, with convenience conversions and formatting."""

value: int

# Binary (1024-based) unit thresholds
KIBI = 1024
MEBI = 1024**2
GIBI = 1024**3
TEBI = 1024**4

def __post_init__(self) -> None:
if self.value < 0:
raise ValueError(f"ByteSize cannot be negative: {self.value}")
if not isinstance(self.value, int):
raise TypeError(f"ByteSize value must be int, got {type(self.value).__name__}")

def to_bytes(self) -> int:
"""Return the size in bytes."""
return self.value

def to_kibi(self) -> float:
"""Return the size in kibibytes (KiB)."""
return self.value / self.KIBI

def to_mibi(self) -> float:
"""Return the size in mebibytes (MiB)."""
return self.value / self.MEBI

def to_gibi(self) -> float:
"""Return the size in gibibytes (GiB)."""
return self.value / self.GIBI

def to_tebi(self) -> float:
"""Return the size in tebibytes (TiB)."""
return self.value / self.TEBI

def to_human(self) -> str:
"""Return a human-readable string with the appropriate binary unit."""
if self.value < self.KIBI:
return f"{self.value}B"
elif self.value < self.MEBI:
return f"{self.to_kibi():.2f}KiB"
elif self.value < self.GIBI:
return f"{self.to_mibi():.2f}MiB"
elif self.value < self.TEBI:
return f"{self.to_gibi():.2f}GiB"
else:
return f"{self.to_tebi():.2f}TiB"

def __str__(self) -> str:
return self.to_human()

def __repr__(self) -> str:
return f"ByteSize({self.value}B)"

def __add__(self, other: ByteSize) -> ByteSize:
return ByteSize(self.value + other.value)

def __sub__(self, other: ByteSize) -> ByteSize:
result = self.value - other.value
if result < 0:
raise ValueError("Subtraction would result in negative ByteSize")
return ByteSize(result)

def __radd__(self, other: int) -> ByteSize:
# allows sum([ByteSize(1), ByteSize(2)]) to work, since sum() starts with 0
if other == 0:
return self
return NotImplemented

@classmethod
def from_bytes(cls, bs: int) -> ByteSize:
"""Create a ByteSize from a byte count."""
return ByteSize(value=bs)

@classmethod
def from_kibi(cls, kb: float) -> ByteSize:
"""Create a ByteSize from a kibibyte value."""
return ByteSize(value=int(kb * cls.KIBI))

@classmethod
def from_mibi(cls, mb: float) -> ByteSize:
"""Create a ByteSize from a mebibyte value."""
return ByteSize(value=int(mb * cls.MEBI))

@classmethod
def from_gibi(cls, gb: float) -> ByteSize:
"""Create a ByteSize from a gibibyte value."""
return ByteSize(value=int(gb * cls.GIBI))

@classmethod
def from_tebi(cls, tib: float) -> ByteSize:
"""Create a ByteSize from a tebibyte value."""
return cls(value=round(tib * cls.TEBI))

@classmethod
def zero(cls) -> ByteSize:
"""Create a byte size with value 0."""
return ByteSize(0)
6 changes: 6 additions & 0 deletions components/renku_data_services/base_models/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,12 @@ def from_strings(cls, *slugs: str) -> Self:
raise errors.ValidationError(message=f"Two slug strings are needed to create a project path, got {slugs}.")
return cls(NamespaceSlug(slugs[0]), ProjectSlug(slugs[1]))

@classmethod
def parse(cls, slug: str) -> Self:
"""Parses a single string into a ProjectPath."""
namespace_split = slug.split("/")
return cls.from_strings(*namespace_split)


@dataclass(frozen=True, eq=True, repr=False)
class DataConnectorPath(__NamespaceCommonMixin):
Expand Down
Loading
Loading