github.com/hms58/moby@v1.13.1/daemon/container_operations_unix.go (about)

     1  // +build linux freebsd
     2  
     3  package daemon
     4  
     5  import (
     6  	"fmt"
     7  	"io/ioutil"
     8  	"os"
     9  	"path/filepath"
    10  	"strconv"
    11  	"syscall"
    12  	"time"
    13  
    14  	"github.com/Sirupsen/logrus"
    15  	"github.com/cloudflare/cfssl/log"
    16  	"github.com/docker/docker/container"
    17  	"github.com/docker/docker/daemon/links"
    18  	"github.com/docker/docker/pkg/idtools"
    19  	"github.com/docker/docker/pkg/mount"
    20  	"github.com/docker/docker/pkg/stringid"
    21  	"github.com/docker/docker/runconfig"
    22  	"github.com/docker/libnetwork"
    23  	"github.com/opencontainers/runc/libcontainer/label"
    24  	"github.com/pkg/errors"
    25  )
    26  
    27  func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]string, error) {
    28  	var env []string
    29  	children := daemon.children(container)
    30  
    31  	bridgeSettings := container.NetworkSettings.Networks[runconfig.DefaultDaemonNetworkMode().NetworkName()]
    32  	if bridgeSettings == nil || bridgeSettings.EndpointSettings == nil {
    33  		return nil, nil
    34  	}
    35  
    36  	for linkAlias, child := range children {
    37  		if !child.IsRunning() {
    38  			return nil, fmt.Errorf("Cannot link to a non running container: %s AS %s", child.Name, linkAlias)
    39  		}
    40  
    41  		childBridgeSettings := child.NetworkSettings.Networks[runconfig.DefaultDaemonNetworkMode().NetworkName()]
    42  		if childBridgeSettings == nil || childBridgeSettings.EndpointSettings == nil {
    43  			return nil, fmt.Errorf("container %s not attached to default bridge network", child.ID)
    44  		}
    45  
    46  		link := links.NewLink(
    47  			bridgeSettings.IPAddress,
    48  			childBridgeSettings.IPAddress,
    49  			linkAlias,
    50  			child.Config.Env,
    51  			child.Config.ExposedPorts,
    52  		)
    53  
    54  		env = append(env, link.ToEnv()...)
    55  	}
    56  
    57  	return env, nil
    58  }
    59  
    60  func (daemon *Daemon) getIpcContainer(container *container.Container) (*container.Container, error) {
    61  	containerID := container.HostConfig.IpcMode.Container()
    62  	c, err := daemon.GetContainer(containerID)
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  	if !c.IsRunning() {
    67  		return nil, fmt.Errorf("cannot join IPC of a non running container: %s", containerID)
    68  	}
    69  	if c.IsRestarting() {
    70  		return nil, errContainerIsRestarting(container.ID)
    71  	}
    72  	return c, nil
    73  }
    74  
    75  func (daemon *Daemon) getPidContainer(container *container.Container) (*container.Container, error) {
    76  	containerID := container.HostConfig.PidMode.Container()
    77  	c, err := daemon.GetContainer(containerID)
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  	if !c.IsRunning() {
    82  		return nil, fmt.Errorf("cannot join PID of a non running container: %s", containerID)
    83  	}
    84  	if c.IsRestarting() {
    85  		return nil, errContainerIsRestarting(container.ID)
    86  	}
    87  	return c, nil
    88  }
    89  
    90  func (daemon *Daemon) setupIpcDirs(c *container.Container) error {
    91  	var err error
    92  
    93  	c.ShmPath, err = c.ShmResourcePath()
    94  	if err != nil {
    95  		return err
    96  	}
    97  
    98  	if c.HostConfig.IpcMode.IsContainer() {
    99  		ic, err := daemon.getIpcContainer(c)
   100  		if err != nil {
   101  			return err
   102  		}
   103  		c.ShmPath = ic.ShmPath
   104  	} else if c.HostConfig.IpcMode.IsHost() {
   105  		if _, err := os.Stat("/dev/shm"); err != nil {
   106  			return fmt.Errorf("/dev/shm is not mounted, but must be for --ipc=host")
   107  		}
   108  		c.ShmPath = "/dev/shm"
   109  	} else {
   110  		rootUID, rootGID := daemon.GetRemappedUIDGID()
   111  		if !c.HasMountFor("/dev/shm") {
   112  			shmPath, err := c.ShmResourcePath()
   113  			if err != nil {
   114  				return err
   115  			}
   116  
   117  			if err := idtools.MkdirAllAs(shmPath, 0700, rootUID, rootGID); err != nil {
   118  				return err
   119  			}
   120  
   121  			shmSize := container.DefaultSHMSize
   122  			if c.HostConfig.ShmSize != 0 {
   123  				shmSize = c.HostConfig.ShmSize
   124  			}
   125  			shmproperty := "mode=1777,size=" + strconv.FormatInt(shmSize, 10)
   126  			if err := syscall.Mount("shm", shmPath, "tmpfs", uintptr(syscall.MS_NOEXEC|syscall.MS_NOSUID|syscall.MS_NODEV), label.FormatMountLabel(shmproperty, c.GetMountLabel())); err != nil {
   127  				return fmt.Errorf("mounting shm tmpfs: %s", err)
   128  			}
   129  			if err := os.Chown(shmPath, rootUID, rootGID); err != nil {
   130  				return err
   131  			}
   132  		}
   133  
   134  	}
   135  
   136  	return nil
   137  }
   138  
   139  func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
   140  	if len(c.SecretReferences) == 0 {
   141  		return nil
   142  	}
   143  
   144  	localMountPath := c.SecretMountPath()
   145  	logrus.Debugf("secrets: setting up secret dir: %s", localMountPath)
   146  
   147  	defer func() {
   148  		if setupErr != nil {
   149  			// cleanup
   150  			_ = detachMounted(localMountPath)
   151  
   152  			if err := os.RemoveAll(localMountPath); err != nil {
   153  				log.Errorf("error cleaning up secret mount: %s", err)
   154  			}
   155  		}
   156  	}()
   157  
   158  	// retrieve possible remapped range start for root UID, GID
   159  	rootUID, rootGID := daemon.GetRemappedUIDGID()
   160  	// create tmpfs
   161  	if err := idtools.MkdirAllAs(localMountPath, 0700, rootUID, rootGID); err != nil {
   162  		return errors.Wrap(err, "error creating secret local mount path")
   163  	}
   164  	tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootUID, rootGID)
   165  	if err := mount.Mount("tmpfs", localMountPath, "tmpfs", "nodev,nosuid,noexec,"+tmpfsOwnership); err != nil {
   166  		return errors.Wrap(err, "unable to setup secret mount")
   167  	}
   168  
   169  	for _, s := range c.SecretReferences {
   170  		if c.SecretStore == nil {
   171  			return fmt.Errorf("secret store is not initialized")
   172  		}
   173  
   174  		// TODO (ehazlett): use type switch when more are supported
   175  		if s.File == nil {
   176  			return fmt.Errorf("secret target type is not a file target")
   177  		}
   178  
   179  		targetPath := filepath.Clean(s.File.Name)
   180  		// ensure that the target is a filename only; no paths allowed
   181  		if targetPath != filepath.Base(targetPath) {
   182  			return fmt.Errorf("error creating secret: secret must not be a path")
   183  		}
   184  
   185  		fPath := filepath.Join(localMountPath, targetPath)
   186  		if err := idtools.MkdirAllAs(filepath.Dir(fPath), 0700, rootUID, rootGID); err != nil {
   187  			return errors.Wrap(err, "error creating secret mount path")
   188  		}
   189  
   190  		logrus.WithFields(logrus.Fields{
   191  			"name": s.File.Name,
   192  			"path": fPath,
   193  		}).Debug("injecting secret")
   194  		secret := c.SecretStore.Get(s.SecretID)
   195  		if secret == nil {
   196  			return fmt.Errorf("unable to get secret from secret store")
   197  		}
   198  		if err := ioutil.WriteFile(fPath, secret.Spec.Data, s.File.Mode); err != nil {
   199  			return errors.Wrap(err, "error injecting secret")
   200  		}
   201  
   202  		uid, err := strconv.Atoi(s.File.UID)
   203  		if err != nil {
   204  			return err
   205  		}
   206  		gid, err := strconv.Atoi(s.File.GID)
   207  		if err != nil {
   208  			return err
   209  		}
   210  
   211  		if err := os.Chown(fPath, rootUID+uid, rootGID+gid); err != nil {
   212  			return errors.Wrap(err, "error setting ownership for secret")
   213  		}
   214  	}
   215  
   216  	// remount secrets ro
   217  	if err := mount.Mount("tmpfs", localMountPath, "tmpfs", "remount,ro,"+tmpfsOwnership); err != nil {
   218  		return errors.Wrap(err, "unable to remount secret dir as readonly")
   219  	}
   220  
   221  	return nil
   222  }
   223  
   224  func killProcessDirectly(container *container.Container) error {
   225  	if _, err := container.WaitStop(10 * time.Second); err != nil {
   226  		// Ensure that we don't kill ourselves
   227  		if pid := container.GetPID(); pid != 0 {
   228  			logrus.Infof("Container %s failed to exit within 10 seconds of kill - trying direct SIGKILL", stringid.TruncateID(container.ID))
   229  			if err := syscall.Kill(pid, 9); err != nil {
   230  				if err != syscall.ESRCH {
   231  					return err
   232  				}
   233  				e := errNoSuchProcess{pid, 9}
   234  				logrus.Debug(e)
   235  				return e
   236  			}
   237  		}
   238  	}
   239  	return nil
   240  }
   241  
   242  func detachMounted(path string) error {
   243  	return syscall.Unmount(path, syscall.MNT_DETACH)
   244  }
   245  
   246  func isLinkable(child *container.Container) bool {
   247  	// A container is linkable only if it belongs to the default network
   248  	_, ok := child.NetworkSettings.Networks[runconfig.DefaultDaemonNetworkMode().NetworkName()]
   249  	return ok
   250  }
   251  
   252  func enableIPOnPredefinedNetwork() bool {
   253  	return false
   254  }
   255  
   256  func (daemon *Daemon) isNetworkHotPluggable() bool {
   257  	return true
   258  }
   259  
   260  func setupPathsAndSandboxOptions(container *container.Container, sboxOptions *[]libnetwork.SandboxOption) error {
   261  	var err error
   262  
   263  	container.HostsPath, err = container.GetRootResourcePath("hosts")
   264  	if err != nil {
   265  		return err
   266  	}
   267  	*sboxOptions = append(*sboxOptions, libnetwork.OptionHostsPath(container.HostsPath))
   268  
   269  	container.ResolvConfPath, err = container.GetRootResourcePath("resolv.conf")
   270  	if err != nil {
   271  		return err
   272  	}
   273  	*sboxOptions = append(*sboxOptions, libnetwork.OptionResolvConfPath(container.ResolvConfPath))
   274  	return nil
   275  }
   276  
   277  func initializeNetworkingPaths(container *container.Container, nc *container.Container) {
   278  	container.HostnamePath = nc.HostnamePath
   279  	container.HostsPath = nc.HostsPath
   280  	container.ResolvConfPath = nc.ResolvConfPath
   281  }