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