github.com/fafucoder/cilium@v1.6.11/pkg/endpoint/directory.go (about) 1 // Copyright 2018-2020 Authors of Cilium 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package endpoint 16 17 import ( 18 "fmt" 19 "os" 20 "path/filepath" 21 22 "github.com/cilium/cilium/common" 23 "github.com/cilium/cilium/pkg/logging/logfields" 24 "github.com/cilium/cilium/pkg/option" 25 26 "github.com/sirupsen/logrus" 27 ) 28 29 const ( 30 nextDirectorySuffix = "_next" 31 nextFailedDirectorySuffix = "_next_fail" 32 backupDirectorySuffix = "_stale" 33 ) 34 35 // DirectoryPath returns the directory name for this endpoint bpf program. 36 func (e *Endpoint) DirectoryPath() string { 37 return filepath.Join(".", fmt.Sprintf("%d", e.ID)) 38 } 39 40 // FailedDirectoryPath returns the directory name for this endpoint bpf program 41 // failed builds. 42 func (e *Endpoint) FailedDirectoryPath() string { 43 return filepath.Join(".", fmt.Sprintf("%d%s", e.ID, nextFailedDirectorySuffix)) 44 } 45 46 // StateDirectoryPath returns the directory name for this endpoint bpf program. 47 func (e *Endpoint) StateDirectoryPath() string { 48 return filepath.Join(option.Config.StateDir, e.StringID()) 49 } 50 51 // NextDirectoryPath returns the directory name for this endpoint bpf program 52 // next bpf builds. 53 func (e *Endpoint) NextDirectoryPath() string { 54 return filepath.Join(".", fmt.Sprintf("%d%s", e.ID, nextDirectorySuffix)) 55 } 56 57 func (e *Endpoint) backupDirectoryPath() string { 58 return e.DirectoryPath() + backupDirectorySuffix 59 } 60 61 // synchronizeDirectories moves the files related to endpoint BPF program 62 // compilation to their according directories if compilation of BPF was 63 // necessary for the endpoint. 64 // Returns the original regenerationError if regenerationError was non-nil, 65 // or if any updates to directories for the endpoint's directories fails. 66 // Must be called with endpoint.Mutex held. 67 func (e *Endpoint) synchronizeDirectories(origDir string, stateDirComplete bool) error { 68 scopedLog := e.getLogger() 69 scopedLog.Debug("synchronizing directories") 70 71 tmpDir := e.NextDirectoryPath() 72 73 // Check if an existing endpoint directory exists, e.g. 74 // /var/run/cilium/state/1111 75 _, err := os.Stat(origDir) 76 switch { 77 78 // An endpoint directory already exists. We need to back it up before attempting 79 // to move the new directory in its place so we can attempt recovery. 80 case !os.IsNotExist(err): 81 scopedLog.Debug("endpoint directory exists; backing it up") 82 backupDir := e.backupDirectoryPath() 83 84 // Remove any eventual old backup directory. This may fail if 85 // the directory does not exist. The error is deliberately 86 // ignored. 87 e.removeDirectory(backupDir) 88 89 // Move the current endpoint directory to a backup location 90 scopedLog.WithFields(logrus.Fields{ 91 "originalDirectory": origDir, 92 "backupDirectory": backupDir, 93 }).Debug("moving current directory to backup location") 94 if err := os.Rename(origDir, backupDir); err != nil { 95 return fmt.Errorf("unable to rename current endpoint directory: %s", err) 96 } 97 98 // Regarldess of whether the atomic replace succeeds or not, 99 // ensure that the backup directory is removed when the 100 // function returns. 101 defer e.removeDirectory(backupDir) 102 103 // Make temporary directory the new endpoint directory 104 if err := os.Rename(tmpDir, origDir); err != nil { 105 if err2 := os.Rename(backupDir, origDir); err2 != nil { 106 scopedLog.WithFields(logrus.Fields{ 107 logfields.Path: backupDir, 108 }).Warn("restoring directory for endpoint failed, endpoint " + 109 "is in inconsistent state. Keeping stale directory.") 110 return err2 111 } 112 113 return fmt.Errorf("restored original endpoint directory, atomic directory move failed: %s", err) 114 } 115 116 // If the compilation was skipped then we need to copy the old 117 // bpf objects into the new directory 118 if !stateDirComplete { 119 scopedLog.Debug("some BPF state files were not recreated; moving old BPF objects into new directory") 120 err := common.MoveNewFilesTo(backupDir, origDir) 121 if err != nil { 122 log.WithError(err).Debugf("unable to copy old bpf object "+ 123 "files from %s into the new directory %s.", backupDir, origDir) 124 } 125 } 126 127 // No existing endpoint directory, synchronizing the directory is a 128 // simple move 129 default: 130 // Make temporary directory the new endpoint directory 131 scopedLog.WithFields(logrus.Fields{ 132 "temporaryDirectory": tmpDir, 133 "originalDirectory": origDir, 134 }).Debug("attempting to make temporary directory new directory for endpoint programs") 135 if err := os.Rename(tmpDir, origDir); err != nil { 136 return fmt.Errorf("atomic endpoint directory move failed: %s", err) 137 } 138 } 139 140 // The build succeeded and is in place, any eventual existing failure 141 // directory can be removed. 142 e.removeDirectory(e.FailedDirectoryPath()) 143 144 return nil 145 } 146 147 func (e *Endpoint) removeDirectory(path string) error { 148 e.getLogger().WithField("directory", path).Debug("removing directory") 149 return os.RemoveAll(path) 150 } 151 152 func (e *Endpoint) removeDirectories() { 153 e.removeDirectory(e.DirectoryPath()) 154 e.removeDirectory(e.FailedDirectoryPath()) 155 e.removeDirectory(e.NextDirectoryPath()) 156 e.removeDirectory(e.backupDirectoryPath()) 157 }