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
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
AMALTHEA_SESSIONS_VERSION ?= 0.25.0
KNATIVE_SERVING_VERSION ?= knative-v1.22.0
COMMON_CODEGEN_PARAMS := \
--output-model-type pydantic_v2.BaseModel \
--use-double-quotes \
Expand Down Expand Up @@ -55,6 +56,7 @@ API_SPECS := \
components/renku_data_services/notifications/apispec.py \
components/renku_data_services/capacity_reservation/apispec.py \
components/renku_data_services/resource_usage/apispec.py \
components/renku_data_services/renku_apps/apispec.py \
components/renku_data_services/authn/api/apispec.py

schemas: ${API_SPECS} ## Generate pydantic classes from apispec yaml files
Expand Down Expand Up @@ -119,6 +121,10 @@ amalthea_schema: ## Updates generates pydantic classes from CRDs
shipwright_schema: ## Updates the Shipwright pydantic classes
curl https://raw.githubusercontent.com/shipwright-io/build/refs/tags/v0.15.2/deploy/crds/shipwright.io_buildruns.yaml | yq '.spec.versions[] | select(.name == "v1beta1") | .schema.openAPIV3Schema' | poetry run datamodel-codegen --output components/renku_data_services/session/cr_shipwright_buildrun.py --base-class renku_data_services.session.cr_base.BaseCRD ${CR_CODEGEN_PARAMS}

.PHONY: knative_serving_schema
knative_serving_schema: ## Updates the Knative Serving pydantic classes
curl https://raw.githubusercontent.com/knative/serving/refs/tags/${KNATIVE_SERVING_VERSION}/config/core/300-resources/service.yaml | yq '.spec.versions[] | select(.name == "v1") | .schema.openAPIV3Schema' | poetry run datamodel-codegen --output components/renku_data_services/renku_apps/cr_knative_service.py --base-class renku_data_services.renku_apps.cr_base.BaseCRD ${CR_CODEGEN_PARAMS}

