@@ -23,6 +23,7 @@ import (
2323 "os"
2424 goexec "os/exec"
2525 "os/signal"
26+ "path"
2627 "syscall"
2728
2829 "github.com/cvmfs-contrib/cvmfs-csi/internal/exec"
@@ -32,6 +33,7 @@ import (
3233const (
3334 AutofsCvmfsRoot = "/cvmfs"
3435 AlienCachePath = "/cvmfs-aliencache"
36+ LocalCachePath = "/cvmfs-localcache"
3537)
3638
3739type Opts struct {
@@ -54,6 +56,100 @@ func cvmfsVersion() (string, error) {
5456 return string (bytes .TrimSpace (out )), nil
5557}
5658
59+ func removeDirContents (dirName string ) error {
60+ contents , err := os .ReadDir (dirName )
61+ if err != nil {
62+ // Ignore ENOENT.
63+ if os .IsNotExist (err ) {
64+ return nil
65+ }
66+
67+ return err
68+ }
69+
70+ for i := range contents {
71+ if err = os .RemoveAll (path .Join (dirName , contents [i ].Name ())); err != nil {
72+ return err
73+ }
74+ }
75+
76+ return nil
77+ }
78+
79+ func readEffectiveDefaultCvmfsConfig () (map [string ]string , error ) {
80+ out , err := exec .Output (goexec .Command (
81+ "cvmfs_config" ,
82+ "showconfig" ,
83+ // Show only non-empty config parameters.
84+ "-s" ,
85+ // Repository name. We use "x" as a dummy value,
86+ // as we don't care at this point, and need only
87+ // the default, not repository-specific values.
88+ "x" ,
89+ ))
90+
91+ if err != nil {
92+ execErr , ok := err .(* goexec.ExitError )
93+ if ! ok {
94+ return nil , err
95+ }
96+
97+ // The command normally exits with code 1, because
98+ // the repository "x" does not exist. The output is
99+ // still valid.
100+ if execErr .ExitCode () != 1 {
101+ return nil , err
102+ }
103+ }
104+
105+ var (
106+ buf = bytes .NewBuffer (out )
107+ sc = bufio .NewScanner (buf )
108+ config = make (map [string ]string )
109+ )
110+
111+ for sc .Scan () {
112+ // Each line is expected to be in the following format:
113+ //
114+ // <Key>=<Value>
115+ //
116+ // when there is no comment, or
117+ //
118+ // <Key>=<Value> # from <Source filepath>
119+ //
120+ // when there is a comment.
121+ line := sc .Bytes ()
122+
123+ // Find the equal sign '=' where the Key is separated from the Value.
124+
125+ eqTok := bytes .IndexByte (line , '=' )
126+ if eqTok == - 1 {
127+ log .Debugf ("Read unexpected CVMFS config parameter \" %s\" , missing '='" , line )
128+ continue
129+ }
130+
131+ // Cut the comment from the Value, if any.
132+
133+ valEndIdx := len (line )
134+ const commentPrefix = " #"
135+
136+ if commentTok := bytes .LastIndexByte (line , '#' ); commentTok != - 1 {
137+ if bytes .HasSuffix (line [:commentTok + 1 ], []byte (commentPrefix )) {
138+ valEndIdx = commentTok - len (commentPrefix ) + 1
139+ }
140+ }
141+
142+ // Add to the map.
143+
144+ key := string (line [:eqTok ])
145+ value := string (line [eqTok + 1 : valEndIdx ])
146+
147+ config [key ] = value
148+ }
149+
150+ return config , nil
151+ }
152+
57153func setupCvmfs (o * Opts ) error {
58154 if o .HasAlienCache {
59155 // Make sure the volume is writable by CVMFS processes.
@@ -62,7 +158,28 @@ func setupCvmfs(o *Opts) error {
62158 }
63159 }
64160
161+ // Clean up local cache. It may be dirty after previous nodeplugin Pod runs.
162+
163+ log .Debugf ("Cleaning up local cache directory %s..." , LocalCachePath )
164+
165+ cvmfsConfig , err := readEffectiveDefaultCvmfsConfig ()
166+ if err != nil {
167+ return fmt .Errorf ("failed to read CVMFS config: %v" , err )
168+ }
169+
170+ cacheDir := cvmfsConfig ["CVMFS_CACHE_BASE" ]
171+ if cacheDir == "" {
172+ cacheDir = LocalCachePath
173+ }
174+
175+ if err := removeDirContents (cacheDir ); err != nil {
176+ return fmt .Errorf ("failed to clean up local cache directory %s: %v" , cacheDir , err )
177+ }
178+
179+ log .Debugf ("Finished cleaning up local cache directory %s" , cacheDir )
180+
65181 // Set up configuration required for autofs with CVMFS to work properly.
182+
66183 if _ , err := exec .CombinedOutput (goexec .Command ("cvmfs_config" , "setup" , "nocfgmod" , "nostart" , "noautofs" )); err != nil {
67184 return fmt .Errorf ("failed to setup CVMFS config: %v" , err )
68185 }
0 commit comments