Skip to content

Commit 5545d0b

Browse files
committed
refactor filesystem.go and adapt tests to use a real file system
Signed-off-by: Tim Ramlot <[email protected]>
1 parent 4e16ea6 commit 5545d0b

File tree

2 files changed

+210
-93
lines changed

2 files changed

+210
-93
lines changed

storage/filesystem.go

Lines changed: 60 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ import (
3434
"github.com/cert-manager/csi-lib/third_party/util"
3535
)
3636

37+
// These variables can be overridden by tests, this makes it easier to test
38+
// the filesystem implementation as a non-root user.
39+
var (
40+
parentFolderMode fs.FileMode = 0700
41+
volumeFolderMode fs.FileMode = 0644
42+
volumeDataFolderMode fs.FileMode = 0550
43+
)
44+
3745
const (
3846
readWriteUserFileMode = 0600
3947
readOnlyUserAndGroupFileMode = 0440
@@ -42,12 +50,9 @@ const (
4250
type Filesystem struct {
4351
log logr.Logger
4452

45-
// baseDir is the absolute path to a directory used to store all metadata
53+
// basePath is the absolute path to a directory used to store all metadata
4654
// about mounted volumes and mount points.
47-
baseDir string
48-
49-
// used by the 'read only' methods
50-
fs fs.StatFS
55+
basePath string
5156

5257
// FixedFSGroup is an optional field which will set the gid ownership of all
5358
// volume's data directories to this value.
@@ -65,30 +70,44 @@ type Filesystem struct {
6570
// Ensure the Filesystem implementation is fully featured
6671
var _ Interface = &Filesystem{}
6772

68-
func NewFilesystem(log logr.Logger, baseDir string) (*Filesystem, error) {
69-
f := &Filesystem{
70-
log: log,
71-
baseDir: baseDir,
72-
// Use the rootfs as the DirFS so that paths passed to both read &
73-
// write methods on this struct use a consistent root.
74-
fs: os.DirFS("/").(fs.StatFS),
73+
func NewFilesystem(log logr.Logger, basePath string) (*Filesystem, error) {
74+
inmemfsPath := filepath.Join(basePath, "inmemfs")
75+
76+
f, err := NewFilesystemOnDisk(log, inmemfsPath)
77+
if err != nil {
78+
return nil, err
7579
}
7680

77-
isMnt, err := mount.New("").IsMountPoint(f.tempfsPath())
81+
isMnt, err := mount.New("").IsMountPoint(inmemfsPath)
7882
if err != nil {
79-
if !os.IsNotExist(err) {
80-
return nil, err
81-
}
82-
if err := os.MkdirAll(f.tempfsPath(), 0700); err != nil {
83-
return nil, err
84-
}
83+
return nil, err
8584
}
8685

8786
if !isMnt {
88-
if err := mount.New("").Mount("tmpfs", f.tempfsPath(), "tmpfs", []string{}); err != nil {
87+
if err := mount.New("").Mount("tmpfs", inmemfsPath, "tmpfs", []string{}); err != nil {
8988
return nil, fmt.Errorf("mounting tmpfs: %w", err)
9089
}
91-
log.Info("Mounted new tmpfs", "path", f.tempfsPath())
90+
log.Info("Mounted new tmpfs", "path", inmemfsPath)
91+
}
92+
93+
return f, nil
94+
}
95+
96+
// WARNING: should be used only for testing purposes only, as we don't want to store
97+
// any sensitive data on disk in production.
98+
func NewFilesystemOnDisk(log logr.Logger, basePath string) (*Filesystem, error) {
99+
if !filepath.IsAbs(basePath) {
100+
return nil, fmt.Errorf("baseDir must be an absolute path")
101+
}
102+
103+
f := &Filesystem{
104+
log: log,
105+
basePath: basePath,
106+
}
107+
108+
// Create the base directory if it does not exist.
109+
if err := os.MkdirAll(basePath, parentFolderMode); err != nil {
110+
return nil, err
92111
}
93112

94113
return f, nil
@@ -99,18 +118,18 @@ func (f *Filesystem) PathForVolume(volumeID string) string {
99118
}
100119

101120
func (f *Filesystem) RemoveVolume(volumeID string) error {
102-
return os.RemoveAll(filepath.Join(f.tempfsPath(), volumeID))
121+
return os.RemoveAll(f.volumePath(volumeID))
103122
}
104123

105124
func (f *Filesystem) ListVolumes() ([]string, error) {
106-
dirs, err := fs.ReadDir(f.fs, f.tempfsPath())
125+
dirs, err := os.ReadDir(f.basePath)
107126
if err != nil {
108127
return nil, fmt.Errorf("listing volumes: %w", err)
109128
}
110129

111130
var vols []string
112131
for _, dir := range dirs {
113-
_, err := f.fs.Stat(f.metadataPathForVolumeID(dir.Name()))
132+
_, err := os.Stat(f.metadataPathForVolumeID(dir.Name()))
114133
switch {
115134
case errors.Is(err, fs.ErrNotExist):
116135
f.log.Info("Directory exists but does not contain a metadata file - deleting directory and its contents", "volume_id", dir.Name())
@@ -133,7 +152,7 @@ func (f *Filesystem) ListVolumes() ([]string, error) {
133152
// Errors wrapping ErrNotFound will be returned if metadata for the ID cannot
134153
// be found.
135154
func (f *Filesystem) ReadMetadata(volumeID string) (metadata.Metadata, error) {
136-
file, err := f.fs.Open(f.metadataPathForVolumeID(volumeID))
155+
file, err := os.Open(f.metadataPathForVolumeID(volumeID))
137156
if err != nil {
138157
// don't leak through error types from fs.Open - wrap with ErrNotFound
139158
// if calling Open fails, as this indicates an invalid path
@@ -164,6 +183,11 @@ func (f *Filesystem) ReadMetadata(volumeID string) (metadata.Metadata, error) {
164183
}
165184

166185
func (f *Filesystem) WriteMetadata(volumeID string, meta metadata.Metadata) error {
186+
// Ensure the the volume directory exists.
187+
if err := f.ensureVolumeDirectory(volumeID); err != nil {
188+
return err
189+
}
190+
167191
metaBytes, err := json.Marshal(meta)
168192
if err != nil {
169193
// if it's an error type we don't recognise, wrap it with %v to prevent
@@ -177,11 +201,6 @@ func (f *Filesystem) WriteMetadata(volumeID string, meta metadata.Metadata) erro
177201
func (f *Filesystem) RegisterMetadata(meta metadata.Metadata) (bool, error) {
178202
existingMeta, err := f.ReadMetadata(meta.VolumeID)
179203
if errors.Is(err, ErrNotFound) {
180-
// Ensure directory structure for the volume exists
181-
if err := f.ensureVolumeDirectory(meta.VolumeID); err != nil {
182-
return false, err
183-
}
184-
185204
if err := f.WriteMetadata(meta.VolumeID, meta); err != nil {
186205
return false, err
187206
}
@@ -191,13 +210,6 @@ func (f *Filesystem) RegisterMetadata(meta metadata.Metadata) (bool, error) {
191210

192211
// If the volume context has changed, should write updated metadata
193212
if !apiequality.Semantic.DeepEqual(existingMeta.VolumeContext, meta.VolumeContext) {
194-
// Ensure directory structure for the volume exists - this will probably do
195-
// nothing, but it helps avoid any weird edge cases we could find ourselves in &
196-
// is an inexpensive operation.
197-
if err := f.ensureVolumeDirectory(meta.VolumeID); err != nil {
198-
return false, err
199-
}
200-
201213
f.log.WithValues("volume_id", meta.VolumeID).Info("volume context changed, updating file system metadata")
202214
existingMeta.VolumeContext = meta.VolumeContext
203215
if err := f.WriteMetadata(existingMeta.VolumeID, existingMeta); err != nil {
@@ -213,29 +225,14 @@ func (f *Filesystem) RegisterMetadata(meta metadata.Metadata) (bool, error) {
213225
// ensureVolumeDirectory ensures the directory structure for the volume exists.
214226
// If the directories already exist, it will do nothing.
215227
func (f *Filesystem) ensureVolumeDirectory(volumeID string) error {
216-
if err := os.MkdirAll(f.volumePath(volumeID), 0644); err != nil {
217-
return err
218-
}
219-
220-
// Data directory should be read and execute only to the fs user and group.
221-
if err := os.MkdirAll(f.dataPathForVolumeID(volumeID), 0550); err != nil {
222-
return err
223-
}
224-
225-
return nil
228+
return os.MkdirAll(f.volumePath(volumeID), volumeFolderMode)
226229
}
227230

228231
// WriteFiles writes the given data to filesystem files within the volume's
229232
// data directory. Filesystem supports changing ownership of the data directory
230233
// to a custom gid.
231234
func (f *Filesystem) WriteFiles(meta metadata.Metadata, files map[string][]byte) error {
232-
// Ensure the full directory structure for the volume exists.
233-
// This already happens in RegisterMetadata, however, when a driver starts up and reads
234-
// the metadata files from the existing tmpfs to re-populate the manager, RegisterMetadata
235-
// is not called again (it is only invoked by driver/nodeserver.go when a pod is first processed
236-
// during NodePublishVolume).
237-
// There is a very slim chance we could end out in a weird situation where the metadata
238-
// file exists but the data directory does not, so re-run ensureVolumeDirectory just to be safe.
235+
// Ensure the the volume directory exists.
239236
if err := f.ensureVolumeDirectory(meta.VolumeID); err != nil {
240237
return err
241238
}
@@ -245,9 +242,14 @@ func (f *Filesystem) WriteFiles(meta metadata.Metadata, files map[string][]byte)
245242
return err
246243
}
247244

245+
// Data directory should be read and execute only to the fs user and group.
246+
if err := os.MkdirAll(f.dataPathForVolumeID(meta.VolumeID), volumeDataFolderMode); err != nil {
247+
return err
248+
}
249+
248250
// If a fsGroup is defined, Chown the directory to that group.
249251
if fsGroup != nil {
250-
if err := os.Chown(f.dataPathForVolumeID(meta.VolumeID), -1, int(*fsGroup)); err != nil {
252+
if err := os.Lchown(f.dataPathForVolumeID(meta.VolumeID), -1, int(*fsGroup)); err != nil {
251253
return fmt.Errorf("failed to chown data dir to gid %v: %w", *fsGroup, err)
252254
}
253255
}
@@ -266,7 +268,7 @@ func (f *Filesystem) WriteFiles(meta metadata.Metadata, files map[string][]byte)
266268
// If a fsGroup is defined, Chown all files in the timestamped directory.
267269
for filename := range files {
268270
// Set the uid to -1 which means don't change ownership in Go.
269-
if err := os.Chown(filepath.Join(f.dataPathForVolumeID(meta.VolumeID), tsDirName, filename), -1, int(*fsGroup)); err != nil {
271+
if err := os.Lchown(filepath.Join(f.dataPathForVolumeID(meta.VolumeID), tsDirName, filename), -1, int(*fsGroup)); err != nil {
270272
return err
271273
}
272274
}
@@ -282,7 +284,7 @@ func (f *Filesystem) WriteFiles(meta metadata.Metadata, files map[string][]byte)
282284

283285
// ReadFile reads the named file within the volume's data directory.
284286
func (f *Filesystem) ReadFile(volumeID, name string) ([]byte, error) {
285-
file, err := f.fs.Open(filepath.Join(f.dataPathForVolumeID(volumeID), name))
287+
file, err := os.Open(filepath.Join(f.dataPathForVolumeID(volumeID), name))
286288
if err != nil {
287289
// don't leak through error types from fs.Open - wrap with ErrNotFound
288290
// if calling Open fails, as this indicates an invalid path
@@ -306,11 +308,7 @@ func (f *Filesystem) dataPathForVolumeID(id string) string {
306308
}
307309

308310
func (f *Filesystem) volumePath(id string) string {
309-
return filepath.Join(f.tempfsPath(), id)
310-
}
311-
312-
func (f *Filesystem) tempfsPath() string {
313-
return filepath.Join(f.baseDir, "inmemfs")
311+
return filepath.Join(f.basePath, id)
314312
}
315313

316314
func makePayload(in map[string][]byte) map[string]util.FileProjection {

0 commit comments

Comments
 (0)