.PHONY: oci_schema
oci_schema: ## Updates the OCI classes
poetry run datamodel-codegen --url "https://raw.githubusercontent.com/opencontainers/image-spec/26647a49f642c7d22a1cd3aa0a48e4650a542269/schema/config-schema.json" --output components/renku_data_services/notebooks/oci/image_config.py --class-name ImageConfig --base-class renku_data_services.notebooks.oci.base_model.BaseOciModel ${CR_CODEGEN_PARAMS}
Expand Down
13 changes: 13 additions & 0 deletions bases/renku_data_services/data_api/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
from renku_data_services.notifications.blueprints import NotificationsBP
from renku_data_services.platform.blueprints import PlatformConfigBP, PlatformUrlRedirectBP
from renku_data_services.project.blueprints import ProjectsBP, ProjectSessionSecretBP
from renku_data_services.renku_apps.blueprints import RenkuAppBP
from renku_data_services.repositories.blueprints import RepositoriesBP
from renku_data_services.resource_usage.blueprints import ResourceUsageBP
from renku_data_services.search.blueprints import SearchBP
Expand Down Expand Up @@ -177,6 +178,16 @@ def register_all_handlers(app: Sanic, dm: DependencyManager) -> Sanic:
authenticator=dm.authenticator,
metrics=dm.metrics,
)
renku_apps = (
RenkuAppBP(
name="renku_apps",
url_prefix=url_prefix,
apps_repo=dm.apps_repo,
authenticator=dm.authenticator,
)
if dm.config.apps.enabled and dm.apps_repo is not None
else None
)
builds = (
BuildsBP(
name="builds",
Expand Down Expand Up @@ -349,6 +360,8 @@ def register_all_handlers(app: Sanic, dm: DependencyManager) -> Sanic:
)
if builds is not None:
app.blueprint(builds.blueprint())
if renku_apps is not None:
app.blueprint(renku_apps.blueprint())

# We need to patch sanic_ext as since version 24.12 they only send a string representation of errors
import sanic_ext.extras.validation.setup
Expand Down
3 changes: 3 additions & 0 deletions bases/renku_data_services/data_api/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from renku_data_services.data_connectors.config import DepositConfig
from renku_data_services.db_config.config import DBConfig
from renku_data_services.notebooks.config import NotebooksConfig
from renku_data_services.renku_apps.config import AppsConfig
from renku_data_services.secrets.config import PublicSecretsConfig
from renku_data_services.session.config import BuildsConfig
from renku_data_services.solr.solr_client import SolrClientConfig
Expand All @@ -33,6 +34,7 @@ class Config:
k8s_config_root: str
db: DBConfig
builds: BuildsConfig
apps: AppsConfig
nb_config: NotebooksConfig
secrets: PublicSecretsConfig
sentry: SentryConfig
Expand Down Expand Up @@ -81,6 +83,7 @@ def from_env(cls, db: DBConfig | None = None) -> Self:
k8s_config_root=os.environ.get("K8S_CONFIGS_ROOT", "/secrets/kube_configs"),
db=db,
builds=BuildsConfig.from_env(),
apps=AppsConfig.from_env(),
nb_config=nb_config,
secrets=PublicSecretsConfig.from_env(),
sentry=SentryConfig.from_env(),
Expand Down
35 changes: 33 additions & 2 deletions bases/renku_data_services/data_api/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import renku_data_services.data_connectors
import renku_data_services.notifications
import renku_data_services.platform
import renku_data_services.renku_apps
import renku_data_services.repositories
import renku_data_services.search
import renku_data_services.storage
Expand Down Expand Up @@ -67,6 +68,8 @@
ProjectRepository,
ProjectSessionSecretRepository,
)
from renku_data_services.renku_apps.k8s_client import KNATIVE_SERVICE_GVK, RenkuAppsK8sClient
from renku_data_services.renku_apps.repository import RenkuAppsRepository
from renku_data_services.repositories.db import GitRepositoriesRepository
from renku_data_services.resource_usage.core import ResourceUsageService
from renku_data_services.resource_usage.db import ResourceRequestsRepo
Expand Down Expand Up @@ -145,6 +148,8 @@ class DependencyManager:
search_updates_repo: SearchUpdatesRepo
search_reprovisioning: SearchReprovision
session_repo: SessionRepository
apps_k8s_client: RenkuAppsK8sClient | None
apps_repo: RenkuAppsRepository | None
user_preferences_repo: UserPreferencesRepository
kc_user_repo: KcUserRepo
low_level_user_secrets_repo: LowLevelUserSecretsRepo
Expand Down Expand Up @@ -196,6 +201,7 @@ def load_apispec() -> dict[str, Any]:
renku_data_services.project.__file__,
renku_data_services.namespace.__file__,
renku_data_services.session.__file__,
renku_data_services.renku_apps.__file__,
renku_data_services.connected_services.__file__,
renku_data_services.repositories.__file__,
renku_data_services.notebooks.__file__,
Expand Down Expand Up @@ -257,7 +263,13 @@ def from_env(cls) -> DependencyManager:
default_kubeconfig=default_kubeconfig,
cluster_repo=cluster_repo,
cache=k8s_db_cache,
kinds_to_cache=[AMALTHEA_SESSION_GVK, JUPYTER_SESSION_GVK, BUILD_RUN_GVK, TASK_RUN_GVK],
kinds_to_cache=[
AMALTHEA_SESSION_GVK,
JUPYTER_SESSION_GVK,
BUILD_RUN_GVK,
TASK_RUN_GVK,
KNATIVE_SERVICE_GVK,
],
),
)
quota_repo = QuotaRepository(K8sResourceQuotaClient(client), K8sPriorityClassClient(client))
Expand Down Expand Up @@ -304,7 +316,13 @@ def from_env(cls) -> DependencyManager:
default_kubeconfig=default_kubeconfig,
cluster_repo=cluster_repo,
cache=k8s_db_cache,
kinds_to_cache=[AMALTHEA_SESSION_GVK, JUPYTER_SESSION_GVK, BUILD_RUN_GVK, TASK_RUN_GVK],
kinds_to_cache=[
AMALTHEA_SESSION_GVK,
JUPYTER_SESSION_GVK,
BUILD_RUN_GVK,
TASK_RUN_GVK,
KNATIVE_SERVICE_GVK,
],
),
),
namespace=config.k8s_namespace,
Expand Down Expand Up @@ -384,6 +402,17 @@ def from_env(cls) -> DependencyManager:
builds_config=config.builds,
git_repositories_repo=git_repositories_repo,
)
apps_k8s_client: RenkuAppsK8sClient | None = None
apps_repo: RenkuAppsRepository | None = None
if config.apps.enabled:
apps_k8s_client = RenkuAppsK8sClient(client=client, cluster_repo=cluster_repo)
apps_repo = RenkuAppsRepository(
authz=authz,
session_repo=session_repo,
rp_repo=rp_repo,
project_repo=project_repo,
k8s_client=apps_k8s_client,
)
project_migration_repo = ProjectMigrationRepository(
session_maker=config.db.async_session_maker,
authz=authz,
Expand Down Expand Up @@ -484,6 +513,8 @@ def from_env(cls) -> DependencyManager:
project_session_secret_repo=project_session_secret_repo,
group_repo=group_repo,
session_repo=session_repo,
apps_k8s_client=apps_k8s_client,
apps_repo=apps_repo,
user_preferences_repo=user_preferences_repo,
kc_user_repo=kc_user_repo,
user_secrets_repo=user_secrets_repo,
Expand Down
16 changes: 16 additions & 0 deletions bases/renku_data_services/k8s_cache/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,19 @@ def from_env(cls) -> _V1ServicesConfig:
return cls(enabled=enabled)


@dataclass
class _AppsConfig:
"""Configuration for Renku apps."""

enabled: bool

@classmethod
def from_env(cls) -> _AppsConfig:
"""Load values from environment variables."""
enabled = os.environ.get("APPS_ENABLED", "false").lower() == "true"
return cls(enabled=enabled)


@dataclass
class Config:
"""K8s cache config."""
Expand All @@ -74,6 +87,7 @@ class Config:
metrics: _MetricsConfig
image_builders: _ImageBuilderConfig
v1_services: _V1ServicesConfig
apps: _AppsConfig
sentry: SentryConfig

@classmethod
Expand All @@ -84,12 +98,14 @@ def from_env(cls) -> Config:
metrics = _MetricsConfig.from_env()
image_builders = _ImageBuilderConfig.from_env()
v1_services = _V1ServicesConfig.from_env()
apps = _AppsConfig.from_env()
sentry = SentryConfig.from_env()
return cls(
db=db,
k8s=k8s,
metrics=metrics,
image_builders=image_builders,
v1_services=v1_services,
apps=apps,
sentry=sentry,
)
3 changes: 3 additions & 0 deletions bases/renku_data_services/k8s_cache/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from renku_data_services.k8s.watcher import K8sWatcher, k8s_object_handler
from renku_data_services.k8s_cache.dependencies import DependencyManager
from renku_data_services.notebooks.constants import AMALTHEA_SESSION_GVK, JUPYTER_SESSION_GVK
from renku_data_services.renku_apps.k8s_client import KNATIVE_SERVICE_GVK
from renku_data_services.session.constants import BUILD_RUN_GVK, TASK_RUN_GVK

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -52,6 +53,8 @@ async def main() -> None:
kinds.append(JUPYTER_SESSION_GVK)
if dm.config.image_builders.enabled:
kinds.extend([BUILD_RUN_GVK, TASK_RUN_GVK])
if dm.config.apps.enabled:
kinds.append(KNATIVE_SERVICE_GVK)
logger.info(f"Resources: {kinds}")
watcher = K8sWatcher(
handler=k8s_object_handler(dm.k8s_cache(), dm.metrics(), rp_repo=dm.rp_repo()),
Expand Down
7 changes: 7 additions & 0 deletions components/renku_data_services/k8s/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,10 @@
Note: we can't curently propagate labels to TaskRuns through shipwright, so we just use a dummy user id for all of them.
This might change if shipwright SHIP-0034 gets implemented.
"""

DUMMY_RENKU_APP_USER_ID: Final[str] = "DummyRenkuAppUser"
"""The user id to use for Renku App Knative Services in the k8s cache.

Renku apps are public and shared across users, so they don't fit the per-user cache model. A fixed sentinel
ensures the cache row is shared across all readers instead of being written once per user.
"""
4 changes: 3 additions & 1 deletion components/renku_data_services/k8s/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from kubernetes.client import V1Secret

from renku_data_services.errors import ProgrammingError, errors
from renku_data_services.k8s.constants import DUMMY_TASK_RUN_USER_ID, ClusterId
from renku_data_services.k8s.constants import DUMMY_RENKU_APP_USER_ID, DUMMY_TASK_RUN_USER_ID, ClusterId

sanitizer = kubernetes.client.ApiClient().sanitize_for_serialization
K8sPatch = dict[str, Any]
Expand Down Expand Up @@ -426,6 +426,8 @@ def user_id(self) -> str | None:
return labels.get("renku.io/safe-username", None)
case "taskrun":
return DUMMY_TASK_RUN_USER_ID
case "service" if self.obj.version == "serving.knative.dev/v1":
return DUMMY_RENKU_APP_USER_ID
case _:
return None

Expand Down
1 change: 1 addition & 0 deletions components/renku_data_services/renku_apps/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Blueprints for Apps."""
Loading
Loading