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