k8s.io/kubernetes@v1.29.3/pkg/kubelet/util/store/filestore.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package store 18 19 import ( 20 "fmt" 21 "os" 22 "path/filepath" 23 "strings" 24 25 utilfs "k8s.io/kubernetes/pkg/util/filesystem" 26 ) 27 28 const ( 29 // Name prefix for the temporary files. 30 tmpPrefix = "." 31 ) 32 33 // FileStore is an implementation of the Store interface which stores data in files. 34 type FileStore struct { 35 // Absolute path to the base directory for storing data files. 36 directoryPath string 37 38 // filesystem to use. 39 filesystem utilfs.Filesystem 40 } 41 42 // NewFileStore returns an instance of FileStore. 43 func NewFileStore(path string, fs utilfs.Filesystem) (Store, error) { 44 if err := fs.MkdirAll(path, 0755); err != nil { 45 return nil, err 46 } 47 return &FileStore{directoryPath: path, filesystem: fs}, nil 48 } 49 50 // Write writes the given data to a file named key. 51 func (f *FileStore) Write(key string, data []byte) error { 52 if err := ValidateKey(key); err != nil { 53 return err 54 } 55 if err := f.filesystem.MkdirAll(f.directoryPath, 0755); err != nil { 56 return err 57 } 58 59 return writeFile(f.filesystem, f.getPathByKey(key), data) 60 } 61 62 // Read reads the data from the file named key. 63 func (f *FileStore) Read(key string) ([]byte, error) { 64 if err := ValidateKey(key); err != nil { 65 return nil, err 66 } 67 bytes, err := f.filesystem.ReadFile(f.getPathByKey(key)) 68 if os.IsNotExist(err) { 69 return bytes, ErrKeyNotFound 70 } 71 return bytes, err 72 } 73 74 // Delete deletes the key file. 75 func (f *FileStore) Delete(key string) error { 76 if err := ValidateKey(key); err != nil { 77 return err 78 } 79 return removePath(f.filesystem, f.getPathByKey(key)) 80 } 81 82 // List returns all keys in the store. 83 func (f *FileStore) List() ([]string, error) { 84 keys := make([]string, 0) 85 files, err := f.filesystem.ReadDir(f.directoryPath) 86 if err != nil { 87 return keys, err 88 } 89 for _, f := range files { 90 if !strings.HasPrefix(f.Name(), tmpPrefix) { 91 keys = append(keys, f.Name()) 92 } 93 } 94 return keys, nil 95 } 96 97 // getPathByKey returns the full path of the file for the key. 98 func (f *FileStore) getPathByKey(key string) string { 99 return filepath.Join(f.directoryPath, key) 100 } 101 102 // writeFile writes data to path in a single transaction. 103 func writeFile(fs utilfs.Filesystem, path string, data []byte) (retErr error) { 104 // Create a temporary file in the base directory of `path` with a prefix. 105 tmpFile, err := fs.TempFile(filepath.Dir(path), tmpPrefix) 106 if err != nil { 107 return err 108 } 109 110 tmpPath := tmpFile.Name() 111 shouldClose := true 112 113 defer func() { 114 // Close the file. 115 if shouldClose { 116 if err := tmpFile.Close(); err != nil { 117 if retErr == nil { 118 retErr = fmt.Errorf("close error: %v", err) 119 } else { 120 retErr = fmt.Errorf("failed to close temp file after error %v; close error: %v", retErr, err) 121 } 122 } 123 } 124 125 // Clean up the temp file on error. 126 if retErr != nil && tmpPath != "" { 127 if err := removePath(fs, tmpPath); err != nil { 128 retErr = fmt.Errorf("failed to remove the temporary file (%q) after error %v; remove error: %v", tmpPath, retErr, err) 129 } 130 } 131 }() 132 133 // Write data. 134 if _, err := tmpFile.Write(data); err != nil { 135 return err 136 } 137 138 // Sync file. 139 if err := tmpFile.Sync(); err != nil { 140 return err 141 } 142 143 // Closing the file before renaming. 144 err = tmpFile.Close() 145 shouldClose = false 146 if err != nil { 147 return err 148 } 149 150 return fs.Rename(tmpPath, path) 151 } 152 153 func removePath(fs utilfs.Filesystem, path string) error { 154 if err := fs.Remove(path); err != nil && !os.IsNotExist(err) { 155 return err 156 } 157 return nil 158 }