@@ -212,7 +212,7 @@ func NewService(
212212 return wms
213213}
214214
215- func (s * AteomHerder ) Run (ctx context.Context , req * ateletpb.RunRequest ) (* ateletpb.RunResponse , error ) {
215+ func (s * AteomHerder ) Run (ctx context.Context , req * ateletpb.RunRequest ) (resp * ateletpb.RunResponse , err error ) {
216216 if err := validateRunRequest (req ); err != nil {
217217 // status.Error so the interceptor surfaces InvalidArgument and the
218218 // message instead of masking both as Internal.
@@ -234,6 +234,16 @@ func (s *AteomHerder) Run(ctx context.Context, req *ateletpb.RunRequest) (*atele
234234 return nil , fmt .Errorf ("while resetting actor dirs: %w" , err )
235235 }
236236
237+ if err := s .mountExternalVolumes (ctx , atespace , actorID , req .GetSpec ().GetVolumes ()); err != nil {
238+ return nil , err
239+ }
240+ defer func () {
241+ if err != nil {
242+ // TODO cleanup orphaned volumes
243+ _ = s .unmountExternalVolumes (ctx , atespace , actorID , req .GetSpec ().GetVolumes ())
244+ }
245+ }()
246+
237247 // Record the sandbox binaries this actor is running so a later Checkpoint
238248 // (whose request no longer carries the sandbox config) can re-fetch the same
239249 // version and pin it into the snapshot manifest.
@@ -350,6 +360,7 @@ func (s *AteomHerder) Checkpoint(ctx context.Context, req *ateletpb.CheckpointRe
350360 // in the metadata if the error is not retriable.
351361 return nil , fmt .Errorf ("while calling ateom.CheckpointWorkload: %w" , err )
352362 }
363+
353364 sandboxRec .SnapshotFiles = resp .GetSnapshotFiles ()
354365 if len (sandboxRec .SnapshotFiles ) == 0 {
355366 return nil , ateerrors .NewGRPCError (ctx , codes .DataLoss , ateerrors .ReasonInvalidCheckpointResult , ateerrors .ActorCrashedMetadata (), errors .New ("ateom reported no snapshot files for checkpoint" ))
@@ -369,6 +380,9 @@ func (s *AteomHerder) Checkpoint(ctx context.Context, req *ateletpb.CheckpointRe
369380 return nil , fmt .Errorf ("unexpected checkpoint type: %v" , req .GetType ())
370381 }
371382
383+ // TODO cleanup orphaned volumes
384+ _ = s .unmountExternalVolumes (ctx , atespace , actorID , req .GetSpec ().GetVolumes ())
385+
372386 // Note: we do not crash the actor if resetting the directory fails.
373387 if err := resetActorDirs (atespace , actorID ); err != nil {
374388 return nil , fmt .Errorf ("while resetting actor dirs: %w" , err )
@@ -449,7 +463,7 @@ func (s *AteomHerder) uploadExternalCheckpoint(ctx context.Context, req *ateletp
449463 return nil
450464}
451465
452- func (s * AteomHerder ) Restore (ctx context.Context , req * ateletpb.RestoreRequest ) (* ateletpb.RestoreResponse , error ) {
466+ func (s * AteomHerder ) Restore (ctx context.Context , req * ateletpb.RestoreRequest ) (resp * ateletpb.RestoreResponse , err error ) {
453467 if err := validateRestoreRequest (req ); err != nil {
454468 return nil , status .Error (codes .InvalidArgument , err .Error ())
455469 }
@@ -462,6 +476,16 @@ func (s *AteomHerder) Restore(ctx context.Context, req *ateletpb.RestoreRequest)
462476 return nil , fmt .Errorf ("while resetting actor dirs: %w" , err )
463477 }
464478
479+ if err := s .mountExternalVolumes (ctx , atespace , actorID , req .GetSpec ().GetVolumes ()); err != nil {
480+ return nil , err
481+ }
482+ defer func () {
483+ if err != nil {
484+ // TODO cleanup orphaned mounts
485+ _ = s .unmountExternalVolumes (ctx , atespace , actorID , req .GetSpec ().GetVolumes ())
486+ }
487+ }()
488+
465489 checkpointDir := ateompath .RestoreStateDir (atespace , actorID )
466490
467491 // Per-step timing so we can attribute resume latency between the rustfs
@@ -657,12 +681,9 @@ func (s *AteomHerder) prepareOCIBundles(
657681 if err := writeFileAtomic (filepath .Join (identityDir , ActorIDFileName ), []byte (actorID ), 0o644 ); err != nil {
658682 return fmt .Errorf ("while writing actor identity file: %w" , err )
659683 }
660-
661- ddVolumes := make (map [string ]bool )
662684 // make directories for all durable-dir volumes
663685 for _ , vol := range spec .GetVolumes () {
664686 if vol .GetType () == ateletpb .VolumeType_VOLUME_TYPE_DURABLE_DIR {
665- ddVolumes [vol .GetName ()] = true
666687 volPath := ateompath .DurableDirVolumeMountPoint (atespace , actorID , vol .GetName ())
667688 if err := os .MkdirAll (volPath , 0o700 ); err != nil {
668689 return fmt .Errorf ("while creating %q: %w" , volPath , err )
@@ -700,6 +721,7 @@ func (s *AteomHerder) prepareOCIBundles(
700721 ateompath .AteomNetNSPath (targetAteomUid ),
701722 "" , // pause is sandbox infra; it gets no actor identity mount.
702723 nil ,
724+ nil ,
703725 ); err != nil {
704726 return wrapFileSystemErr ("while creating pause OCI bundle" , err )
705727 }
@@ -713,12 +735,6 @@ func (s *AteomHerder) prepareOCIBundles(
713735 for _ , env := range ctr .GetEnv () {
714736 envs = append (envs , fmt .Sprintf ("%s=%s" , env .GetName (), env .GetValue ()))
715737 }
716- var ddMounts []* ateletpb.VolumeMount
717- for _ , vm := range ctr .GetVolumeMounts () {
718- if ddVolumes [vm .GetName ()] {
719- ddMounts = append (ddMounts , vm )
720- }
721- }
722738 g .Go (func () error {
723739 if err := prepareOCIDirectory (
724740 gCtx ,
@@ -735,7 +751,8 @@ func (s *AteomHerder) prepareOCIBundles(
735751 },
736752 ateompath .AteomNetNSPath (targetAteomUid ),
737753 identityDir ,
738- ddMounts ,
754+ spec .GetVolumes (),
755+ ctr .GetVolumeMounts (),
739756 ); err != nil {
740757 return wrapFileSystemErr (fmt .Sprintf ("while creating %q OCI bundle" , ctr .GetName ()), err )
741758 }
@@ -1058,5 +1075,22 @@ func resetActorDirs(atespace, actorID string) error {
10581075 return wrapFileSystemErr ("while creating durable-dir volumes mount dir: %w" , err )
10591076 }
10601077
1078+ // Do not call RemoveAll on volume directories in case the unmount failed.
1079+ // We do not want to delete mount content.
1080+ volumesDir := ateompath .VolumesDir (atespace , actorID )
1081+ entries , err := os .ReadDir (volumesDir )
1082+ if err != nil && ! os .IsNotExist (err ) {
1083+ return wrapFileSystemErr ("while reading volumes dir: %w" , err )
1084+ }
1085+ for _ , entry := range entries {
1086+ volPath := filepath .Join (volumesDir , entry .Name ())
1087+ if err := os .Remove (volPath ); err != nil {
1088+ return wrapFileSystemErr ("while removing volume dir: %w" , err )
1089+ }
1090+ }
1091+ if err := os .MkdirAll (volumesDir , 0o755 ); err != nil {
1092+ return wrapFileSystemErr ("while creating volumes dir: %w" , err )
1093+ }
1094+
10611095 return nil
10621096}
0 commit comments