github.com/jingleWang/moby@v1.13.1/container/container.go (about)

     1  package container
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io"
     7  	"net"
     8  	"os"
     9  	"path/filepath"
    10  	"strconv"
    11  	"strings"
    12  	"sync"
    13  	"syscall"
    14  	"time"
    15  
    16  	"golang.org/x/net/context"
    17  
    18  	"github.com/Sirupsen/logrus"
    19  	containertypes "github.com/docker/docker/api/types/container"
    20  	mounttypes "github.com/docker/docker/api/types/mount"
    21  	networktypes "github.com/docker/docker/api/types/network"
    22  	swarmtypes "github.com/docker/docker/api/types/swarm"
    23  	"github.com/docker/docker/container/stream"
    24  	"github.com/docker/docker/daemon/exec"
    25  	"github.com/docker/docker/daemon/logger"
    26  	"github.com/docker/docker/daemon/logger/jsonfilelog"
    27  	"github.com/docker/docker/daemon/network"
    28  	"github.com/docker/docker/image"
    29  	"github.com/docker/docker/layer"
    30  	"github.com/docker/docker/libcontainerd"
    31  	"github.com/docker/docker/pkg/idtools"
    32  	"github.com/docker/docker/pkg/ioutils"
    33  	"github.com/docker/docker/pkg/promise"
    34  	"github.com/docker/docker/pkg/signal"
    35  	"github.com/docker/docker/pkg/symlink"
    36  	"github.com/docker/docker/restartmanager"
    37  	"github.com/docker/docker/runconfig"
    38  	runconfigopts "github.com/docker/docker/runconfig/opts"
    39  	"github.com/docker/docker/volume"
    40  	"github.com/docker/go-connections/nat"
    41  	"github.com/docker/libnetwork"
    42  	"github.com/docker/libnetwork/netlabel"
    43  	"github.com/docker/libnetwork/options"
    44  	"github.com/docker/libnetwork/types"
    45  	agentexec "github.com/docker/swarmkit/agent/exec"
    46  	"github.com/opencontainers/runc/libcontainer/label"
    47  )
    48  
    49  const configFileName = "config.v2.json"
    50  
    51  const (
    52  	// DefaultStopTimeout is the timeout (in seconds) for the syscall signal used to stop a container.
    53  	DefaultStopTimeout = 10
    54  )
    55  
    56  var (
    57  	errInvalidEndpoint = fmt.Errorf("invalid endpoint while building port map info")
    58  	errInvalidNetwork  = fmt.Errorf("invalid network settings while building port map info")
    59  )
    60  
    61  // DetachError is special error which returned in case of container detach.
    62  type DetachError struct{}
    63  
    64  func (DetachError) Error() string {
    65  	return "detached from container"
    66  }
    67  
    68  // CommonContainer holds the fields for a container which are
    69  // applicable across all platforms supported by the daemon.
    70  type CommonContainer struct {
    71  	StreamConfig *stream.Config
    72  	// embed for Container to support states directly.
    73  	*State          `json:"State"` // Needed for Engine API version <= 1.11
    74  	Root            string         `json:"-"` // Path to the "home" of the container, including metadata.
    75  	BaseFS          string         `json:"-"` // Path to the graphdriver mountpoint
    76  	RWLayer         layer.RWLayer  `json:"-"`
    77  	ID              string
    78  	Created         time.Time
    79  	Managed         bool
    80  	Path            string
    81  	Args            []string
    82  	Config          *containertypes.Config
    83  	ImageID         image.ID `json:"Image"`
    84  	NetworkSettings *network.Settings
    85  	LogPath         string
    86  	Name            string
    87  	Driver          string
    88  	// MountLabel contains the options for the 'mount' command
    89  	MountLabel             string
    90  	ProcessLabel           string
    91  	RestartCount           int
    92  	HasBeenStartedBefore   bool
    93  	HasBeenManuallyStopped bool // used for unless-stopped restart policy
    94  	MountPoints            map[string]*volume.MountPoint
    95  	HostConfig             *containertypes.HostConfig `json:"-"` // do not serialize the host config in the json, otherwise we'll make the container unportable
    96  	ExecCommands           *exec.Store                `json:"-"`
    97  	SecretStore            agentexec.SecretGetter     `json:"-"`
    98  	SecretReferences       []*swarmtypes.SecretReference
    99  	// logDriver for closing
   100  	LogDriver      logger.Logger  `json:"-"`
   101  	LogCopier      *logger.Copier `json:"-"`
   102  	restartManager restartmanager.RestartManager
   103  	attachContext  *attachContext
   104  }
   105  
   106  // NewBaseContainer creates a new container with its
   107  // basic configuration.
   108  func NewBaseContainer(id, root string) *Container {
   109  	return &Container{
   110  		CommonContainer: CommonContainer{
   111  			ID:            id,
   112  			State:         NewState(),
   113  			ExecCommands:  exec.NewStore(),
   114  			Root:          root,
   115  			MountPoints:   make(map[string]*volume.MountPoint),
   116  			StreamConfig:  stream.NewConfig(),
   117  			attachContext: &attachContext{},
   118  		},
   119  	}
   120  }
   121  
   122  // FromDisk loads the container configuration stored in the host.
   123  func (container *Container) FromDisk() error {
   124  	pth, err := container.ConfigPath()
   125  	if err != nil {
   126  		return err
   127  	}
   128  
   129  	jsonSource, err := os.Open(pth)
   130  	if err != nil {
   131  		return err
   132  	}
   133  	defer jsonSource.Close()
   134  
   135  	dec := json.NewDecoder(jsonSource)
   136  
   137  	// Load container settings
   138  	if err := dec.Decode(container); err != nil {
   139  		return err
   140  	}
   141  
   142  	if err := label.ReserveLabel(container.ProcessLabel); err != nil {
   143  		return err
   144  	}
   145  	return container.readHostConfig()
   146  }
   147  
   148  // ToDisk saves the container configuration on disk.
   149  func (container *Container) ToDisk() error {
   150  	pth, err := container.ConfigPath()
   151  	if err != nil {
   152  		return err
   153  	}
   154  
   155  	jsonSource, err := ioutils.NewAtomicFileWriter(pth, 0644)
   156  	if err != nil {
   157  		return err
   158  	}
   159  	defer jsonSource.Close()
   160  
   161  	enc := json.NewEncoder(jsonSource)
   162  
   163  	// Save container settings
   164  	if err := enc.Encode(container); err != nil {
   165  		return err
   166  	}
   167  
   168  	return container.WriteHostConfig()
   169  }
   170  
   171  // ToDiskLocking saves the container configuration on disk in a thread safe way.
   172  func (container *Container) ToDiskLocking() error {
   173  	container.Lock()
   174  	err := container.ToDisk()
   175  	container.Unlock()
   176  	return err
   177  }
   178  
   179  // readHostConfig reads the host configuration from disk for the container.
   180  func (container *Container) readHostConfig() error {
   181  	container.HostConfig = &containertypes.HostConfig{}
   182  	// If the hostconfig file does not exist, do not read it.
   183  	// (We still have to initialize container.HostConfig,
   184  	// but that's OK, since we just did that above.)
   185  	pth, err := container.HostConfigPath()
   186  	if err != nil {
   187  		return err
   188  	}
   189  
   190  	f, err := os.Open(pth)
   191  	if err != nil {
   192  		if os.IsNotExist(err) {
   193  			return nil
   194  		}
   195  		return err
   196  	}
   197  	defer f.Close()
   198  
   199  	if err := json.NewDecoder(f).Decode(&container.HostConfig); err != nil {
   200  		return err
   201  	}
   202  
   203  	container.InitDNSHostConfig()
   204  
   205  	return nil
   206  }
   207  
   208  // WriteHostConfig saves the host configuration on disk for the container.
   209  func (container *Container) WriteHostConfig() error {
   210  	pth, err := container.HostConfigPath()
   211  	if err != nil {
   212  		return err
   213  	}
   214  
   215  	f, err := ioutils.NewAtomicFileWriter(pth, 0644)
   216  	if err != nil {
   217  		return err
   218  	}
   219  	defer f.Close()
   220  
   221  	return json.NewEncoder(f).Encode(&container.HostConfig)
   222  }
   223  
   224  // SetupWorkingDirectory sets up the container's working directory as set in container.Config.WorkingDir
   225  func (container *Container) SetupWorkingDirectory(rootUID, rootGID int) error {
   226  	if container.Config.WorkingDir == "" {
   227  		return nil
   228  	}
   229  
   230  	container.Config.WorkingDir = filepath.Clean(container.Config.WorkingDir)
   231  
   232  	pth, err := container.GetResourcePath(container.Config.WorkingDir)
   233  	if err != nil {
   234  		return err
   235  	}
   236  
   237  	if err := idtools.MkdirAllNewAs(pth, 0755, rootUID, rootGID); err != nil {
   238  		pthInfo, err2 := os.Stat(pth)
   239  		if err2 == nil && pthInfo != nil && !pthInfo.IsDir() {
   240  			return fmt.Errorf("Cannot mkdir: %s is not a directory", container.Config.WorkingDir)
   241  		}
   242  
   243  		return err
   244  	}
   245  
   246  	return nil
   247  }
   248  
   249  // GetResourcePath evaluates `path` in the scope of the container's BaseFS, with proper path
   250  // sanitisation. Symlinks are all scoped to the BaseFS of the container, as
   251  // though the container's BaseFS was `/`.
   252  //
   253  // The BaseFS of a container is the host-facing path which is bind-mounted as
   254  // `/` inside the container. This method is essentially used to access a
   255  // particular path inside the container as though you were a process in that
   256  // container.
   257  //
   258  // NOTE: The returned path is *only* safely scoped inside the container's BaseFS
   259  //       if no component of the returned path changes (such as a component
   260  //       symlinking to a different path) between using this method and using the
   261  //       path. See symlink.FollowSymlinkInScope for more details.
   262  func (container *Container) GetResourcePath(path string) (string, error) {
   263  	// IMPORTANT - These are paths on the OS where the daemon is running, hence
   264  	// any filepath operations must be done in an OS agnostic way.
   265  
   266  	cleanPath := cleanResourcePath(path)
   267  	r, e := symlink.FollowSymlinkInScope(filepath.Join(container.BaseFS, cleanPath), container.BaseFS)
   268  
   269  	// Log this here on the daemon side as there's otherwise no indication apart
   270  	// from the error being propagated all the way back to the client. This makes
   271  	// debugging significantly easier and clearly indicates the error comes from the daemon.
   272  	if e != nil {
   273  		logrus.Errorf("Failed to FollowSymlinkInScope BaseFS %s cleanPath %s path %s %s\n", container.BaseFS, cleanPath, path, e)
   274  	}
   275  	return r, e
   276  }
   277  
   278  // GetRootResourcePath evaluates `path` in the scope of the container's root, with proper path
   279  // sanitisation. Symlinks are all scoped to the root of the container, as
   280  // though the container's root was `/`.
   281  //
   282  // The root of a container is the host-facing configuration metadata directory.
   283  // Only use this method to safely access the container's `container.json` or
   284  // other metadata files. If in doubt, use container.GetResourcePath.
   285  //
   286  // NOTE: The returned path is *only* safely scoped inside the container's root
   287  //       if no component of the returned path changes (such as a component
   288  //       symlinking to a different path) between using this method and using the
   289  //       path. See symlink.FollowSymlinkInScope for more details.
   290  func (container *Container) GetRootResourcePath(path string) (string, error) {
   291  	// IMPORTANT - These are paths on the OS where the daemon is running, hence
   292  	// any filepath operations must be done in an OS agnostic way.
   293  	cleanPath := filepath.Join(string(os.PathSeparator), path)
   294  	return symlink.FollowSymlinkInScope(filepath.Join(container.Root, cleanPath), container.Root)
   295  }
   296  
   297  // ExitOnNext signals to the monitor that it should not restart the container
   298  // after we send the kill signal.
   299  func (container *Container) ExitOnNext() {
   300  	container.RestartManager().Cancel()
   301  }
   302  
   303  // HostConfigPath returns the path to the container's JSON hostconfig
   304  func (container *Container) HostConfigPath() (string, error) {
   305  	return container.GetRootResourcePath("hostconfig.json")
   306  }
   307  
   308  // ConfigPath returns the path to the container's JSON config
   309  func (container *Container) ConfigPath() (string, error) {
   310  	return container.GetRootResourcePath(configFileName)
   311  }
   312  
   313  // CheckpointDir returns the directory checkpoints are stored in
   314  func (container *Container) CheckpointDir() string {
   315  	return filepath.Join(container.Root, "checkpoints")
   316  }
   317  
   318  // StartLogger starts a new logger driver for the container.
   319  func (container *Container) StartLogger(cfg containertypes.LogConfig) (logger.Logger, error) {
   320  	c, err := logger.GetLogDriver(cfg.Type)
   321  	if err != nil {
   322  		return nil, fmt.Errorf("Failed to get logging factory: %v", err)
   323  	}
   324  	ctx := logger.Context{
   325  		Config:              cfg.Config,
   326  		ContainerID:         container.ID,
   327  		ContainerName:       container.Name,
   328  		ContainerEntrypoint: container.Path,
   329  		ContainerArgs:       container.Args,
   330  		ContainerImageID:    container.ImageID.String(),
   331  		ContainerImageName:  container.Config.Image,
   332  		ContainerCreated:    container.Created,
   333  		ContainerEnv:        container.Config.Env,
   334  		ContainerLabels:     container.Config.Labels,
   335  		DaemonName:          "docker",
   336  	}
   337  
   338  	// Set logging file for "json-logger"
   339  	if cfg.Type == jsonfilelog.Name {
   340  		ctx.LogPath, err = container.GetRootResourcePath(fmt.Sprintf("%s-json.log", container.ID))
   341  		if err != nil {
   342  			return nil, err
   343  		}
   344  	}
   345  	return c(ctx)
   346  }
   347  
   348  // GetProcessLabel returns the process label for the container.
   349  func (container *Container) GetProcessLabel() string {
   350  	// even if we have a process label return "" if we are running
   351  	// in privileged mode
   352  	if container.HostConfig.Privileged {
   353  		return ""
   354  	}
   355  	return container.ProcessLabel
   356  }
   357  
   358  // GetMountLabel returns the mounting label for the container.
   359  // This label is empty if the container is privileged.
   360  func (container *Container) GetMountLabel() string {
   361  	return container.MountLabel
   362  }
   363  
   364  // GetExecIDs returns the list of exec commands running on the container.
   365  func (container *Container) GetExecIDs() []string {
   366  	return container.ExecCommands.List()
   367  }
   368  
   369  // Attach connects to the container's TTY, delegating to standard
   370  // streams or websockets depending on the configuration.
   371  func (container *Container) Attach(stdin io.ReadCloser, stdout io.Writer, stderr io.Writer, keys []byte) chan error {
   372  	ctx := container.InitAttachContext()
   373  	return AttachStreams(ctx, container.StreamConfig, container.Config.OpenStdin, container.Config.StdinOnce, container.Config.Tty, stdin, stdout, stderr, keys)
   374  }
   375  
   376  // AttachStreams connects streams to a TTY.
   377  // Used by exec too. Should this move somewhere else?
   378  func AttachStreams(ctx context.Context, streamConfig *stream.Config, openStdin, stdinOnce, tty bool, stdin io.ReadCloser, stdout io.Writer, stderr io.Writer, keys []byte) chan error {
   379  	var (
   380  		cStdout, cStderr io.ReadCloser
   381  		cStdin           io.WriteCloser
   382  		wg               sync.WaitGroup
   383  		errors           = make(chan error, 3)
   384  	)
   385  
   386  	if stdin != nil && openStdin {
   387  		cStdin = streamConfig.StdinPipe()
   388  		wg.Add(1)
   389  	}
   390  
   391  	if stdout != nil {
   392  		cStdout = streamConfig.StdoutPipe()
   393  		wg.Add(1)
   394  	}
   395  
   396  	if stderr != nil {
   397  		cStderr = streamConfig.StderrPipe()
   398  		wg.Add(1)
   399  	}
   400  
   401  	// Connect stdin of container to the http conn.
   402  	go func() {
   403  		if stdin == nil || !openStdin {
   404  			return
   405  		}
   406  		logrus.Debug("attach: stdin: begin")
   407  
   408  		var err error
   409  		if tty {
   410  			_, err = copyEscapable(cStdin, stdin, keys)
   411  		} else {
   412  			_, err = io.Copy(cStdin, stdin)
   413  		}
   414  		if err == io.ErrClosedPipe {
   415  			err = nil
   416  		}
   417  		if err != nil {
   418  			logrus.Errorf("attach: stdin: %s", err)
   419  			errors <- err
   420  		}
   421  		if stdinOnce && !tty {
   422  			cStdin.Close()
   423  		} else {
   424  			// No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr
   425  			if cStdout != nil {
   426  				cStdout.Close()
   427  			}
   428  			if cStderr != nil {
   429  				cStderr.Close()
   430  			}
   431  		}
   432  		logrus.Debug("attach: stdin: end")
   433  		wg.Done()
   434  	}()
   435  
   436  	attachStream := func(name string, stream io.Writer, streamPipe io.ReadCloser) {
   437  		if stream == nil {
   438  			return
   439  		}
   440  
   441  		logrus.Debugf("attach: %s: begin", name)
   442  		_, err := io.Copy(stream, streamPipe)
   443  		if err == io.ErrClosedPipe {
   444  			err = nil
   445  		}
   446  		if err != nil {
   447  			logrus.Errorf("attach: %s: %v", name, err)
   448  			errors <- err
   449  		}
   450  		// Make sure stdin gets closed
   451  		if stdin != nil {
   452  			stdin.Close()
   453  		}
   454  		streamPipe.Close()
   455  		logrus.Debugf("attach: %s: end", name)
   456  		wg.Done()
   457  	}
   458  
   459  	go attachStream("stdout", stdout, cStdout)
   460  	go attachStream("stderr", stderr, cStderr)
   461  
   462  	return promise.Go(func() error {
   463  		done := make(chan struct{})
   464  		go func() {
   465  			wg.Wait()
   466  			close(done)
   467  		}()
   468  		select {
   469  		case <-done:
   470  		case <-ctx.Done():
   471  			// close all pipes
   472  			if cStdin != nil {
   473  				cStdin.Close()
   474  			}
   475  			if cStdout != nil {
   476  				cStdout.Close()
   477  			}
   478  			if cStderr != nil {
   479  				cStderr.Close()
   480  			}
   481  			<-done
   482  		}
   483  		close(errors)
   484  		for err := range errors {
   485  			if err != nil {
   486  				return err
   487  			}
   488  		}
   489  		return nil
   490  	})
   491  }
   492  
   493  // Code c/c from io.Copy() modified to handle escape sequence
   494  func copyEscapable(dst io.Writer, src io.ReadCloser, keys []byte) (written int64, err error) {
   495  	if len(keys) == 0 {
   496  		// Default keys : ctrl-p ctrl-q
   497  		keys = []byte{16, 17}
   498  	}
   499  	buf := make([]byte, 32*1024)
   500  	for {
   501  		nr, er := src.Read(buf)
   502  		if nr > 0 {
   503  			// ---- Docker addition
   504  			preservBuf := []byte{}
   505  			for i, key := range keys {
   506  				preservBuf = append(preservBuf, buf[0:nr]...)
   507  				if nr != 1 || buf[0] != key {
   508  					break
   509  				}
   510  				if i == len(keys)-1 {
   511  					src.Close()
   512  					return 0, DetachError{}
   513  				}
   514  				nr, er = src.Read(buf)
   515  			}
   516  			var nw int
   517  			var ew error
   518  			if len(preservBuf) > 0 {
   519  				nw, ew = dst.Write(preservBuf)
   520  				nr = len(preservBuf)
   521  			} else {
   522  				// ---- End of docker
   523  				nw, ew = dst.Write(buf[0:nr])
   524  			}
   525  			if nw > 0 {
   526  				written += int64(nw)
   527  			}
   528  			if ew != nil {
   529  				err = ew
   530  				break
   531  			}
   532  			if nr != nw {
   533  				err = io.ErrShortWrite
   534  				break
   535  			}
   536  		}
   537  		if er == io.EOF {
   538  			break
   539  		}
   540  		if er != nil {
   541  			err = er
   542  			break
   543  		}
   544  	}
   545  	return written, err
   546  }
   547  
   548  // ShouldRestart decides whether the daemon should restart the container or not.
   549  // This is based on the container's restart policy.
   550  func (container *Container) ShouldRestart() bool {
   551  	shouldRestart, _, _ := container.RestartManager().ShouldRestart(uint32(container.ExitCode()), container.HasBeenManuallyStopped, container.FinishedAt.Sub(container.StartedAt))
   552  	return shouldRestart
   553  }
   554  
   555  // AddMountPointWithVolume adds a new mount point configured with a volume to the container.
   556  func (container *Container) AddMountPointWithVolume(destination string, vol volume.Volume, rw bool) {
   557  	container.MountPoints[destination] = &volume.MountPoint{
   558  		Type:        mounttypes.TypeVolume,
   559  		Name:        vol.Name(),
   560  		Driver:      vol.DriverName(),
   561  		Destination: destination,
   562  		RW:          rw,
   563  		Volume:      vol,
   564  		CopyData:    volume.DefaultCopyMode,
   565  	}
   566  }
   567  
   568  // UnmountVolumes unmounts all volumes
   569  func (container *Container) UnmountVolumes(volumeEventLog func(name, action string, attributes map[string]string)) error {
   570  	var errors []string
   571  	for _, volumeMount := range container.MountPoints {
   572  		// Check if the mounpoint has an ID, this is currently the best way to tell if it's actually mounted
   573  		// TODO(cpuguyh83): there should be a better way to handle this
   574  		if volumeMount.Volume != nil && volumeMount.ID != "" {
   575  			if err := volumeMount.Volume.Unmount(volumeMount.ID); err != nil {
   576  				errors = append(errors, err.Error())
   577  				continue
   578  			}
   579  			volumeMount.ID = ""
   580  
   581  			attributes := map[string]string{
   582  				"driver":    volumeMount.Volume.DriverName(),
   583  				"container": container.ID,
   584  			}
   585  			volumeEventLog(volumeMount.Volume.Name(), "unmount", attributes)
   586  		}
   587  	}
   588  	if len(errors) > 0 {
   589  		return fmt.Errorf("error while unmounting volumes for container %s: %s", container.ID, strings.Join(errors, "; "))
   590  	}
   591  	return nil
   592  }
   593  
   594  // IsDestinationMounted checks whether a path is mounted on the container or not.
   595  func (container *Container) IsDestinationMounted(destination string) bool {
   596  	return container.MountPoints[destination] != nil
   597  }
   598  
   599  // StopSignal returns the signal used to stop the container.
   600  func (container *Container) StopSignal() int {
   601  	var stopSignal syscall.Signal
   602  	if container.Config.StopSignal != "" {
   603  		stopSignal, _ = signal.ParseSignal(container.Config.StopSignal)
   604  	}
   605  
   606  	if int(stopSignal) == 0 {
   607  		stopSignal, _ = signal.ParseSignal(signal.DefaultStopSignal)
   608  	}
   609  	return int(stopSignal)
   610  }
   611  
   612  // StopTimeout returns the timeout (in seconds) used to stop the container.
   613  func (container *Container) StopTimeout() int {
   614  	if container.Config.StopTimeout != nil {
   615  		return *container.Config.StopTimeout
   616  	}
   617  	return DefaultStopTimeout
   618  }
   619  
   620  // InitDNSHostConfig ensures that the dns fields are never nil.
   621  // New containers don't ever have those fields nil,
   622  // but pre created containers can still have those nil values.
   623  // The non-recommended host configuration in the start api can
   624  // make these fields nil again, this corrects that issue until
   625  // we remove that behavior for good.
   626  // See https://github.com/docker/docker/pull/17779
   627  // for a more detailed explanation on why we don't want that.
   628  func (container *Container) InitDNSHostConfig() {
   629  	container.Lock()
   630  	defer container.Unlock()
   631  	if container.HostConfig.DNS == nil {
   632  		container.HostConfig.DNS = make([]string, 0)
   633  	}
   634  
   635  	if container.HostConfig.DNSSearch == nil {
   636  		container.HostConfig.DNSSearch = make([]string, 0)
   637  	}
   638  
   639  	if container.HostConfig.DNSOptions == nil {
   640  		container.HostConfig.DNSOptions = make([]string, 0)
   641  	}
   642  }
   643  
   644  // GetEndpointInNetwork returns the container's endpoint to the provided network.
   645  func (container *Container) GetEndpointInNetwork(n libnetwork.Network) (libnetwork.Endpoint, error) {
   646  	endpointName := strings.TrimPrefix(container.Name, "/")
   647  	return n.EndpointByName(endpointName)
   648  }
   649  
   650  func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint) error {
   651  	if ep == nil {
   652  		return errInvalidEndpoint
   653  	}
   654  
   655  	networkSettings := container.NetworkSettings
   656  	if networkSettings == nil {
   657  		return errInvalidNetwork
   658  	}
   659  
   660  	if len(networkSettings.Ports) == 0 {
   661  		pm, err := getEndpointPortMapInfo(ep)
   662  		if err != nil {
   663  			return err
   664  		}
   665  		networkSettings.Ports = pm
   666  	}
   667  	return nil
   668  }
   669  
   670  func getEndpointPortMapInfo(ep libnetwork.Endpoint) (nat.PortMap, error) {
   671  	pm := nat.PortMap{}
   672  	driverInfo, err := ep.DriverInfo()
   673  	if err != nil {
   674  		return pm, err
   675  	}
   676  
   677  	if driverInfo == nil {
   678  		// It is not an error for epInfo to be nil
   679  		return pm, nil
   680  	}
   681  
   682  	if expData, ok := driverInfo[netlabel.ExposedPorts]; ok {
   683  		if exposedPorts, ok := expData.([]types.TransportPort); ok {
   684  			for _, tp := range exposedPorts {
   685  				natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port)))
   686  				if err != nil {
   687  					return pm, fmt.Errorf("Error parsing Port value(%v):%v", tp.Port, err)
   688  				}
   689  				pm[natPort] = nil
   690  			}
   691  		}
   692  	}
   693  
   694  	mapData, ok := driverInfo[netlabel.PortMap]
   695  	if !ok {
   696  		return pm, nil
   697  	}
   698  
   699  	if portMapping, ok := mapData.([]types.PortBinding); ok {
   700  		for _, pp := range portMapping {
   701  			natPort, err := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port)))
   702  			if err != nil {
   703  				return pm, err
   704  			}
   705  			natBndg := nat.PortBinding{HostIP: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))}
   706  			pm[natPort] = append(pm[natPort], natBndg)
   707  		}
   708  	}
   709  
   710  	return pm, nil
   711  }
   712  
   713  // GetSandboxPortMapInfo retrieves the current port-mapping programmed for the given sandbox
   714  func GetSandboxPortMapInfo(sb libnetwork.Sandbox) nat.PortMap {
   715  	pm := nat.PortMap{}
   716  	if sb == nil {
   717  		return pm
   718  	}
   719  
   720  	for _, ep := range sb.Endpoints() {
   721  		pm, _ = getEndpointPortMapInfo(ep)
   722  		if len(pm) > 0 {
   723  			break
   724  		}
   725  	}
   726  	return pm
   727  }
   728  
   729  // BuildEndpointInfo sets endpoint-related fields on container.NetworkSettings based on the provided network and endpoint.
   730  func (container *Container) BuildEndpointInfo(n libnetwork.Network, ep libnetwork.Endpoint) error {
   731  	if ep == nil {
   732  		return errInvalidEndpoint
   733  	}
   734  
   735  	networkSettings := container.NetworkSettings
   736  	if networkSettings == nil {
   737  		return errInvalidNetwork
   738  	}
   739  
   740  	epInfo := ep.Info()
   741  	if epInfo == nil {
   742  		// It is not an error to get an empty endpoint info
   743  		return nil
   744  	}
   745  
   746  	if _, ok := networkSettings.Networks[n.Name()]; !ok {
   747  		networkSettings.Networks[n.Name()] = &network.EndpointSettings{
   748  			EndpointSettings: &networktypes.EndpointSettings{},
   749  		}
   750  	}
   751  	networkSettings.Networks[n.Name()].NetworkID = n.ID()
   752  	networkSettings.Networks[n.Name()].EndpointID = ep.ID()
   753  
   754  	iface := epInfo.Iface()
   755  	if iface == nil {
   756  		return nil
   757  	}
   758  
   759  	if iface.MacAddress() != nil {
   760  		networkSettings.Networks[n.Name()].MacAddress = iface.MacAddress().String()
   761  	}
   762  
   763  	if iface.Address() != nil {
   764  		ones, _ := iface.Address().Mask.Size()
   765  		networkSettings.Networks[n.Name()].IPAddress = iface.Address().IP.String()
   766  		networkSettings.Networks[n.Name()].IPPrefixLen = ones
   767  	}
   768  
   769  	if iface.AddressIPv6() != nil && iface.AddressIPv6().IP.To16() != nil {
   770  		onesv6, _ := iface.AddressIPv6().Mask.Size()
   771  		networkSettings.Networks[n.Name()].GlobalIPv6Address = iface.AddressIPv6().IP.String()
   772  		networkSettings.Networks[n.Name()].GlobalIPv6PrefixLen = onesv6
   773  	}
   774  
   775  	return nil
   776  }
   777  
   778  // UpdateJoinInfo updates network settings when container joins network n with endpoint ep.
   779  func (container *Container) UpdateJoinInfo(n libnetwork.Network, ep libnetwork.Endpoint) error {
   780  	if err := container.buildPortMapInfo(ep); err != nil {
   781  		return err
   782  	}
   783  
   784  	epInfo := ep.Info()
   785  	if epInfo == nil {
   786  		// It is not an error to get an empty endpoint info
   787  		return nil
   788  	}
   789  	if epInfo.Gateway() != nil {
   790  		container.NetworkSettings.Networks[n.Name()].Gateway = epInfo.Gateway().String()
   791  	}
   792  	if epInfo.GatewayIPv6().To16() != nil {
   793  		container.NetworkSettings.Networks[n.Name()].IPv6Gateway = epInfo.GatewayIPv6().String()
   794  	}
   795  
   796  	return nil
   797  }
   798  
   799  // UpdateSandboxNetworkSettings updates the sandbox ID and Key.
   800  func (container *Container) UpdateSandboxNetworkSettings(sb libnetwork.Sandbox) error {
   801  	container.NetworkSettings.SandboxID = sb.ID()
   802  	container.NetworkSettings.SandboxKey = sb.Key()
   803  	return nil
   804  }
   805  
   806  // BuildJoinOptions builds endpoint Join options from a given network.
   807  func (container *Container) BuildJoinOptions(n libnetwork.Network) ([]libnetwork.EndpointOption, error) {
   808  	var joinOptions []libnetwork.EndpointOption
   809  	if epConfig, ok := container.NetworkSettings.Networks[n.Name()]; ok {
   810  		for _, str := range epConfig.Links {
   811  			name, alias, err := runconfigopts.ParseLink(str)
   812  			if err != nil {
   813  				return nil, err
   814  			}
   815  			joinOptions = append(joinOptions, libnetwork.CreateOptionAlias(name, alias))
   816  		}
   817  	}
   818  	return joinOptions, nil
   819  }
   820  
   821  // BuildCreateEndpointOptions builds endpoint options from a given network.
   822  func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network, epConfig *networktypes.EndpointSettings, sb libnetwork.Sandbox, daemonDNS []string) ([]libnetwork.EndpointOption, error) {
   823  	var (
   824  		bindings      = make(nat.PortMap)
   825  		pbList        []types.PortBinding
   826  		exposeList    []types.TransportPort
   827  		createOptions []libnetwork.EndpointOption
   828  	)
   829  
   830  	defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()
   831  
   832  	if (!container.EnableServiceDiscoveryOnDefaultNetwork() && n.Name() == defaultNetName) ||
   833  		container.NetworkSettings.IsAnonymousEndpoint {
   834  		createOptions = append(createOptions, libnetwork.CreateOptionAnonymous())
   835  	}
   836  
   837  	if epConfig != nil {
   838  		ipam := epConfig.IPAMConfig
   839  		if ipam != nil && (ipam.IPv4Address != "" || ipam.IPv6Address != "" || len(ipam.LinkLocalIPs) > 0) {
   840  			var ipList []net.IP
   841  			for _, ips := range ipam.LinkLocalIPs {
   842  				if ip := net.ParseIP(ips); ip != nil {
   843  					ipList = append(ipList, ip)
   844  				}
   845  			}
   846  			createOptions = append(createOptions,
   847  				libnetwork.CreateOptionIpam(net.ParseIP(ipam.IPv4Address), net.ParseIP(ipam.IPv6Address), ipList, nil))
   848  		}
   849  
   850  		for _, alias := range epConfig.Aliases {
   851  			createOptions = append(createOptions, libnetwork.CreateOptionMyAlias(alias))
   852  		}
   853  	}
   854  
   855  	if container.NetworkSettings.Service != nil {
   856  		svcCfg := container.NetworkSettings.Service
   857  
   858  		var vip string
   859  		if svcCfg.VirtualAddresses[n.ID()] != nil {
   860  			vip = svcCfg.VirtualAddresses[n.ID()].IPv4
   861  		}
   862  
   863  		var portConfigs []*libnetwork.PortConfig
   864  		for _, portConfig := range svcCfg.ExposedPorts {
   865  			portConfigs = append(portConfigs, &libnetwork.PortConfig{
   866  				Name:          portConfig.Name,
   867  				Protocol:      libnetwork.PortConfig_Protocol(portConfig.Protocol),
   868  				TargetPort:    portConfig.TargetPort,
   869  				PublishedPort: portConfig.PublishedPort,
   870  			})
   871  		}
   872  
   873  		createOptions = append(createOptions, libnetwork.CreateOptionService(svcCfg.Name, svcCfg.ID, net.ParseIP(vip), portConfigs, svcCfg.Aliases[n.ID()]))
   874  	}
   875  
   876  	if !containertypes.NetworkMode(n.Name()).IsUserDefined() {
   877  		createOptions = append(createOptions, libnetwork.CreateOptionDisableResolution())
   878  	}
   879  
   880  	// configs that are applicable only for the endpoint in the network
   881  	// to which container was connected to on docker run.
   882  	// Ideally all these network-specific endpoint configurations must be moved under
   883  	// container.NetworkSettings.Networks[n.Name()]
   884  	if n.Name() == container.HostConfig.NetworkMode.NetworkName() ||
   885  		(n.Name() == defaultNetName && container.HostConfig.NetworkMode.IsDefault()) {
   886  		if container.Config.MacAddress != "" {
   887  			mac, err := net.ParseMAC(container.Config.MacAddress)
   888  			if err != nil {
   889  				return nil, err
   890  			}
   891  
   892  			genericOption := options.Generic{
   893  				netlabel.MacAddress: mac,
   894  			}
   895  
   896  			createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption))
   897  		}
   898  	}
   899  
   900  	// Port-mapping rules belong to the container & applicable only to non-internal networks
   901  	portmaps := GetSandboxPortMapInfo(sb)
   902  	if n.Info().Internal() || len(portmaps) > 0 {
   903  		return createOptions, nil
   904  	}
   905  
   906  	if container.HostConfig.PortBindings != nil {
   907  		for p, b := range container.HostConfig.PortBindings {
   908  			bindings[p] = []nat.PortBinding{}
   909  			for _, bb := range b {
   910  				bindings[p] = append(bindings[p], nat.PortBinding{
   911  					HostIP:   bb.HostIP,
   912  					HostPort: bb.HostPort,
   913  				})
   914  			}
   915  		}
   916  	}
   917  
   918  	portSpecs := container.Config.ExposedPorts
   919  	ports := make([]nat.Port, len(portSpecs))
   920  	var i int
   921  	for p := range portSpecs {
   922  		ports[i] = p
   923  		i++
   924  	}
   925  	nat.SortPortMap(ports, bindings)
   926  	for _, port := range ports {
   927  		expose := types.TransportPort{}
   928  		expose.Proto = types.ParseProtocol(port.Proto())
   929  		expose.Port = uint16(port.Int())
   930  		exposeList = append(exposeList, expose)
   931  
   932  		pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto}
   933  		binding := bindings[port]
   934  		for i := 0; i < len(binding); i++ {
   935  			pbCopy := pb.GetCopy()
   936  			newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort))
   937  			var portStart, portEnd int
   938  			if err == nil {
   939  				portStart, portEnd, err = newP.Range()
   940  			}
   941  			if err != nil {
   942  				return nil, fmt.Errorf("Error parsing HostPort value(%s):%v", binding[i].HostPort, err)
   943  			}
   944  			pbCopy.HostPort = uint16(portStart)
   945  			pbCopy.HostPortEnd = uint16(portEnd)
   946  			pbCopy.HostIP = net.ParseIP(binding[i].HostIP)
   947  			pbList = append(pbList, pbCopy)
   948  		}
   949  
   950  		if container.HostConfig.PublishAllPorts && len(binding) == 0 {
   951  			pbList = append(pbList, pb)
   952  		}
   953  	}
   954  
   955  	var dns []string
   956  
   957  	if len(container.HostConfig.DNS) > 0 {
   958  		dns = container.HostConfig.DNS
   959  	} else if len(daemonDNS) > 0 {
   960  		dns = daemonDNS
   961  	}
   962  
   963  	if len(dns) > 0 {
   964  		createOptions = append(createOptions,
   965  			libnetwork.CreateOptionDNS(dns))
   966  	}
   967  
   968  	createOptions = append(createOptions,
   969  		libnetwork.CreateOptionPortMapping(pbList),
   970  		libnetwork.CreateOptionExposedPorts(exposeList))
   971  
   972  	return createOptions, nil
   973  }
   974  
   975  // UpdateMonitor updates monitor configure for running container
   976  func (container *Container) UpdateMonitor(restartPolicy containertypes.RestartPolicy) {
   977  	type policySetter interface {
   978  		SetPolicy(containertypes.RestartPolicy)
   979  	}
   980  
   981  	if rm, ok := container.RestartManager().(policySetter); ok {
   982  		rm.SetPolicy(restartPolicy)
   983  	}
   984  }
   985  
   986  // FullHostname returns hostname and optional domain appended to it.
   987  func (container *Container) FullHostname() string {
   988  	fullHostname := container.Config.Hostname
   989  	if container.Config.Domainname != "" {
   990  		fullHostname = fmt.Sprintf("%s.%s", fullHostname, container.Config.Domainname)
   991  	}
   992  	return fullHostname
   993  }
   994  
   995  // RestartManager returns the current restartmanager instance connected to container.
   996  func (container *Container) RestartManager() restartmanager.RestartManager {
   997  	if container.restartManager == nil {
   998  		container.restartManager = restartmanager.New(container.HostConfig.RestartPolicy, container.RestartCount)
   999  	}
  1000  	return container.restartManager
  1001  }
  1002  
  1003  // ResetRestartManager initializes new restartmanager based on container config
  1004  func (container *Container) ResetRestartManager(resetCount bool) {
  1005  	if container.restartManager != nil {
  1006  		container.restartManager.Cancel()
  1007  	}
  1008  	if resetCount {
  1009  		container.RestartCount = 0
  1010  	}
  1011  	container.restartManager = nil
  1012  }
  1013  
  1014  type attachContext struct {
  1015  	ctx    context.Context
  1016  	cancel context.CancelFunc
  1017  	mu     sync.Mutex
  1018  }
  1019  
  1020  // InitAttachContext initializes or returns existing context for attach calls to
  1021  // track container liveness.
  1022  func (container *Container) InitAttachContext() context.Context {
  1023  	container.attachContext.mu.Lock()
  1024  	defer container.attachContext.mu.Unlock()
  1025  	if container.attachContext.ctx == nil {
  1026  		container.attachContext.ctx, container.attachContext.cancel = context.WithCancel(context.Background())
  1027  	}
  1028  	return container.attachContext.ctx
  1029  }
  1030  
  1031  // CancelAttachContext cancels attach context. All attach calls should detach
  1032  // after this call.
  1033  func (container *Container) CancelAttachContext() {
  1034  	container.attachContext.mu.Lock()
  1035  	if container.attachContext.ctx != nil {
  1036  		container.attachContext.cancel()
  1037  		container.attachContext.ctx = nil
  1038  	}
  1039  	container.attachContext.mu.Unlock()
  1040  }
  1041  
  1042  func (container *Container) startLogging() error {
  1043  	if container.HostConfig.LogConfig.Type == "none" {
  1044  		return nil // do not start logging routines
  1045  	}
  1046  
  1047  	l, err := container.StartLogger(container.HostConfig.LogConfig)
  1048  	if err != nil {
  1049  		return fmt.Errorf("Failed to initialize logging driver: %v", err)
  1050  	}
  1051  
  1052  	copier := logger.NewCopier(map[string]io.Reader{"stdout": container.StdoutPipe(), "stderr": container.StderrPipe()}, l)
  1053  	container.LogCopier = copier
  1054  	copier.Run()
  1055  	container.LogDriver = l
  1056  
  1057  	// set LogPath field only for json-file logdriver
  1058  	if jl, ok := l.(*jsonfilelog.JSONFileLogger); ok {
  1059  		container.LogPath = jl.LogPath()
  1060  	}
  1061  
  1062  	return nil
  1063  }
  1064  
  1065  // StdinPipe gets the stdin stream of the container
  1066  func (container *Container) StdinPipe() io.WriteCloser {
  1067  	return container.StreamConfig.StdinPipe()
  1068  }
  1069  
  1070  // StdoutPipe gets the stdout stream of the container
  1071  func (container *Container) StdoutPipe() io.ReadCloser {
  1072  	return container.StreamConfig.StdoutPipe()
  1073  }
  1074  
  1075  // StderrPipe gets the stderr stream of the container
  1076  func (container *Container) StderrPipe() io.ReadCloser {
  1077  	return container.StreamConfig.StderrPipe()
  1078  }
  1079  
  1080  // CloseStreams closes the container's stdio streams
  1081  func (container *Container) CloseStreams() error {
  1082  	return container.StreamConfig.CloseStreams()
  1083  }
  1084  
  1085  // InitializeStdio is called by libcontainerd to connect the stdio.
  1086  func (container *Container) InitializeStdio(iop libcontainerd.IOPipe) error {
  1087  	if err := container.startLogging(); err != nil {
  1088  		container.Reset(false)
  1089  		return err
  1090  	}
  1091  
  1092  	container.StreamConfig.CopyToPipe(iop)
  1093  
  1094  	if container.StreamConfig.Stdin() == nil && !container.Config.Tty {
  1095  		if iop.Stdin != nil {
  1096  			if err := iop.Stdin.Close(); err != nil {
  1097  				logrus.Warnf("error closing stdin: %+v", err)
  1098  			}
  1099  		}
  1100  	}
  1101  
  1102  	return nil
  1103  }