...

Source file src/k8s.io/kubernetes/pkg/volume/util/nested_volumes.go

Documentation: k8s.io/kubernetes/pkg/volume/util

     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  }
   115  

View as plain text