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