77from dataclasses import dataclass
88from datetime import UTC , datetime
99from math import floor
10- from pathlib import Path
10+ from pathlib import PurePosixPath
1111from typing import Any
1212from urllib .parse import urljoin , urlparse
1313
5555 Authentication ,
5656 AuthenticationType ,
5757 Culling ,
58+ DataSource ,
5859 ExtraContainer ,
5960 ExtraVolume ,
6061 ExtraVolumeMount ,
6465 Resources ,
6566 SecretAsVolume ,
6667 SecretAsVolumeItem ,
67- SecretRef ,
68+ SecretRefKey ,
69+ SecretRefWhole ,
6870 Session ,
6971 SessionEnvItem ,
7072 Storage ,
8587from renku_data_services .project .db import ProjectRepository
8688from renku_data_services .repositories .db import GitRepositoriesRepository
8789from renku_data_services .session .db import SessionRepository
90+ from renku_data_services .storage .db import StorageV2Repository
8891
8992
9093@dataclass (kw_only = True )
@@ -414,7 +417,7 @@ async def launch_notebook_helper(
414417 if lfs_auto_fetch is not None :
415418 parsed_server_options .lfs_auto_fetch = lfs_auto_fetch
416419
417- image_work_dir = image_repo .image_workdir (parsed_image ) or Path ("/" )
420+ image_work_dir = image_repo .image_workdir (parsed_image ) or PurePosixPath ("/" )
418421 mount_path = image_work_dir / "work"
419422
420423 server_work_dir = mount_path / gl_project_path
@@ -429,7 +432,7 @@ async def launch_notebook_helper(
429432 cstorage .model_dump (),
430433 user = user ,
431434 project_id = gl_project_id ,
432- work_dir = server_work_dir . absolute () ,
435+ work_dir = server_work_dir ,
433436 config = nb_config ,
434437 internal_gitlab_user = internal_gitlab_user ,
435438 )
@@ -773,6 +776,7 @@ class NotebooksNewBP(CustomBlueprint):
773776 project_repo : ProjectRepository
774777 session_repo : SessionRepository
775778 rp_repo : ResourcePoolRepository
779+ storage_repo : StorageV2Repository
776780
777781 def start (self ) -> BlueprintFactoryResponse :
778782 """Start a session with the new operator."""
@@ -804,17 +808,49 @@ async def _handler(
804808 parsed_server_options = await self .nb_config .crc_validator .validate_class_storage (
805809 user , resource_class_id , body .disk_storage
806810 )
807- work_dir = Path ( "/home/jovyan/work" )
811+ work_dir = environment . working_directory
808812 user_secrets : K8sUserSecrets | None = None
809813 # if body.user_secrets:
810814 # user_secrets = K8sUserSecrets(
811815 # name=server_name,
812816 # user_secret_ids=body.user_secrets.user_secret_ids,
813817 # mount_path=body.user_secrets.mount_path,
814818 # )
815- cloud_storage : list [RCloneStorage ] = []
819+ cloud_storages_db = await self .storage_repo .get_storage (
820+ user = user , project_id = project .id , include_secrets = True
821+ )
822+ cloud_storage : dict [str , RCloneStorage ] = {
823+ str (s .storage_id ): RCloneStorage (
824+ source_path = s .source_path ,
825+ mount_folder = (work_dir / s .target_path ).as_posix (),
826+ configuration = s .configuration .model_dump (mode = "python" ),
827+ readonly = s .readonly ,
828+ config = self .nb_config ,
829+ name = s .name ,
830+ )
831+ for s in cloud_storages_db
832+ }
833+ cloud_storage_request : dict [str , RCloneStorage ] = {
834+ s .storage_id : RCloneStorage (
835+ source_path = s .source_path ,
836+ mount_folder = (work_dir / s .target_path ).as_posix (),
837+ configuration = s .configuration ,
838+ readonly = s .readonly ,
839+ config = self .nb_config ,
840+ name = None ,
841+ )
842+ for s in body .cloudstorage or []
843+ if s .storage_id is not None
844+ }
845+ # NOTE: Check the cloud storage in the request body and if any match
846+ # then overwrite the projects cloud storages
847+ # NOTE: Cloud storages in the session launch request body that are not form the DB are ignored
848+ for csr_id , csr in cloud_storage_request .items ():
849+ if csr_id in cloud_storage :
850+ cloud_storage [csr_id ] = csr
816851 # repositories = [Repository(i.url, branch=i.branch, commit_sha=i.commit_sha) for i in body.repositories]
817852 repositories = [Repository (url = i ) for i in project .repositories ]
853+ secrets_to_create : list [V1Secret ] = []
818854 server = Renku2UserServer (
819855 user = user ,
820856 image = image ,
@@ -824,7 +860,7 @@ async def _handler(
824860 server_options = parsed_server_options ,
825861 environment_variables = {},
826862 user_secrets = user_secrets ,
827- cloudstorage = cloud_storage ,
863+ cloudstorage = [ i for i in cloud_storage . values ()] ,
828864 k8s_client = self .nb_config .k8s_v2_client ,
829865 workspace_mount_path = work_dir ,
830866 work_dir = work_dir ,
@@ -834,6 +870,14 @@ async def _handler(
834870 is_image_private = False ,
835871 internal_gitlab_user = internal_gitlab_user ,
836872 )
873+ # Generate the cloud starge secrets
874+ data_sources : list [DataSource ] = []
875+ for ics , cs in enumerate (cloud_storage .values ()):
876+ secret_name = f"{ server_name } -ds-{ ics } "
877+ secrets_to_create .append (cs .secret (secret_name , server .k8s_client .preferred_namespace ))
878+ data_sources .append (
879+ DataSource (mountPath = cs .mount_folder , secretRef = SecretRefWhole (name = secret_name , adopt = True ))
880+ )
837881 cert_init , cert_vols = init_containers .certificates_container (self .nb_config )
838882 session_init_containers = [InitContainer .model_validate (self .nb_config .k8s_v2_client .sanitize (cert_init ))]
839883 extra_volumes = [ExtraVolume .model_validate (self .nb_config .k8s_v2_client .sanitize (i )) for i in cert_vols ]
@@ -867,7 +911,6 @@ async def _handler(
867911 metadata = Metadata (name = server_name , annotations = annotations ),
868912 spec = AmaltheaSessionSpec (
869913 codeRepositories = [],
870- dataSources = [],
871914 hibernated = False ,
872915 session = Session (
873916 image = image ,
@@ -914,13 +957,14 @@ async def _handler(
914957 type = AuthenticationType .oauth2proxy
915958 if isinstance (user , AuthenticatedAPIUser )
916959 else AuthenticationType .token ,
917- secretRef = SecretRef (name = server_name , key = "auth" , adopt = True ),
960+ secretRef = SecretRefKey (name = server_name , key = "auth" , adopt = True ),
918961 extraVolumeMounts = [
919962 ExtraVolumeMount (name = "renku-authorized-emails" , mountPath = "/authorized_emails" )
920963 ]
921964 if isinstance (user , AuthenticatedAPIUser )
922965 else [],
923966 ),
967+ dataSources = data_sources ,
924968 ),
925969 )
926970 parsed_proxy_url = urlparse (urljoin (server .server_url + "/" , "oauth2" ))
@@ -951,12 +995,14 @@ async def _handler(
951995 "verbose" : True ,
952996 }
953997 )
954- secret = V1Secret (metadata = V1ObjectMeta (name = server_name ), string_data = secret_data )
955- secret = await self .nb_config .k8s_v2_client .create_secret (secret )
998+ secrets_to_create .append (V1Secret (metadata = V1ObjectMeta (name = server_name ), string_data = secret_data ))
999+ for s in secrets_to_create :
1000+ await self .nb_config .k8s_v2_client .create_secret (s )
9561001 try :
9571002 manifest = await self .nb_config .k8s_v2_client .create_server (manifest , user .id )
9581003 except Exception :
959- await self .nb_config .k8s_v2_client .delete_secret (secret .metadata .name )
1004+ for s in secrets_to_create :
1005+ await self .nb_config .k8s_v2_client .delete_secret (s .metadata .name )
9601006 raise errors .ProgrammingError (message = "Could not start the amalthea session" )
9611007
9621008 return json (manifest .as_apispec ().model_dump (mode = "json" , exclude_none = True ), 201 )
0 commit comments