@@ -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,92 @@ 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+ if err := rootfsViewAccessor .Prepare (ctx , r .Bundle ); err != nil {
81+ log .G (ctx ).WithError (err ).Warn ("urunc(shim): failed to prepare rootfs view; falling back to legacy boot artifact extraction" )
82+ } else {
83+ log .G (ctx ).Debug ("urunc(shim): rootfs view prepared" )
84+ }
85+ } else {
86+ log .G (ctx ).WithField ("rootfs_type" , rootfsChoice .Type ).Debug ("urunc(shim): rootfs view prepare skipped" )
87+ }
88+ }
89+
6790 return resp , nil
6891}
6992
7093func (s * taskService ) Delete (ctx context.Context , r * taskAPI.DeleteRequest ) (* taskAPI.DeleteResponse , error ) {
71- return s .TaskService .Delete (ctx , r )
94+ shouldCleanup := false
95+ snapshotter := ""
96+ var loadErr error
97+
98+ if r .ExecID == "" {
99+ bundle , err := s .bundlePathFor (ctx , r .ID )
100+ if err != nil {
101+ log .G (ctx ).WithError (err ).Warn ("urunc(shim): resolve bundle path during Delete failed" )
102+ loadErr = err
103+ } else {
104+ // Read view state before inner Delete; snapshotter is taken from bundle
105+ // (written at Prepare) because container metadata may be gone after Delete.
106+ shouldCleanup , snapshotter , loadErr = containerdShim .ShouldCleanupRootfsView (bundle )
107+ }
108+ }
109+
110+ // Delete tears down the monitor namespace before removing the view it may pin.
111+ resp , err := s .TaskService .Delete (ctx , r )
112+
113+ if loadErr != nil {
114+ if err != nil {
115+ return resp , err
116+ }
117+ return resp , loadErr
118+ }
119+
120+ if shouldCleanup {
121+ session , sessionErr := containerdShim .OpenSession (ctx , s .containerdAddress , r .ID )
122+ if sessionErr != nil {
123+ log .G (ctx ).WithError (sessionErr ).Warn ("urunc(shim): open containerd session for rootfs view cleanup failed" )
124+ if err == nil {
125+ err = sessionErr
126+ }
127+ } else {
128+ defer func () {
129+ if err := session .Close (); err != nil {
130+ log .G (ctx ).WithError (err ).Warn ("urunc(shim): failed to close containerd session after rootfs view cleanup" )
131+ }
132+ }()
133+ if cleanupErr := containerdShim .NewRootfsViewAccessor (session ).Cleanup (ctx , snapshotter ); cleanupErr != nil {
134+ log .G (ctx ).WithError (cleanupErr ).Warn ("urunc(shim): delete rootfs view during Delete failed" )
135+ if err == nil {
136+ err = cleanupErr
137+ }
138+ }
139+ }
140+ }
141+
142+ return resp , err
72143}
73144
74145func (s * taskService ) RegisterTTRPC (server * ttrpc.Server ) error {
75146 taskAPI .RegisterTaskService (server , s )
76147 return nil
77148}
149+
150+ func (s * taskService ) bundlePathFor (ctx context.Context , containerID string ) (string , error ) {
151+ if s .stateRoot == "" {
152+ return "" , fmt .Errorf ("task service state root is empty (shim cwd layout assumption violated)" )
153+ }
154+ ns , err := namespaces .NamespaceRequired (ctx )
155+ if err != nil {
156+ return "" , fmt .Errorf ("namespace required: %w" , err )
157+ }
158+ return filepath .Join (s .stateRoot , ns , containerID ), nil
159+ }
0 commit comments