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