github.com/uriddle/docker@v0.0.0-20210926094723-4072e6aeb013/daemon/volumes_unix.go (about)

     1  // +build !windows
     2  
     3  package daemon
     4  
     5  import (
     6  	"os"
     7  	"sort"
     8  	"strconv"
     9  
    10  	"github.com/docker/docker/container"
    11  	"github.com/docker/docker/daemon/execdriver"
    12  	"github.com/docker/docker/volume"
    13  	volumedrivers "github.com/docker/docker/volume/drivers"
    14  	"github.com/docker/docker/volume/local"
    15  )
    16  
    17  // setupMounts iterates through each of the mount points for a container and
    18  // calls Setup() on each. It also looks to see if is a network mount such as
    19  // /etc/resolv.conf, and if it is not, appends it to the array of mounts.
    20  func (daemon *Daemon) setupMounts(container *container.Container) ([]execdriver.Mount, error) {
    21  	var mounts []execdriver.Mount
    22  	for _, m := range container.MountPoints {
    23  		if err := daemon.lazyInitializeVolume(container.ID, m); err != nil {
    24  			return nil, err
    25  		}
    26  		path, err := m.Setup()
    27  		if err != nil {
    28  			return nil, err
    29  		}
    30  		if !container.TrySetNetworkMount(m.Destination, path) {
    31  			mnt := execdriver.Mount{
    32  				Source:      path,
    33  				Destination: m.Destination,
    34  				Writable:    m.RW,
    35  				Propagation: m.Propagation,
    36  			}
    37  			if m.Volume != nil {
    38  				attributes := map[string]string{
    39  					"driver":      m.Volume.DriverName(),
    40  					"container":   container.ID,
    41  					"destination": m.Destination,
    42  					"read/write":  strconv.FormatBool(m.RW),
    43  					"propagation": m.Propagation,
    44  				}
    45  				daemon.LogVolumeEvent(m.Volume.Name(), "mount", attributes)
    46  			}
    47  			mounts = append(mounts, mnt)
    48  		}
    49  	}
    50  
    51  	mounts = sortMounts(mounts)
    52  	netMounts := container.NetworkMounts()
    53  	// if we are going to mount any of the network files from container
    54  	// metadata, the ownership must be set properly for potential container
    55  	// remapped root (user namespaces)
    56  	rootUID, rootGID := daemon.GetRemappedUIDGID()
    57  	for _, mount := range netMounts {
    58  		if err := os.Chown(mount.Source, rootUID, rootGID); err != nil {
    59  			return nil, err
    60  		}
    61  	}
    62  	return append(mounts, netMounts...), nil
    63  }
    64  
    65  // sortMounts sorts an array of mounts in lexicographic order. This ensure that
    66  // when mounting, the mounts don't shadow other mounts. For example, if mounting
    67  // /etc and /etc/resolv.conf, /etc/resolv.conf must not be mounted first.
    68  func sortMounts(m []execdriver.Mount) []execdriver.Mount {
    69  	sort.Sort(mounts(m))
    70  	return m
    71  }
    72  
    73  // migrateVolume links the contents of a volume created pre Docker 1.7
    74  // into the location expected by the local driver.
    75  // It creates a symlink from DOCKER_ROOT/vfs/dir/VOLUME_ID to DOCKER_ROOT/volumes/VOLUME_ID/_container_data.
    76  // It preserves the volume json configuration generated pre Docker 1.7 to be able to
    77  // downgrade from Docker 1.7 to Docker 1.6 without losing volume compatibility.
    78  func migrateVolume(id, vfs string) error {
    79  	l, err := volumedrivers.Lookup(volume.DefaultDriverName)
    80  	if err != nil {
    81  		return err
    82  	}
    83  
    84  	newDataPath := l.(*local.Root).DataPath(id)
    85  	fi, err := os.Stat(newDataPath)
    86  	if err != nil && !os.IsNotExist(err) {
    87  		return err
    88  	}
    89  
    90  	if fi != nil && fi.IsDir() {
    91  		return nil
    92  	}
    93  
    94  	return os.Symlink(vfs, newDataPath)
    95  }
    96  
    97  // validVolumeLayout checks whether the volume directory layout
    98  // is valid to work with Docker post 1.7 or not.
    99  func validVolumeLayout(files []os.FileInfo) bool {
   100  	if len(files) == 1 && files[0].Name() == local.VolumeDataPathName && files[0].IsDir() {
   101  		return true
   102  	}
   103  
   104  	if len(files) != 2 {
   105  		return false
   106  	}
   107  
   108  	for _, f := range files {
   109  		if f.Name() == "config.json" ||
   110  			(f.Name() == local.VolumeDataPathName && f.Mode()&os.ModeSymlink == os.ModeSymlink) {
   111  			// Old volume configuration, we ignore it
   112  			continue
   113  		}
   114  		return false
   115  	}
   116  
   117  	return true
   118  }
   119  
   120  // setBindModeIfNull is platform specific processing to ensure the
   121  // shared mode is set to 'z' if it is null. This is called in the case
   122  // of processing a named volume and not a typical bind.
   123  func setBindModeIfNull(bind *volume.MountPoint) *volume.MountPoint {
   124  	if bind.Mode == "" {
   125  		bind.Mode = "z"
   126  	}
   127  	return bind
   128  }