github.com/jingruilea/kubeedge@v1.2.0-beta.0.0.20200410162146-4bb8902b3879/edge/pkg/edged/edged_volumes.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors. 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 http://www.apache.org/licenses/LICENSE-2.0 7 Unless required by applicable law or agreed to in writing, software 8 distributed under the License is distributed on an "AS IS" BASIS, 9 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 See the License for the specific language governing permissions and 11 limitations under the License. 12 13 @CHANGELOG 14 KubeEdge Authors: To create mini-kubelet for edge deployment scenario, 15 This file is derived from K8S Kubelet code with reduced set of methods 16 Changes done are 17 1. Most functions in this file is come from "k8s.io/kubernetes/pkg/kubelet/kubelet_volumes.go" 18 and made some variant. 19 */ 20 21 package edged 22 23 import ( 24 "fmt" 25 "strconv" 26 "strings" 27 28 api "k8s.io/api/core/v1" 29 "k8s.io/apimachinery/pkg/types" 30 utilerrors "k8s.io/apimachinery/pkg/util/errors" 31 "k8s.io/apimachinery/pkg/util/sets" 32 "k8s.io/klog" 33 "k8s.io/kubernetes/pkg/kubelet/container" 34 "k8s.io/kubernetes/pkg/util/removeall" 35 "k8s.io/kubernetes/pkg/volume" 36 volumetypes "k8s.io/kubernetes/pkg/volume/util/types" 37 utilio "k8s.io/utils/io" 38 "k8s.io/utils/mount" 39 ) 40 41 // newVolumeMounterFromPlugins attempts to find a plugin by volume spec, pod 42 // and volume options and then creates a Mounter. 43 // Returns a valid Unmounter or an error. 44 func (e *edged) newVolumeMounterFromPlugins(spec *volume.Spec, pod *api.Pod, opts volume.VolumeOptions) (volume.Mounter, error) { 45 plugin, err := e.volumePluginMgr.FindPluginBySpec(spec) 46 if err != nil { 47 return nil, fmt.Errorf("can't use volume plugins for %s: %v", spec.Name(), err) 48 } 49 50 physicalMounter, err := plugin.NewMounter(spec, pod, opts) 51 if err != nil { 52 return nil, fmt.Errorf("failed to instantiate mounter for volume: %s using plugin: %s with a root cause: %v", spec.Name(), plugin.GetPluginName(), err) 53 } 54 klog.Infof("Using volume plugin %q to mount %s", plugin.GetPluginName(), spec.Name()) 55 return physicalMounter, nil 56 } 57 58 // cleanupOrphanedPodDirs removes the volumes of pods that should not be 59 // running and that have no containers running. 60 func (e *edged) cleanupOrphanedPodDirs(pods []*api.Pod, containerRunningPods []*container.Pod) error { 61 62 allPods := sets.NewString() 63 for _, pod := range pods { 64 allPods.Insert(string(pod.UID)) 65 } 66 67 for _, pod := range containerRunningPods { 68 allPods.Insert(string(pod.ID)) 69 } 70 71 found, err := e.listPodsFromDisk() 72 if err != nil { 73 return err 74 } 75 orphanRemovalErrors := []error{} 76 orphanVolumeErrors := []error{} 77 78 for _, uid := range found { 79 if allPods.Has(string(uid)) { 80 continue 81 } 82 // If volumes have not been unmounted/detached, do not delete directory. 83 // Doing so may result in corruption of data. 84 if podVolumesExist := e.podVolumesExist(uid); podVolumesExist { 85 klog.Infof("Orphaned pod %q found, but volumes are not cleaned up", uid) 86 continue 87 } 88 // If there are still volume directories, do not delete directory 89 volumePaths, err := e.getPodVolumePathListFromDisk(uid) 90 if err != nil { 91 orphanVolumeErrors = append(orphanVolumeErrors, fmt.Errorf("Orphaned pod %q found, but error %v occurred during reading volume dir from disk", uid, err)) 92 continue 93 } 94 if len(volumePaths) > 0 { 95 orphanVolumeErrors = append(orphanVolumeErrors, fmt.Errorf("Orphaned pod %q found, but volume paths are still present on disk", uid)) 96 continue 97 } 98 99 // TODO: by paas group 100 // k8s has no cleanupMoutPoints, what the purpose of this method? 101 // can be contributed? 102 klog.Infof("Clearing up volume directories of orphaned pod %q.", uid) 103 if err := e.cleanupMountPoints(e.getPodVolumesDir(uid)); err != nil { 104 klog.Warningf("Failed to clearing up volume mount points of pod %q: %s.", uid, err) 105 } 106 // If there are any volume-subpaths, do not cleanup directories 107 volumeSubpathExists, err := e.podVolumeSubpathsDirExists(uid) 108 if err != nil { 109 orphanVolumeErrors = append(orphanVolumeErrors, fmt.Errorf("Orphaned pod %q found, but error %v occurred during reading of volume-subpaths dir from disk", uid, err)) 110 continue 111 } 112 if volumeSubpathExists { 113 orphanVolumeErrors = append(orphanVolumeErrors, fmt.Errorf("Orphaned pod %q found, but volume subpaths are still present on disk", uid)) 114 continue 115 } 116 117 klog.Infof("Orphaned pod %q found, removing", uid) 118 if err := removeall.RemoveAllOneFilesystem(e.mounter, e.getPodDir(uid)); err != nil { 119 klog.Errorf("Failed to remove orphaned pod %q dir; err: %v", uid, err) 120 orphanRemovalErrors = append(orphanRemovalErrors, err) 121 } 122 } 123 124 logSpew := func(errs []error) { 125 if len(errs) > 0 { 126 klog.Errorf("%v : There were a total of %v errors similar to this. Turn up verbosity to see them.", errs[0], len(errs)) 127 for _, err := range errs { 128 klog.Infof("Orphan pod: %v", err) 129 } 130 } 131 } 132 133 logSpew(orphanVolumeErrors) 134 logSpew(orphanRemovalErrors) 135 return utilerrors.NewAggregate(orphanRemovalErrors) 136 } 137 138 // cleanMountPoints traverses the volume directory to find out all mount points and umount them 139 func (e *edged) cleanupMountPoints(volumeDir string) error { 140 mounter := mount.New("") 141 mountPoints, err := listProcMounts(volumeDir) 142 if err != nil { 143 return err 144 } 145 errlist := []error{} 146 for _, mp := range mountPoints { 147 if err := mounter.Unmount(mp.Path); err != nil { 148 errlist = append(errlist, err) 149 } 150 } 151 if len(errlist) != 0 { 152 return utilerrors.NewAggregate(errlist) 153 } 154 return nil 155 } 156 157 // podVolumesExist checks with the volume manager and returns true any of the 158 // pods for the specified volume are mounted. 159 func (e *edged) podVolumesExist(podUID types.UID) bool { 160 if mountedVolumes := 161 e.volumeManager.GetMountedVolumesForPod( 162 volumetypes.UniquePodName(podUID)); len(mountedVolumes) > 0 { 163 return true 164 } 165 166 return false 167 } 168 169 // listProcMounts is come from k8s.io\kubernetes\pkg\util\mount.listProcMounts 170 func listProcMounts(mountFilePath string) ([]mount.MountPoint, error) { 171 listTryTime, expectedNumFieldsPerLine := 3, 6 172 content, err := utilio.ConsistentRead(mountFilePath, listTryTime) 173 if err != nil { 174 return nil, err 175 } 176 177 out := []mount.MountPoint{} 178 lines := strings.Split(string(content), "\n") 179 for _, line := range lines { 180 if line == "" { 181 // the last split() item is empty string following the last \n 182 continue 183 } 184 fields := strings.Fields(line) 185 if len(fields) != expectedNumFieldsPerLine { 186 return nil, fmt.Errorf("wrong number of fields (expected %d, got %d): %s", expectedNumFieldsPerLine, len(fields), line) 187 } 188 189 mp := mount.MountPoint{ 190 Device: fields[0], 191 Path: fields[1], 192 Type: fields[2], 193 Opts: strings.Split(fields[3], ","), 194 } 195 196 freq, err := strconv.Atoi(fields[4]) 197 if err != nil { 198 return nil, err 199 } 200 mp.Freq = freq 201 202 pass, err := strconv.Atoi(fields[5]) 203 if err != nil { 204 return nil, err 205 } 206 mp.Pass = pass 207 208 out = append(out, mp) 209 } 210 return out, nil 211 }