github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/engine/container/container.go (about) 1 package container // import "github.com/docker/docker/container" 2 3 import ( 4 "bytes" 5 "context" 6 "encoding/json" 7 "fmt" 8 "io" 9 "os" 10 "path/filepath" 11 "runtime" 12 "strings" 13 "sync" 14 "syscall" 15 "time" 16 17 "github.com/containerd/containerd/cio" 18 containertypes "github.com/docker/docker/api/types/container" 19 mounttypes "github.com/docker/docker/api/types/mount" 20 swarmtypes "github.com/docker/docker/api/types/swarm" 21 "github.com/docker/docker/container/stream" 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/logger/local" 26 "github.com/docker/docker/daemon/logger/loggerutils/cache" 27 "github.com/docker/docker/daemon/network" 28 "github.com/docker/docker/errdefs" 29 "github.com/docker/docker/image" 30 "github.com/docker/docker/layer" 31 "github.com/docker/docker/pkg/containerfs" 32 "github.com/docker/docker/pkg/idtools" 33 "github.com/docker/docker/pkg/ioutils" 34 "github.com/docker/docker/pkg/signal" 35 "github.com/docker/docker/pkg/system" 36 "github.com/docker/docker/restartmanager" 37 "github.com/docker/docker/volume" 38 volumemounts "github.com/docker/docker/volume/mounts" 39 units "github.com/docker/go-units" 40 agentexec "github.com/docker/swarmkit/agent/exec" 41 "github.com/moby/sys/symlink" 42 "github.com/pkg/errors" 43 "github.com/sirupsen/logrus" 44 ) 45 46 const configFileName = "config.v2.json" 47 48 // ExitStatus provides exit reasons for a container. 49 type ExitStatus struct { 50 // The exit code with which the container exited. 51 ExitCode int 52 53 // Whether the container encountered an OOM. 54 OOMKilled bool 55 56 // Time at which the container died 57 ExitedAt time.Time 58 } 59 60 // Container holds the structure defining a container object. 61 type Container struct { 62 StreamConfig *stream.Config 63 // embed for Container to support states directly. 64 *State `json:"State"` // Needed for Engine API version <= 1.11 65 Root string `json:"-"` // Path to the "home" of the container, including metadata. 66 BaseFS containerfs.ContainerFS `json:"-"` // interface containing graphdriver mount 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 OS string 80 // MountLabel contains the options for the 'mount' command 81 MountLabel string 82 ProcessLabel string 83 RestartCount int 84 HasBeenStartedBefore bool 85 HasBeenManuallyStopped bool // used for unless-stopped restart policy 86 MountPoints map[string]*volumemounts.MountPoint 87 HostConfig *containertypes.HostConfig `json:"-"` // do not serialize the host config in the json, otherwise we'll make the container unportable 88 ExecCommands *exec.Store `json:"-"` 89 DependencyStore agentexec.DependencyGetter `json:"-"` 90 SecretReferences []*swarmtypes.SecretReference 91 ConfigReferences []*swarmtypes.ConfigReference 92 // logDriver for closing 93 LogDriver logger.Logger `json:"-"` 94 LogCopier *logger.Copier `json:"-"` 95 restartManager restartmanager.RestartManager 96 attachContext *attachContext 97 98 // Fields here are specific to Unix platforms 99 AppArmorProfile string 100 HostnamePath string 101 HostsPath string 102 ShmPath string 103 ResolvConfPath string 104 SeccompProfile string 105 NoNewPrivileges bool 106 107 // Fields here are specific to Windows 108 NetworkSharedContainerID string `json:"-"` 109 SharedEndpointList []string `json:"-"` 110 LocalLogCacheMeta localLogCacheMeta `json:",omitempty"` 111 } 112 113 type localLogCacheMeta struct { 114 HaveNotifyEnabled bool 115 } 116 117 // NewBaseContainer creates a new container with its 118 // basic configuration. 119 func NewBaseContainer(id, root string) *Container { 120 return &Container{ 121 ID: id, 122 State: NewState(), 123 ExecCommands: exec.NewStore(), 124 Root: root, 125 MountPoints: make(map[string]*volumemounts.MountPoint), 126 StreamConfig: stream.NewConfig(), 127 attachContext: &attachContext{}, 128 } 129 } 130 131 // FromDisk loads the container configuration stored in the host. 132 func (container *Container) FromDisk() error { 133 pth, err := container.ConfigPath() 134 if err != nil { 135 return err 136 } 137 138 jsonSource, err := os.Open(pth) 139 if err != nil { 140 return err 141 } 142 defer jsonSource.Close() 143 144 dec := json.NewDecoder(jsonSource) 145 146 // Load container settings 147 if err := dec.Decode(container); err != nil { 148 return err 149 } 150 151 // Ensure the operating system is set if blank. Assume it is the OS of the 152 // host OS if not, to ensure containers created before multiple-OS 153 // support are migrated 154 if container.OS == "" { 155 container.OS = runtime.GOOS 156 } 157 158 return container.readHostConfig() 159 } 160 161 // toDisk saves the container configuration on disk and returns a deep copy. 162 func (container *Container) toDisk() (*Container, error) { 163 var ( 164 buf bytes.Buffer 165 deepCopy Container 166 ) 167 pth, err := container.ConfigPath() 168 if err != nil { 169 return nil, err 170 } 171 172 // Save container settings 173 f, err := ioutils.NewAtomicFileWriter(pth, 0600) 174 if err != nil { 175 return nil, err 176 } 177 defer f.Close() 178 179 w := io.MultiWriter(&buf, f) 180 if err := json.NewEncoder(w).Encode(container); err != nil { 181 return nil, err 182 } 183 184 if err := json.NewDecoder(&buf).Decode(&deepCopy); err != nil { 185 return nil, err 186 } 187 deepCopy.HostConfig, err = container.WriteHostConfig() 188 if err != nil { 189 return nil, err 190 } 191 192 return &deepCopy, nil 193 } 194 195 // CheckpointTo makes the Container's current state visible to queries, and persists state. 196 // Callers must hold a Container lock. 197 func (container *Container) CheckpointTo(store ViewDB) error { 198 deepCopy, err := container.toDisk() 199 if err != nil { 200 return err 201 } 202 return store.Save(deepCopy) 203 } 204 205 // readHostConfig reads the host configuration from disk for the container. 206 func (container *Container) readHostConfig() error { 207 container.HostConfig = &containertypes.HostConfig{} 208 // If the hostconfig file does not exist, do not read it. 209 // (We still have to initialize container.HostConfig, 210 // but that's OK, since we just did that above.) 211 pth, err := container.HostConfigPath() 212 if err != nil { 213 return err 214 } 215 216 f, err := os.Open(pth) 217 if err != nil { 218 if os.IsNotExist(err) { 219 return nil 220 } 221 return err 222 } 223 defer f.Close() 224 225 if err := json.NewDecoder(f).Decode(&container.HostConfig); err != nil { 226 return err 227 } 228 229 container.InitDNSHostConfig() 230 231 return nil 232 } 233 234 // WriteHostConfig saves the host configuration on disk for the container, 235 // and returns a deep copy of the saved object. Callers must hold a Container lock. 236 func (container *Container) WriteHostConfig() (*containertypes.HostConfig, error) { 237 var ( 238 buf bytes.Buffer 239 deepCopy containertypes.HostConfig 240 ) 241 242 pth, err := container.HostConfigPath() 243 if err != nil { 244 return nil, err 245 } 246 247 f, err := ioutils.NewAtomicFileWriter(pth, 0644) 248 if err != nil { 249 return nil, err 250 } 251 defer f.Close() 252 253 w := io.MultiWriter(&buf, f) 254 if err := json.NewEncoder(w).Encode(&container.HostConfig); err != nil { 255 return nil, err 256 } 257 258 if err := json.NewDecoder(&buf).Decode(&deepCopy); err != nil { 259 return nil, err 260 } 261 return &deepCopy, nil 262 } 263 264 // SetupWorkingDirectory sets up the container's working directory as set in container.Config.WorkingDir 265 func (container *Container) SetupWorkingDirectory(rootIdentity idtools.Identity) error { 266 // TODO: LCOW Support. This will need revisiting. 267 // We will need to do remote filesystem operations here. 268 if container.OS != runtime.GOOS { 269 return nil 270 } 271 272 if container.Config.WorkingDir == "" { 273 return nil 274 } 275 276 container.Config.WorkingDir = filepath.Clean(container.Config.WorkingDir) 277 pth, err := container.GetResourcePath(container.Config.WorkingDir) 278 if err != nil { 279 return err 280 } 281 282 if err := idtools.MkdirAllAndChownNew(pth, 0755, rootIdentity); err != nil { 283 pthInfo, err2 := os.Stat(pth) 284 if err2 == nil && pthInfo != nil && !pthInfo.IsDir() { 285 return errors.Errorf("Cannot mkdir: %s is not a directory", container.Config.WorkingDir) 286 } 287 288 return err 289 } 290 291 return nil 292 } 293 294 // GetResourcePath evaluates `path` in the scope of the container's BaseFS, with proper path 295 // sanitisation. Symlinks are all scoped to the BaseFS of the container, as 296 // though the container's BaseFS was `/`. 297 // 298 // The BaseFS of a container is the host-facing path which is bind-mounted as 299 // `/` inside the container. This method is essentially used to access a 300 // particular path inside the container as though you were a process in that 301 // container. 302 // 303 // # NOTE 304 // The returned path is *only* safely scoped inside the container's BaseFS 305 // if no component of the returned path changes (such as a component 306 // symlinking to a different path) between using this method and using the 307 // path. See symlink.FollowSymlinkInScope for more details. 308 func (container *Container) GetResourcePath(path string) (string, error) { 309 if container.BaseFS == nil { 310 return "", errors.New("GetResourcePath: BaseFS of container " + container.ID + " is unexpectedly nil") 311 } 312 // IMPORTANT - These are paths on the OS where the daemon is running, hence 313 // any filepath operations must be done in an OS agnostic way. 314 r, e := container.BaseFS.ResolveScopedPath(path, false) 315 316 // Log this here on the daemon side as there's otherwise no indication apart 317 // from the error being propagated all the way back to the client. This makes 318 // debugging significantly easier and clearly indicates the error comes from the daemon. 319 if e != nil { 320 logrus.Errorf("Failed to ResolveScopedPath BaseFS %s path %s %s\n", container.BaseFS.Path(), path, e) 321 } 322 return r, e 323 } 324 325 // GetRootResourcePath evaluates `path` in the scope of the container's root, with proper path 326 // sanitisation. Symlinks are all scoped to the root of the container, as 327 // though the container's root was `/`. 328 // 329 // The root of a container is the host-facing configuration metadata directory. 330 // Only use this method to safely access the container's `container.json` or 331 // other metadata files. If in doubt, use container.GetResourcePath. 332 // 333 // # NOTE 334 // The returned path is *only* safely scoped inside the container's root 335 // if no component of the returned path changes (such as a component 336 // symlinking to a different path) between using this method and using the 337 // path. See symlink.FollowSymlinkInScope for more details. 338 func (container *Container) GetRootResourcePath(path string) (string, error) { 339 // IMPORTANT - These are paths on the OS where the daemon is running, hence 340 // any filepath operations must be done in an OS agnostic way. 341 cleanPath := filepath.Join(string(os.PathSeparator), path) 342 return symlink.FollowSymlinkInScope(filepath.Join(container.Root, cleanPath), container.Root) 343 } 344 345 // ExitOnNext signals to the monitor that it should not restart the container 346 // after we send the kill signal. 347 func (container *Container) ExitOnNext() { 348 container.RestartManager().Cancel() 349 } 350 351 // HostConfigPath returns the path to the container's JSON hostconfig 352 func (container *Container) HostConfigPath() (string, error) { 353 return container.GetRootResourcePath("hostconfig.json") 354 } 355 356 // ConfigPath returns the path to the container's JSON config 357 func (container *Container) ConfigPath() (string, error) { 358 return container.GetRootResourcePath(configFileName) 359 } 360 361 // CheckpointDir returns the directory checkpoints are stored in 362 func (container *Container) CheckpointDir() string { 363 return filepath.Join(container.Root, "checkpoints") 364 } 365 366 // StartLogger starts a new logger driver for the container. 367 func (container *Container) StartLogger() (logger.Logger, error) { 368 cfg := container.HostConfig.LogConfig 369 initDriver, err := logger.GetLogDriver(cfg.Type) 370 if err != nil { 371 return nil, errors.Wrap(err, "failed to get logging factory") 372 } 373 info := logger.Info{ 374 Config: cfg.Config, 375 ContainerID: container.ID, 376 ContainerName: container.Name, 377 ContainerEntrypoint: container.Path, 378 ContainerArgs: container.Args, 379 ContainerImageID: container.ImageID.String(), 380 ContainerImageName: container.Config.Image, 381 ContainerCreated: container.Created, 382 ContainerEnv: container.Config.Env, 383 ContainerLabels: container.Config.Labels, 384 DaemonName: "docker", 385 } 386 387 // Set logging file for "json-logger" 388 // TODO(@cpuguy83): Setup here based on log driver is a little weird. 389 switch cfg.Type { 390 case jsonfilelog.Name: 391 info.LogPath, err = container.GetRootResourcePath(fmt.Sprintf("%s-json.log", container.ID)) 392 if err != nil { 393 return nil, err 394 } 395 396 container.LogPath = info.LogPath 397 case local.Name: 398 // Do not set container.LogPath for the local driver 399 // This would expose the value to the API, which should not be done as it means 400 // that the log file implementation would become a stable API that cannot change. 401 logDir, err := container.GetRootResourcePath("local-logs") 402 if err != nil { 403 return nil, err 404 } 405 if err := os.MkdirAll(logDir, 0700); err != nil { 406 return nil, errdefs.System(errors.Wrap(err, "error creating local logs dir")) 407 } 408 info.LogPath = filepath.Join(logDir, "container.log") 409 } 410 411 l, err := initDriver(info) 412 if err != nil { 413 return nil, err 414 } 415 416 if containertypes.LogMode(cfg.Config["mode"]) == containertypes.LogModeNonBlock { 417 bufferSize := int64(-1) 418 if s, exists := cfg.Config["max-buffer-size"]; exists { 419 bufferSize, err = units.RAMInBytes(s) 420 if err != nil { 421 return nil, err 422 } 423 } 424 l = logger.NewRingLogger(l, info, bufferSize) 425 } 426 427 if _, ok := l.(logger.LogReader); !ok { 428 if cache.ShouldUseCache(cfg.Config) { 429 logPath, err := container.GetRootResourcePath("container-cached.log") 430 if err != nil { 431 return nil, err 432 } 433 434 if !container.LocalLogCacheMeta.HaveNotifyEnabled { 435 logrus.WithField("container", container.ID).WithField("driver", container.HostConfig.LogConfig.Type).Info("Configured log driver does not support reads, enabling local file cache for container logs") 436 container.LocalLogCacheMeta.HaveNotifyEnabled = true 437 } 438 info.LogPath = logPath 439 l, err = cache.WithLocalCache(l, info) 440 if err != nil { 441 return nil, errors.Wrap(err, "error setting up local container log cache") 442 } 443 } 444 } 445 return l, nil 446 } 447 448 // GetProcessLabel returns the process label for the container. 449 func (container *Container) GetProcessLabel() string { 450 // even if we have a process label return "" if we are running 451 // in privileged mode 452 if container.HostConfig.Privileged { 453 return "" 454 } 455 return container.ProcessLabel 456 } 457 458 // GetMountLabel returns the mounting label for the container. 459 // This label is empty if the container is privileged. 460 func (container *Container) GetMountLabel() string { 461 return container.MountLabel 462 } 463 464 // GetExecIDs returns the list of exec commands running on the container. 465 func (container *Container) GetExecIDs() []string { 466 return container.ExecCommands.List() 467 } 468 469 // ShouldRestart decides whether the daemon should restart the container or not. 470 // This is based on the container's restart policy. 471 func (container *Container) ShouldRestart() bool { 472 shouldRestart, _, _ := container.RestartManager().ShouldRestart(uint32(container.ExitCode()), container.HasBeenManuallyStopped, container.FinishedAt.Sub(container.StartedAt)) 473 return shouldRestart 474 } 475 476 // AddMountPointWithVolume adds a new mount point configured with a volume to the container. 477 func (container *Container) AddMountPointWithVolume(destination string, vol volume.Volume, rw bool) { 478 operatingSystem := container.OS 479 if operatingSystem == "" { 480 operatingSystem = runtime.GOOS 481 } 482 volumeParser := volumemounts.NewParser(operatingSystem) 483 container.MountPoints[destination] = &volumemounts.MountPoint{ 484 Type: mounttypes.TypeVolume, 485 Name: vol.Name(), 486 Driver: vol.DriverName(), 487 Destination: destination, 488 RW: rw, 489 Volume: vol, 490 CopyData: volumeParser.DefaultCopyMode(), 491 } 492 } 493 494 // UnmountVolumes unmounts all volumes 495 func (container *Container) UnmountVolumes(volumeEventLog func(name, action string, attributes map[string]string)) error { 496 var errors []string 497 for _, volumeMount := range container.MountPoints { 498 if volumeMount.Volume == nil { 499 continue 500 } 501 502 if err := volumeMount.Cleanup(); err != nil { 503 errors = append(errors, err.Error()) 504 continue 505 } 506 507 attributes := map[string]string{ 508 "driver": volumeMount.Volume.DriverName(), 509 "container": container.ID, 510 } 511 volumeEventLog(volumeMount.Volume.Name(), "unmount", attributes) 512 } 513 if len(errors) > 0 { 514 return fmt.Errorf("error while unmounting volumes for container %s: %s", container.ID, strings.Join(errors, "; ")) 515 } 516 return nil 517 } 518 519 // IsDestinationMounted checks whether a path is mounted on the container or not. 520 func (container *Container) IsDestinationMounted(destination string) bool { 521 return container.MountPoints[destination] != nil 522 } 523 524 // StopSignal returns the signal used to stop the container. 525 func (container *Container) StopSignal() int { 526 var stopSignal syscall.Signal 527 if container.Config.StopSignal != "" { 528 stopSignal, _ = signal.ParseSignal(container.Config.StopSignal) 529 } 530 531 if int(stopSignal) == 0 { 532 stopSignal, _ = signal.ParseSignal(signal.DefaultStopSignal) 533 } 534 return int(stopSignal) 535 } 536 537 // StopTimeout returns the timeout (in seconds) used to stop the container. 538 func (container *Container) StopTimeout() int { 539 if container.Config.StopTimeout != nil { 540 return *container.Config.StopTimeout 541 } 542 return DefaultStopTimeout 543 } 544 545 // InitDNSHostConfig ensures that the dns fields are never nil. 546 // New containers don't ever have those fields nil, 547 // but pre created containers can still have those nil values. 548 // The non-recommended host configuration in the start api can 549 // make these fields nil again, this corrects that issue until 550 // we remove that behavior for good. 551 // See https://github.com/docker/docker/pull/17779 552 // for a more detailed explanation on why we don't want that. 553 func (container *Container) InitDNSHostConfig() { 554 container.Lock() 555 defer container.Unlock() 556 if container.HostConfig.DNS == nil { 557 container.HostConfig.DNS = make([]string, 0) 558 } 559 560 if container.HostConfig.DNSSearch == nil { 561 container.HostConfig.DNSSearch = make([]string, 0) 562 } 563 564 if container.HostConfig.DNSOptions == nil { 565 container.HostConfig.DNSOptions = make([]string, 0) 566 } 567 } 568 569 // UpdateMonitor updates monitor configure for running container 570 func (container *Container) UpdateMonitor(restartPolicy containertypes.RestartPolicy) { 571 type policySetter interface { 572 SetPolicy(containertypes.RestartPolicy) 573 } 574 575 if rm, ok := container.RestartManager().(policySetter); ok { 576 rm.SetPolicy(restartPolicy) 577 } 578 } 579 580 // FullHostname returns hostname and optional domain appended to it. 581 func (container *Container) FullHostname() string { 582 fullHostname := container.Config.Hostname 583 if container.Config.Domainname != "" { 584 fullHostname = fmt.Sprintf("%s.%s", fullHostname, container.Config.Domainname) 585 } 586 return fullHostname 587 } 588 589 // RestartManager returns the current restartmanager instance connected to container. 590 func (container *Container) RestartManager() restartmanager.RestartManager { 591 if container.restartManager == nil { 592 container.restartManager = restartmanager.New(container.HostConfig.RestartPolicy, container.RestartCount) 593 } 594 return container.restartManager 595 } 596 597 // ResetRestartManager initializes new restartmanager based on container config 598 func (container *Container) ResetRestartManager(resetCount bool) { 599 if container.restartManager != nil { 600 container.restartManager.Cancel() 601 } 602 if resetCount { 603 container.RestartCount = 0 604 } 605 container.restartManager = nil 606 } 607 608 type attachContext struct { 609 ctx context.Context 610 cancel context.CancelFunc 611 mu sync.Mutex 612 } 613 614 // InitAttachContext initializes or returns existing context for attach calls to 615 // track container liveness. 616 func (container *Container) InitAttachContext() context.Context { 617 container.attachContext.mu.Lock() 618 defer container.attachContext.mu.Unlock() 619 if container.attachContext.ctx == nil { 620 container.attachContext.ctx, container.attachContext.cancel = context.WithCancel(context.Background()) 621 } 622 return container.attachContext.ctx 623 } 624 625 // CancelAttachContext cancels attach context. All attach calls should detach 626 // after this call. 627 func (container *Container) CancelAttachContext() { 628 container.attachContext.mu.Lock() 629 if container.attachContext.ctx != nil { 630 container.attachContext.cancel() 631 container.attachContext.ctx = nil 632 } 633 container.attachContext.mu.Unlock() 634 } 635 636 func (container *Container) startLogging() error { 637 if container.HostConfig.LogConfig.Type == "none" { 638 return nil // do not start logging routines 639 } 640 641 l, err := container.StartLogger() 642 if err != nil { 643 return fmt.Errorf("failed to initialize logging driver: %v", err) 644 } 645 646 copier := logger.NewCopier(map[string]io.Reader{"stdout": container.StdoutPipe(), "stderr": container.StderrPipe()}, l) 647 container.LogCopier = copier 648 copier.Run() 649 container.LogDriver = l 650 651 return nil 652 } 653 654 // StdinPipe gets the stdin stream of the container 655 func (container *Container) StdinPipe() io.WriteCloser { 656 return container.StreamConfig.StdinPipe() 657 } 658 659 // StdoutPipe gets the stdout stream of the container 660 func (container *Container) StdoutPipe() io.ReadCloser { 661 return container.StreamConfig.StdoutPipe() 662 } 663 664 // StderrPipe gets the stderr stream of the container 665 func (container *Container) StderrPipe() io.ReadCloser { 666 return container.StreamConfig.StderrPipe() 667 } 668 669 // CloseStreams closes the container's stdio streams 670 func (container *Container) CloseStreams() error { 671 return container.StreamConfig.CloseStreams() 672 } 673 674 // InitializeStdio is called by libcontainerd to connect the stdio. 675 func (container *Container) InitializeStdio(iop *cio.DirectIO) (cio.IO, error) { 676 if err := container.startLogging(); err != nil { 677 container.Reset(false) 678 return nil, err 679 } 680 681 container.StreamConfig.CopyToPipe(iop) 682 683 if container.StreamConfig.Stdin() == nil && !container.Config.Tty { 684 if iop.Stdin != nil { 685 if err := iop.Stdin.Close(); err != nil { 686 logrus.Warnf("error closing stdin: %+v", err) 687 } 688 } 689 } 690 691 return &rio{IO: iop, sc: container.StreamConfig}, nil 692 } 693 694 // MountsResourcePath returns the path where mounts are stored for the given mount 695 func (container *Container) MountsResourcePath(mount string) (string, error) { 696 return container.GetRootResourcePath(filepath.Join("mounts", mount)) 697 } 698 699 // SecretMountPath returns the path of the secret mount for the container 700 func (container *Container) SecretMountPath() (string, error) { 701 return container.MountsResourcePath("secrets") 702 } 703 704 // SecretFilePath returns the path to the location of a secret on the host. 705 func (container *Container) SecretFilePath(secretRef swarmtypes.SecretReference) (string, error) { 706 secrets, err := container.SecretMountPath() 707 if err != nil { 708 return "", err 709 } 710 return filepath.Join(secrets, secretRef.SecretID), nil 711 } 712 713 func getSecretTargetPath(r *swarmtypes.SecretReference) string { 714 if filepath.IsAbs(r.File.Name) { 715 return r.File.Name 716 } 717 718 return filepath.Join(containerSecretMountPath, r.File.Name) 719 } 720 721 // getConfigTargetPath makes sure that config paths inside the container are 722 // absolute, as required by the runtime spec, and enforced by runc >= 1.0.0-rc94. 723 // see https://github.com/opencontainers/runc/issues/2928 724 func getConfigTargetPath(r *swarmtypes.ConfigReference) string { 725 if filepath.IsAbs(r.File.Name) { 726 return r.File.Name 727 } 728 729 return filepath.Join(containerConfigMountPath, r.File.Name) 730 } 731 732 // CreateDaemonEnvironment creates a new environment variable slice for this container. 733 func (container *Container) CreateDaemonEnvironment(tty bool, linkedEnv []string) []string { 734 // Setup environment 735 os := container.OS 736 if os == "" { 737 os = runtime.GOOS 738 } 739 740 // Figure out what size slice we need so we can allocate this all at once. 741 envSize := len(container.Config.Env) 742 if runtime.GOOS != "windows" || (runtime.GOOS == "windows" && os == "linux") { 743 envSize += 2 + len(linkedEnv) 744 } 745 if tty { 746 envSize++ 747 } 748 749 env := make([]string, 0, envSize) 750 if runtime.GOOS != "windows" || (runtime.GOOS == "windows" && os == "linux") { 751 env = append(env, "PATH="+system.DefaultPathEnv(os)) 752 env = append(env, "HOSTNAME="+container.Config.Hostname) 753 if tty { 754 env = append(env, "TERM=xterm") 755 } 756 env = append(env, linkedEnv...) 757 } 758 759 // because the env on the container can override certain default values 760 // we need to replace the 'env' keys where they match and append anything 761 // else. 762 env = ReplaceOrAppendEnvValues(env, container.Config.Env) 763 return env 764 } 765 766 type rio struct { 767 cio.IO 768 769 sc *stream.Config 770 } 771 772 func (i *rio) Close() error { 773 i.IO.Close() 774 775 return i.sc.CloseStreams() 776 } 777 778 func (i *rio) Wait() { 779 i.sc.Wait(context.Background()) 780 781 i.IO.Wait() 782 }