@@ -24,8 +24,10 @@ import (
2424 goexec "os/exec"
2525 "os/signal"
2626 "path"
27+ "sync/atomic"
2728 "syscall"
2829
30+ "github.com/cvmfs-contrib/cvmfs-csi/internal/cvmfs/env"
2931 "github.com/cvmfs-contrib/cvmfs-csi/internal/exec"
3032 "github.com/cvmfs-contrib/cvmfs-csi/internal/log"
3133)
@@ -245,6 +247,19 @@ func RunBlocking() error {
245247
246248 if log .LevelEnabled (log .LevelDebug ) {
247249 args = append (args , "--verbose" )
250+
251+ // Log info about autofs mount in /cvmfs.
252+
253+ isAutofs , err := IsAutofs ("/cvmfs" )
254+ if err != nil {
255+ log .Fatalf ("Failed to stat /cvmfs: %v" , err )
256+ }
257+
258+ if isAutofs {
259+ log .Debugf ("autofs already mounted in /cvmfs, automount daemon will reconnect..." )
260+ } else {
261+ log .Debugf ("autofs not mounted in /cvmfs, automount daemon will mount it now..." )
262+ }
248263 }
249264
250265 if log .LevelEnabled (log .LevelTrace ) {
@@ -276,20 +291,62 @@ func RunBlocking() error {
276291
277292 // Catch SIGTERM and SIGKILL and forward it to the automount process.
278293
279- sigCh := make (chan os.Signal , 1 )
294+ autofsTryCleanAtExit := env .GetAutofsTryCleanAtExit ()
295+
296+ sigCh := make (chan os.Signal , 2 )
280297 defer close (sigCh )
281298
299+ var exitedWithSigTerm atomic.Bool
300+
282301 go func () {
283302 for {
284- if sig , more := <- sigCh ; more {
285- cmd .Process .Signal (sig )
286- } else {
303+ sig , more := <- sigCh
304+ if ! more {
287305 break
288306 }
307+
308+ if ! autofsTryCleanAtExit && sig == syscall .SIGTERM {
309+ // automount daemon unmounts the autofs root in /cvmfs upon
310+ // receiving SIGTERM. This makes it impossible to reconnect
311+ // the daemon to the mount later, so all consumer Pods will
312+ // loose their mounts CVMFS, without the possibility of restoring
313+ // them (unless these Pods are restarted too). The implication
314+ // is that the nodeplugin is just being restarted, and will be
315+ // needed again.
316+ //
317+ // SIGKILL is handled differently in automount, as this forces
318+ // the daemon to skip the cleanup at exit, leaving the autofs
319+ // mount behind and making it possible to reconnect to it later.
320+ // We make a use of this, and unless the admin doesn't explicitly
321+ // ask for cleanup with AUTOFS_TRY_CLEAN_AT_EXIT env var, no cleanup
322+ // is done.
323+ //
324+ // Also, we intentionally don't unmount the existing autofs-managed
325+ // mounts inside /cvmfs, so that any existing consumers receive ENOTCONN
326+ // (due to broken FUSE mounts), so that accidental `mkdir -p` won't
327+ // succeed. They are cleaned by the daemon on startup.
328+ //
329+ // TODO: remove this once the automount daemon supports skipping
330+ // cleanup (via a command line flag).
331+
332+ log .Debugf ("Sending SIGKILL to automount daemon" )
333+
334+ exitedWithSigTerm .Store (true )
335+ cmd .Process .Signal (syscall .SIGKILL )
336+ break
337+ }
338+
339+ cmd .Process .Signal (sig )
289340 }
290341 }()
291342
292- signal .Notify (sigCh , syscall .SIGTERM , syscall .SIGKILL )
343+ shutdownSignals := []os.Signal {
344+ syscall .SIGINT ,
345+ syscall .SIGTERM ,
346+ syscall .SIGKILL ,
347+ }
348+
349+ signal .Notify (sigCh , shutdownSignals ... )
293350
294351 // Start automount daemon.
295352
@@ -303,7 +360,7 @@ func RunBlocking() error {
303360
304361 cmd .Wait ()
305362
306- if cmd .ProcessState .ExitCode () != 0 {
363+ if ! exitedWithSigTerm . Load () && cmd .ProcessState .ExitCode () != 0 {
307364 log .Fatalf (fmt .Sprintf ("automount[%d] has exited unexpectedly: %s" , cmd .Process .Pid , cmd .ProcessState ))
308365 }
309366
0 commit comments