k8s.io/kubernetes@v1.29.3/pkg/volume/util/nested_volumes.go (about) 1 /* 2 Copyright 2018 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 util 18 19 import ( 20 "fmt" 21 "os" 22 "path/filepath" 23 "sort" 24 "strings" 25 26 v1 "k8s.io/api/core/v1" 27 podutil "k8s.io/kubernetes/pkg/api/v1/pod" 28 ) 29 30 // getNestedMountpoints returns a list of mountpoint directories that should be created 31 // for the volume indicated by name. 32 // note: the returned list is relative to baseDir 33 func getNestedMountpoints(name, baseDir string, pod v1.Pod) ([]string, error) { 34 var retval []string 35 checkContainer := func(container *v1.Container) error { 36 var allMountPoints []string // all mount points in this container 37 var myMountPoints []string // mount points that match name 38 for _, vol := range container.VolumeMounts { 39 cleaned := filepath.Clean(vol.MountPath) 40 allMountPoints = append(allMountPoints, cleaned) 41 if vol.Name == name { 42 myMountPoints = append(myMountPoints, cleaned) 43 } 44 } 45 sort.Strings(allMountPoints) 46 parentPrefix := ".." + string(os.PathSeparator) 47 // Examine each place where this volume is mounted 48 for _, myMountPoint := range myMountPoints { 49 if strings.HasPrefix(myMountPoint, parentPrefix) { 50 // Don't let a container trick us into creating directories outside of its rootfs 51 return fmt.Errorf("invalid container mount point %v", myMountPoint) 52 } 53 myMPSlash := myMountPoint + string(os.PathSeparator) 54 // The previously found nested mountpoints. 55 // NOTE: We can't simply rely on sort.Strings to have all the mountpoints sorted and 56 // grouped. For example, the following strings are sorted in this exact order: 57 // /dir/nested, /dir/nested-vol, /dir/nested.vol, /dir/nested/double, /dir/nested2 58 // The issue is a bit worse for Windows paths, since the \'s value is higher than /'s: 59 // \dir\nested, \dir\nested-vol, \dir\nested.vol, \dir\nested2, \dir\nested\double 60 // Because of this, we should use a list of previously mounted mountpoints, rather than only one. 61 prevNestedMPs := []string{} 62 // examine each mount point to see if it's nested beneath this volume 63 // (but skip any that are double-nested beneath this volume) 64 // For example, if this volume is mounted as /dir and other volumes are mounted 65 // as /dir/nested and /dir/nested/other, only create /dir/nested. 66 for _, mp := range allMountPoints { 67 if !strings.HasPrefix(mp, myMPSlash) { 68 continue // skip -- not nested beneath myMountPoint 69 } 70 71 isNested := false 72 for _, prevNestedMP := range prevNestedMPs { 73 if strings.HasPrefix(mp, prevNestedMP) { 74 isNested = true 75 break 76 } 77 } 78 if isNested { 79 continue // skip -- double nested beneath myMountPoint 80 } 81 // since this mount point is nested, remember it so that we can check that following ones aren't nested beneath this one 82 prevNestedMPs = append(prevNestedMPs, mp+string(os.PathSeparator)) 83 retval = append(retval, mp[len(myMPSlash):]) 84 } 85 } 86 return nil 87 } 88 89 var retErr error 90 podutil.VisitContainers(&pod.Spec, podutil.AllFeatureEnabledContainers(), func(c *v1.Container, containerType podutil.ContainerType) bool { 91 retErr = checkContainer(c) 92 return retErr == nil 93 }) 94 if retErr != nil { 95 return nil, retErr 96 } 97 98 return retval, nil 99 } 100 101 // MakeNestedMountpoints creates mount points in baseDir for volumes mounted beneath name 102 func MakeNestedMountpoints(name, baseDir string, pod v1.Pod) error { 103 dirs, err := getNestedMountpoints(name, baseDir, pod) 104 if err != nil { 105 return err 106 } 107 for _, dir := range dirs { 108 err := os.MkdirAll(filepath.Join(baseDir, dir), 0755) 109 if err != nil { 110 return fmt.Errorf("unable to create nested volume mountpoints: %v", err) 111 } 112 } 113 return nil 114 }