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 }