@@ -17,8 +17,11 @@ package containerdshim
1717import (
1818 "context"
1919 "errors"
20+ "fmt"
21+ "path/filepath"
2022
2123 taskAPI "github.com/containerd/containerd/api/runtime/task/v2"
24+ "github.com/containerd/containerd/namespaces"
2225 "github.com/containerd/log"
2326 "github.com/containerd/ttrpc"
2427 containerdShim "github.com/urunc-dev/urunc/pkg/containerd-shim/containerd"
@@ -31,6 +34,8 @@ type taskService struct {
3134 taskAPI.TaskService
3235
3336 containerdAddress string
37+ // Used on Delete, where cwd may no longer be the bundle.
38+ stateRoot string
3439}
3540
3641func (s * taskService ) Create (ctx context.Context , r * taskAPI.CreateTaskRequest ) (* taskAPI.CreateTaskResponse , error ) {
@@ -53,9 +58,8 @@ func (s *taskService) Create(ctx context.Context, r *taskAPI.CreateTaskRequest)
5358 return resp , err
5459 }
5560
56- // ChooseRootfs after inner task Create so bundle rootfs is mounted;
57- // params are persisted in bundle config.json for runtime Exec.
58- if err := chooseGuestRootfs (r ); err != nil {
61+ rootfsChoice , err := chooseGuestRootfs (r )
62+ if err != nil {
5963 if errors .Is (err , errGuestRootfsChoiceSkipped ) {
6064 log .G (ctx ).WithError (err ).Debug ("urunc(shim): guest rootfs choice skipped" )
6165 return resp , nil
@@ -64,14 +68,94 @@ func (s *taskService) Create(ctx context.Context, r *taskAPI.CreateTaskRequest)
6468 return nil , err
6569 }
6670
71+ log .G (ctx ).WithFields (map [string ]any {
72+ "rootfs_type" : rootfsChoice .Type ,
73+ "rootfs_path" : rootfsChoice .Path ,
74+ "mon_rootfs" : rootfsChoice .MonRootfs ,
75+ }).Debug ("urunc(shim): guest rootfs chosen" )
76+
77+ if session != nil {
78+ rootfsViewAccessor := containerdShim .NewRootfsViewAccessor (session )
79+ if rootfsViewAccessor .ShouldPrepare (rootfsChoice ) {
80+ log .G (ctx ).WithFields (map [string ]any {
81+ "rootfs_type" : rootfsChoice .Type ,
82+ "rootfs_path" : rootfsChoice .Path ,
83+ }).Debug ("urunc(shim): preparing rootfs view" )
84+ if err := rootfsViewAccessor .Prepare (ctx , r .Bundle ); err != nil {
85+ log .G (ctx ).WithError (err ).Warn ("urunc(shim): failed to prepare rootfs view; falling back to legacy boot artifact extraction" )
86+ } else {
87+ log .G (ctx ).Debug ("urunc(shim): rootfs view prepared" )
88+ }
89+ } else {
90+ log .G (ctx ).WithField ("rootfs_type" , rootfsChoice .Type ).Debug ("urunc(shim): rootfs view prepare skipped" )
91+ }
92+ }
93+
6794 return resp , nil
6895}
6996
7097func (s * taskService ) Delete (ctx context.Context , r * taskAPI.DeleteRequest ) (* taskAPI.DeleteResponse , error ) {
71- return s .TaskService .Delete (ctx , r )
98+ shouldCleanup := false
99+ snapshotter := ""
100+ var loadErr error
101+
102+ if r .ExecID == "" {
103+ bundle , err := s .bundlePathFor (ctx , r .ID )
104+ if err != nil {
105+ log .G (ctx ).WithError (err ).Warn ("urunc(shim): resolve bundle path during Delete failed" )
106+ loadErr = err
107+ } else {
108+ shouldCleanup , snapshotter , loadErr = containerdShim .ShouldCleanupRootfsView (bundle )
109+ }
110+ }
111+
112+ // Delete tears down the monitor namespace before removing the view it may pin.
113+ resp , err := s .TaskService .Delete (ctx , r )
114+
115+ if loadErr != nil {
116+ if err != nil {
117+ return resp , err
118+ }
119+ return resp , loadErr
120+ }
121+
122+ if shouldCleanup {
123+ session , sessionErr := containerdShim .OpenSession (ctx , s .containerdAddress , r .ID )
124+ if sessionErr != nil {
125+ log .G (ctx ).WithError (sessionErr ).Warn ("urunc(shim): open containerd session for rootfs view cleanup failed" )
126+ if err == nil {
127+ err = sessionErr
128+ }
129+ } else {
130+ defer func () {
131+ if err := session .Close (); err != nil {
132+ log .G (ctx ).WithError (err ).Warn ("urunc(shim): failed to close containerd session after rootfs view cleanup" )
133+ }
134+ }()
135+ if cleanupErr := containerdShim .NewRootfsViewAccessor (session ).Cleanup (ctx , snapshotter ); cleanupErr != nil {
136+ log .G (ctx ).WithError (cleanupErr ).Warn ("urunc(shim): delete rootfs view during Delete failed" )
137+ if err == nil {
138+ err = cleanupErr
139+ }
140+ }
141+ }
142+ }
143+
144+ return resp , err
72145}
73146
74147func (s * taskService ) RegisterTTRPC (server * ttrpc.Server ) error {
75148 taskAPI .RegisterTaskService (server , s )
76149 return nil
77150}
151+
152+ func (s * taskService ) bundlePathFor (ctx context.Context , containerID string ) (string , error ) {
153+ if s .stateRoot == "" {
154+ return "" , fmt .Errorf ("task service state root is empty (shim cwd layout assumption violated)" )
155+ }
156+ ns , err := namespaces .NamespaceRequired (ctx )
157+ if err != nil {
158+ return "" , fmt .Errorf ("namespace required: %w" , err )
159+ }
160+ return filepath .Join (s .stateRoot , ns , containerID ), nil
161+ }
0 commit comments