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 }