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