github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/libpod/container.go (about) 1 package libpod 2 3 import ( 4 "bytes" 5 "fmt" 6 "io/ioutil" 7 "net" 8 "os" 9 "time" 10 11 "github.com/containernetworking/cni/pkg/types" 12 cnitypes "github.com/containernetworking/cni/pkg/types/current" 13 "github.com/containers/image/v5/manifest" 14 "github.com/containers/podman/v2/libpod/define" 15 "github.com/containers/podman/v2/libpod/lock" 16 "github.com/containers/podman/v2/pkg/rootless" 17 "github.com/containers/storage" 18 "github.com/cri-o/ocicni/pkg/ocicni" 19 spec "github.com/opencontainers/runtime-spec/specs-go" 20 "github.com/pkg/errors" 21 "github.com/sirupsen/logrus" 22 ) 23 24 // CgroupfsDefaultCgroupParent is the cgroup parent for CGroupFS in libpod 25 const CgroupfsDefaultCgroupParent = "/libpod_parent" 26 27 // SystemdDefaultCgroupParent is the cgroup parent for the systemd cgroup 28 // manager in libpod 29 const SystemdDefaultCgroupParent = "machine.slice" 30 31 // SystemdDefaultRootlessCgroupParent is the cgroup parent for the systemd cgroup 32 // manager in libpod when running as rootless 33 const SystemdDefaultRootlessCgroupParent = "user.slice" 34 35 // DefaultWaitInterval is the default interval between container status checks 36 // while waiting. 37 const DefaultWaitInterval = 250 * time.Millisecond 38 39 // LinuxNS represents a Linux namespace 40 type LinuxNS int 41 42 const ( 43 // InvalidNS is an invalid namespace 44 InvalidNS LinuxNS = iota 45 // IPCNS is the IPC namespace 46 IPCNS LinuxNS = iota 47 // MountNS is the mount namespace 48 MountNS LinuxNS = iota 49 // NetNS is the network namespace 50 NetNS LinuxNS = iota 51 // PIDNS is the PID namespace 52 PIDNS LinuxNS = iota 53 // UserNS is the user namespace 54 UserNS LinuxNS = iota 55 // UTSNS is the UTS namespace 56 UTSNS LinuxNS = iota 57 // CgroupNS is the CGroup namespace 58 CgroupNS LinuxNS = iota 59 ) 60 61 // String returns a string representation of a Linux namespace 62 // It is guaranteed to be the name of the namespace in /proc for valid ns types 63 func (ns LinuxNS) String() string { 64 switch ns { 65 case InvalidNS: 66 return "invalid" 67 case IPCNS: 68 return "ipc" 69 case MountNS: 70 return "mnt" 71 case NetNS: 72 return "net" 73 case PIDNS: 74 return "pid" 75 case UserNS: 76 return "user" 77 case UTSNS: 78 return "uts" 79 case CgroupNS: 80 return "cgroup" 81 default: 82 return "unknown" 83 } 84 } 85 86 // Valid restart policy types. 87 const ( 88 // RestartPolicyNone indicates that no restart policy has been requested 89 // by a container. 90 RestartPolicyNone = "" 91 // RestartPolicyNo is identical in function to RestartPolicyNone. 92 RestartPolicyNo = "no" 93 // RestartPolicyAlways unconditionally restarts the container. 94 RestartPolicyAlways = "always" 95 // RestartPolicyOnFailure restarts the container on non-0 exit code, 96 // with an optional maximum number of retries. 97 RestartPolicyOnFailure = "on-failure" 98 // RestartPolicyUnlessStopped unconditionally restarts unless stopped 99 // by the user. It is identical to Always except with respect to 100 // handling of system restart, which Podman does not yet support. 101 RestartPolicyUnlessStopped = "unless-stopped" 102 ) 103 104 // Container is a single OCI container. 105 // All operations on a Container that access state must begin with a call to 106 // syncContainer(). 107 // There is no guarantee that state exists in a readable state before 108 // syncContainer() is run, and even if it does, its contents will be out of date 109 // and must be refreshed from the database. 110 // Generally, this requirement applies only to top-level functions; helpers can 111 // assume that their callers handled this requirement. Generally speaking, if a 112 // function takes the container lock and accesses any part of state, it should 113 // syncContainer() immediately after locking. 114 type Container struct { 115 config *ContainerConfig 116 117 state *ContainerState 118 119 // Batched indicates that a container has been locked as part of a 120 // Batch() operation 121 // Functions called on a batched container will not lock or sync 122 batched bool 123 124 valid bool 125 lock lock.Locker 126 runtime *Runtime 127 ociRuntime OCIRuntime 128 129 rootlessSlirpSyncR *os.File 130 rootlessSlirpSyncW *os.File 131 132 rootlessPortSyncR *os.File 133 rootlessPortSyncW *os.File 134 135 // A restored container should have the same IP address as before 136 // being checkpointed. If requestedIP is set it will be used instead 137 // of config.StaticIP. 138 requestedIP net.IP 139 // A restored container should have the same MAC address as before 140 // being checkpointed. If requestedMAC is set it will be used instead 141 // of config.StaticMAC. 142 requestedMAC net.HardwareAddr 143 144 // This is true if a container is restored from a checkpoint. 145 restoreFromCheckpoint bool 146 } 147 148 // ContainerState contains the current state of the container 149 // It is stored on disk in a tmpfs and recreated on reboot 150 type ContainerState struct { 151 // The current state of the running container 152 State define.ContainerStatus `json:"state"` 153 // The path to the JSON OCI runtime spec for this container 154 ConfigPath string `json:"configPath,omitempty"` 155 // RunDir is a per-boot directory for container content 156 RunDir string `json:"runDir,omitempty"` 157 // Mounted indicates whether the container's storage has been mounted 158 // for use 159 Mounted bool `json:"mounted,omitempty"` 160 // Mountpoint contains the path to the container's mounted storage as given 161 // by containers/storage. 162 Mountpoint string `json:"mountPoint,omitempty"` 163 // StartedTime is the time the container was started 164 StartedTime time.Time `json:"startedTime,omitempty"` 165 // FinishedTime is the time the container finished executing 166 FinishedTime time.Time `json:"finishedTime,omitempty"` 167 // ExitCode is the exit code returned when the container stopped 168 ExitCode int32 `json:"exitCode,omitempty"` 169 // Exited is whether the container has exited 170 Exited bool `json:"exited,omitempty"` 171 // OOMKilled indicates that the container was killed as it ran out of 172 // memory 173 OOMKilled bool `json:"oomKilled,omitempty"` 174 // PID is the PID of a running container 175 PID int `json:"pid,omitempty"` 176 // ConmonPID is the PID of the container's conmon 177 ConmonPID int `json:"conmonPid,omitempty"` 178 // ExecSessions contains all exec sessions that are associated with this 179 // container. 180 ExecSessions map[string]*ExecSession `json:"newExecSessions,omitempty"` 181 // LegacyExecSessions are legacy exec sessions from older versions of 182 // Podman. 183 // These are DEPRECATED and will be removed in a future release. 184 LegacyExecSessions map[string]*legacyExecSession `json:"execSessions,omitempty"` 185 // NetworkStatus contains the configuration results for all networks 186 // the pod is attached to. Only populated if we created a network 187 // namespace for the container, and the network namespace is currently 188 // active 189 NetworkStatus []*cnitypes.Result `json:"networkResults,omitempty"` 190 // BindMounts contains files that will be bind-mounted into the 191 // container when it is mounted. 192 // These include /etc/hosts and /etc/resolv.conf 193 // This maps the path the file will be mounted to in the container to 194 // the path of the file on disk outside the container 195 BindMounts map[string]string `json:"bindMounts,omitempty"` 196 // StoppedByUser indicates whether the container was stopped by an 197 // explicit call to the Stop() API. 198 StoppedByUser bool `json:"stoppedByUser,omitempty"` 199 // RestartPolicyMatch indicates whether the conditions for restart 200 // policy have been met. 201 RestartPolicyMatch bool `json:"restartPolicyMatch,omitempty"` 202 // RestartCount is how many times the container was restarted by its 203 // restart policy. This is NOT incremented by normal container restarts 204 // (only by restart policy). 205 RestartCount uint `json:"restartCount,omitempty"` 206 207 // ExtensionStageHooks holds hooks which will be executed by libpod 208 // and not delegated to the OCI runtime. 209 ExtensionStageHooks map[string][]spec.Hook `json:"extensionStageHooks,omitempty"` 210 211 // NetInterfaceDescriptions describe the relationship between a CNI 212 // network and an interface names 213 NetInterfaceDescriptions ContainerNetworkDescriptions `json:"networkDescriptions,omitempty"` 214 215 // containerPlatformState holds platform-specific container state. 216 containerPlatformState 217 } 218 219 // ContainerNamedVolume is a named volume that will be mounted into the 220 // container. Each named volume is a libpod Volume present in the state. 221 type ContainerNamedVolume struct { 222 // Name is the name of the volume to mount in. 223 // Must resolve to a valid volume present in this Podman. 224 Name string `json:"volumeName"` 225 // Dest is the mount's destination 226 Dest string `json:"dest"` 227 // Options are fstab style mount options 228 Options []string `json:"options,omitempty"` 229 } 230 231 // ContainerOverlayVolume is a overlay volume that will be mounted into the 232 // container. Each volume is a libpod Volume present in the state. 233 type ContainerOverlayVolume struct { 234 // Destination is the absolute path where the mount will be placed in the container. 235 Dest string `json:"dest"` 236 // Source specifies the source path of the mount. 237 Source string `json:"source,omitempty"` 238 } 239 240 // ContainerImageVolume is a volume based on a container image. The container 241 // image is first mounted on the host and is then bind-mounted into the 242 // container. 243 type ContainerImageVolume struct { 244 // Source is the source of the image volume. The image can be referred 245 // to by name and by ID. 246 Source string `json:"source"` 247 // Dest is the absolute path of the mount in the container. 248 Dest string `json:"dest"` 249 // ReadWrite sets the volume writable. 250 ReadWrite bool `json:"rw"` 251 } 252 253 // ContainerNetworkDescriptions describes the relationship between the CNI 254 // network and the ethN where N is an integer 255 type ContainerNetworkDescriptions map[string]int 256 257 // Config accessors 258 // Unlocked 259 260 // Config returns the configuration used to create the container 261 func (c *Container) Config() *ContainerConfig { 262 returnConfig := new(ContainerConfig) 263 if err := JSONDeepCopy(c.config, returnConfig); err != nil { 264 return nil 265 } 266 267 return returnConfig 268 } 269 270 // Spec returns the container's OCI runtime spec 271 // The spec returned is the one used to create the container. The running 272 // spec may differ slightly as mounts are added based on the image 273 func (c *Container) Spec() *spec.Spec { 274 returnSpec := new(spec.Spec) 275 if err := JSONDeepCopy(c.config.Spec, returnSpec); err != nil { 276 return nil 277 } 278 279 return returnSpec 280 } 281 282 // specFromState returns the unmarshalled json config of the container. If the 283 // config does not exist (e.g., because the container was never started) return 284 // the spec from the config. 285 func (c *Container) specFromState() (*spec.Spec, error) { 286 returnSpec := c.config.Spec 287 288 if f, err := os.Open(c.state.ConfigPath); err == nil { 289 returnSpec = new(spec.Spec) 290 content, err := ioutil.ReadAll(f) 291 if err != nil { 292 return nil, errors.Wrapf(err, "error reading container config") 293 } 294 if err := json.Unmarshal(content, &returnSpec); err != nil { 295 return nil, errors.Wrapf(err, "error unmarshalling container config") 296 } 297 } else if !os.IsNotExist(err) { 298 // ignore when the file does not exist 299 return nil, errors.Wrapf(err, "error opening container config") 300 } 301 302 return returnSpec, nil 303 } 304 305 // ID returns the container's ID 306 func (c *Container) ID() string { 307 return c.config.ID 308 } 309 310 // Name returns the container's name 311 func (c *Container) Name() string { 312 return c.config.Name 313 } 314 315 // PodID returns the full ID of the pod the container belongs to, or "" if it 316 // does not belong to a pod 317 func (c *Container) PodID() string { 318 return c.config.Pod 319 } 320 321 // Namespace returns the libpod namespace the container is in. 322 // Namespaces are used to logically separate containers and pods in the state. 323 func (c *Container) Namespace() string { 324 return c.config.Namespace 325 } 326 327 // Image returns the ID and name of the image used as the container's rootfs. 328 func (c *Container) Image() (string, string) { 329 return c.config.RootfsImageID, c.config.RootfsImageName 330 } 331 332 // RawImageName returns the unprocessed and not-normalized user-specified image 333 // name. 334 func (c *Container) RawImageName() string { 335 return c.config.RawImageName 336 } 337 338 // ShmDir returns the sources path to be mounted on /dev/shm in container 339 func (c *Container) ShmDir() string { 340 return c.config.ShmDir 341 } 342 343 // ShmSize returns the size of SHM device to be mounted into the container 344 func (c *Container) ShmSize() int64 { 345 return c.config.ShmSize 346 } 347 348 // StaticDir returns the directory used to store persistent container files 349 func (c *Container) StaticDir() string { 350 return c.config.StaticDir 351 } 352 353 // NamedVolumes returns the container's named volumes. 354 // The name of each is guaranteed to point to a valid libpod Volume present in 355 // the state. 356 func (c *Container) NamedVolumes() []*ContainerNamedVolume { 357 volumes := []*ContainerNamedVolume{} 358 for _, vol := range c.config.NamedVolumes { 359 newVol := new(ContainerNamedVolume) 360 newVol.Name = vol.Name 361 newVol.Dest = vol.Dest 362 newVol.Options = vol.Options 363 volumes = append(volumes, newVol) 364 } 365 366 return volumes 367 } 368 369 // Privileged returns whether the container is privileged 370 func (c *Container) Privileged() bool { 371 return c.config.Privileged 372 } 373 374 // ProcessLabel returns the selinux ProcessLabel of the container 375 func (c *Container) ProcessLabel() string { 376 return c.config.ProcessLabel 377 } 378 379 // MountLabel returns the SELinux mount label of the container 380 func (c *Container) MountLabel() string { 381 return c.config.MountLabel 382 } 383 384 // Systemd returns whether the container will be running in systemd mode 385 func (c *Container) Systemd() bool { 386 return c.config.Systemd 387 } 388 389 // User returns the user who the container is run as 390 func (c *Container) User() string { 391 return c.config.User 392 } 393 394 // Dependencies gets the containers this container depends upon 395 func (c *Container) Dependencies() []string { 396 // Collect in a map first to remove dupes 397 dependsCtrs := map[string]bool{} 398 399 // First add all namespace containers 400 if c.config.IPCNsCtr != "" { 401 dependsCtrs[c.config.IPCNsCtr] = true 402 } 403 if c.config.MountNsCtr != "" { 404 dependsCtrs[c.config.MountNsCtr] = true 405 } 406 if c.config.NetNsCtr != "" { 407 dependsCtrs[c.config.NetNsCtr] = true 408 } 409 if c.config.PIDNsCtr != "" { 410 dependsCtrs[c.config.PIDNsCtr] = true 411 } 412 if c.config.UserNsCtr != "" { 413 dependsCtrs[c.config.UserNsCtr] = true 414 } 415 if c.config.UTSNsCtr != "" { 416 dependsCtrs[c.config.UTSNsCtr] = true 417 } 418 if c.config.CgroupNsCtr != "" { 419 dependsCtrs[c.config.CgroupNsCtr] = true 420 } 421 422 // Add all generic dependencies 423 for _, id := range c.config.Dependencies { 424 dependsCtrs[id] = true 425 } 426 427 if len(dependsCtrs) == 0 { 428 return []string{} 429 } 430 431 depends := make([]string, 0, len(dependsCtrs)) 432 for ctr := range dependsCtrs { 433 depends = append(depends, ctr) 434 } 435 436 return depends 437 } 438 439 // NewNetNS returns whether the container will create a new network namespace 440 func (c *Container) NewNetNS() bool { 441 return c.config.CreateNetNS 442 } 443 444 // PortMappings returns the ports that will be mapped into a container if 445 // a new network namespace is created 446 // If NewNetNS() is false, this value is unused 447 func (c *Container) PortMappings() ([]ocicni.PortMapping, error) { 448 // First check if the container belongs to a network namespace (like a pod) 449 if len(c.config.NetNsCtr) > 0 { 450 netNsCtr, err := c.runtime.GetContainer(c.config.NetNsCtr) 451 if err != nil { 452 return nil, errors.Wrapf(err, "unable to lookup network namespace for container %s", c.ID()) 453 } 454 return netNsCtr.PortMappings() 455 } 456 return c.config.PortMappings, nil 457 } 458 459 // DNSServers returns DNS servers that will be used in the container's 460 // resolv.conf 461 // If empty, DNS server from the host's resolv.conf will be used instead 462 func (c *Container) DNSServers() []net.IP { 463 return c.config.DNSServer 464 } 465 466 // DNSSearch returns the DNS search domains that will be used in the container's 467 // resolv.conf 468 // If empty, DNS Search domains from the host's resolv.conf will be used instead 469 func (c *Container) DNSSearch() []string { 470 return c.config.DNSSearch 471 } 472 473 // DNSOption returns the DNS options that will be used in the container's 474 // resolv.conf 475 // If empty, options from the host's resolv.conf will be used instead 476 func (c *Container) DNSOption() []string { 477 return c.config.DNSOption 478 } 479 480 // HostsAdd returns hosts that will be added to the container's hosts file 481 // The host system's hosts file is used as a base, and these are appended to it 482 func (c *Container) HostsAdd() []string { 483 return c.config.HostAdd 484 } 485 486 // UserVolumes returns user-added volume mounts in the container. 487 // These are not added to the spec, but are used during image commit and to 488 // trigger some OCI hooks. 489 func (c *Container) UserVolumes() []string { 490 volumes := make([]string, 0, len(c.config.UserVolumes)) 491 volumes = append(volumes, c.config.UserVolumes...) 492 return volumes 493 } 494 495 // Entrypoint is the container's entrypoint. 496 // This is not added to the spec, but is instead used during image commit. 497 func (c *Container) Entrypoint() []string { 498 entrypoint := make([]string, 0, len(c.config.Entrypoint)) 499 entrypoint = append(entrypoint, c.config.Entrypoint...) 500 return entrypoint 501 } 502 503 // Command is the container's command 504 // This is not added to the spec, but is instead used during image commit 505 func (c *Container) Command() []string { 506 command := make([]string, 0, len(c.config.Command)) 507 command = append(command, c.config.Command...) 508 return command 509 } 510 511 // Stdin returns whether STDIN on the container will be kept open 512 func (c *Container) Stdin() bool { 513 return c.config.Stdin 514 } 515 516 // Labels returns the container's labels 517 func (c *Container) Labels() map[string]string { 518 labels := make(map[string]string) 519 for key, value := range c.config.Labels { 520 labels[key] = value 521 } 522 return labels 523 } 524 525 // StopSignal is the signal that will be used to stop the container 526 // If it fails to stop the container, SIGKILL will be used after a timeout 527 // If StopSignal is 0, the default signal of SIGTERM will be used 528 func (c *Container) StopSignal() uint { 529 return c.config.StopSignal 530 } 531 532 // StopTimeout returns the container's stop timeout 533 // If the container's default stop signal fails to kill the container, SIGKILL 534 // will be used after this timeout 535 func (c *Container) StopTimeout() uint { 536 return c.config.StopTimeout 537 } 538 539 // CreatedTime gets the time when the container was created 540 func (c *Container) CreatedTime() time.Time { 541 return c.config.CreatedTime 542 } 543 544 // CgroupParent gets the container's CGroup parent 545 func (c *Container) CgroupParent() string { 546 return c.config.CgroupParent 547 } 548 549 // LogPath returns the path to the container's log file 550 // This file will only be present after Init() is called to create the container 551 // in the runtime 552 func (c *Container) LogPath() string { 553 return c.config.LogPath 554 } 555 556 // LogTag returns the tag to the container's log file 557 func (c *Container) LogTag() string { 558 return c.config.LogTag 559 } 560 561 // RestartPolicy returns the container's restart policy. 562 func (c *Container) RestartPolicy() string { 563 return c.config.RestartPolicy 564 } 565 566 // RestartRetries returns the number of retries that will be attempted when 567 // using the "on-failure" restart policy 568 func (c *Container) RestartRetries() uint { 569 return c.config.RestartRetries 570 } 571 572 // LogDriver returns the log driver for this container 573 func (c *Container) LogDriver() string { 574 return c.config.LogDriver 575 } 576 577 // RuntimeName returns the name of the runtime 578 func (c *Container) RuntimeName() string { 579 return c.config.OCIRuntime 580 } 581 582 // Runtime spec accessors 583 // Unlocked 584 585 // Hostname gets the container's hostname 586 func (c *Container) Hostname() string { 587 if c.config.Spec.Hostname != "" { 588 return c.config.Spec.Hostname 589 } 590 591 if len(c.ID()) < 11 { 592 return c.ID() 593 } 594 return c.ID()[:12] 595 } 596 597 // WorkingDir returns the containers working dir 598 func (c *Container) WorkingDir() string { 599 if c.config.Spec.Process != nil { 600 return c.config.Spec.Process.Cwd 601 } 602 return "/" 603 } 604 605 // State Accessors 606 // Require locking 607 608 // State returns the current state of the container 609 func (c *Container) State() (define.ContainerStatus, error) { 610 if !c.batched { 611 c.lock.Lock() 612 defer c.lock.Unlock() 613 614 if err := c.syncContainer(); err != nil { 615 return define.ContainerStateUnknown, err 616 } 617 } 618 return c.state.State, nil 619 } 620 621 // Mounted returns whether the container is mounted and the path it is mounted 622 // at (if it is mounted). 623 // If the container is not mounted, no error is returned, and the mountpoint 624 // will be set to "". 625 func (c *Container) Mounted() (bool, string, error) { 626 if !c.batched { 627 c.lock.Lock() 628 defer c.lock.Unlock() 629 if err := c.syncContainer(); err != nil { 630 return false, "", errors.Wrapf(err, "error updating container %s state", c.ID()) 631 } 632 } 633 // We cannot directly return c.state.Mountpoint as it is not guaranteed 634 // to be set if the container is mounted, only if the container has been 635 // prepared with c.prepare(). 636 // Instead, let's call into c/storage 637 mountedTimes, err := c.runtime.storageService.MountedContainerImage(c.ID()) 638 if err != nil { 639 return false, "", err 640 } 641 642 if mountedTimes > 0 { 643 mountPoint, err := c.runtime.storageService.GetMountpoint(c.ID()) 644 if err != nil { 645 return false, "", err 646 } 647 648 return true, mountPoint, nil 649 } 650 651 return false, "", nil 652 } 653 654 // StartedTime is the time the container was started 655 func (c *Container) StartedTime() (time.Time, error) { 656 if !c.batched { 657 c.lock.Lock() 658 defer c.lock.Unlock() 659 if err := c.syncContainer(); err != nil { 660 return time.Time{}, errors.Wrapf(err, "error updating container %s state", c.ID()) 661 } 662 } 663 return c.state.StartedTime, nil 664 } 665 666 // FinishedTime is the time the container was stopped 667 func (c *Container) FinishedTime() (time.Time, error) { 668 if !c.batched { 669 c.lock.Lock() 670 defer c.lock.Unlock() 671 if err := c.syncContainer(); err != nil { 672 return time.Time{}, errors.Wrapf(err, "error updating container %s state", c.ID()) 673 } 674 } 675 return c.state.FinishedTime, nil 676 } 677 678 // ExitCode returns the exit code of the container as 679 // an int32, and whether the container has exited. 680 // If the container has not exited, exit code will always be 0. 681 // If the container restarts, the exit code is reset to 0. 682 func (c *Container) ExitCode() (int32, bool, error) { 683 if !c.batched { 684 c.lock.Lock() 685 defer c.lock.Unlock() 686 if err := c.syncContainer(); err != nil { 687 return 0, false, errors.Wrapf(err, "error updating container %s state", c.ID()) 688 } 689 } 690 return c.state.ExitCode, c.state.Exited, nil 691 } 692 693 // OOMKilled returns whether the container was killed by an OOM condition 694 func (c *Container) OOMKilled() (bool, error) { 695 if !c.batched { 696 c.lock.Lock() 697 defer c.lock.Unlock() 698 if err := c.syncContainer(); err != nil { 699 return false, errors.Wrapf(err, "error updating container %s state", c.ID()) 700 } 701 } 702 return c.state.OOMKilled, nil 703 } 704 705 // PID returns the PID of the container. 706 // If the container is not running, a pid of 0 will be returned. No error will 707 // occur. 708 func (c *Container) PID() (int, error) { 709 if !c.batched { 710 c.lock.Lock() 711 defer c.lock.Unlock() 712 713 if err := c.syncContainer(); err != nil { 714 return -1, err 715 } 716 } 717 718 return c.state.PID, nil 719 } 720 721 // ConmonPID Returns the PID of the container's conmon process. 722 // If the container is not running, a PID of 0 will be returned. No error will 723 // occur. 724 func (c *Container) ConmonPID() (int, error) { 725 if !c.batched { 726 c.lock.Lock() 727 defer c.lock.Unlock() 728 729 if err := c.syncContainer(); err != nil { 730 return -1, err 731 } 732 } 733 734 return c.state.ConmonPID, nil 735 } 736 737 // ExecSessions retrieves active exec sessions running in the container 738 func (c *Container) ExecSessions() ([]string, error) { 739 if !c.batched { 740 c.lock.Lock() 741 defer c.lock.Unlock() 742 743 if err := c.syncContainer(); err != nil { 744 return nil, err 745 } 746 } 747 748 ids := make([]string, 0, len(c.state.ExecSessions)) 749 for id := range c.state.ExecSessions { 750 ids = append(ids, id) 751 } 752 753 return ids, nil 754 } 755 756 // ExecSession retrieves detailed information on a single active exec session in 757 // a container 758 func (c *Container) ExecSession(id string) (*ExecSession, error) { 759 if !c.batched { 760 c.lock.Lock() 761 defer c.lock.Unlock() 762 763 if err := c.syncContainer(); err != nil { 764 return nil, err 765 } 766 } 767 768 session, ok := c.state.ExecSessions[id] 769 if !ok { 770 return nil, errors.Wrapf(define.ErrNoSuchExecSession, "no exec session with ID %s found in container %s", id, c.ID()) 771 } 772 773 returnSession := new(ExecSession) 774 if err := JSONDeepCopy(session, returnSession); err != nil { 775 return nil, errors.Wrapf(err, "error copying contents of container %s exec session %s", c.ID(), session.ID()) 776 } 777 778 return returnSession, nil 779 } 780 781 // IPs retrieves a container's IP address(es) 782 // This will only be populated if the container is configured to created a new 783 // network namespace, and that namespace is presently active 784 func (c *Container) IPs() ([]net.IPNet, error) { 785 if !c.batched { 786 c.lock.Lock() 787 defer c.lock.Unlock() 788 789 if err := c.syncContainer(); err != nil { 790 return nil, err 791 } 792 } 793 794 if !c.config.CreateNetNS { 795 return nil, errors.Wrapf(define.ErrInvalidArg, "container %s network namespace is not managed by libpod", c.ID()) 796 } 797 798 ips := make([]net.IPNet, 0) 799 800 for _, r := range c.state.NetworkStatus { 801 for _, ip := range r.IPs { 802 ips = append(ips, ip.Address) 803 } 804 } 805 806 return ips, nil 807 } 808 809 // Routes retrieves a container's routes 810 // This will only be populated if the container is configured to created a new 811 // network namespace, and that namespace is presently active 812 func (c *Container) Routes() ([]types.Route, error) { 813 if !c.batched { 814 c.lock.Lock() 815 defer c.lock.Unlock() 816 817 if err := c.syncContainer(); err != nil { 818 return nil, err 819 } 820 } 821 822 if !c.config.CreateNetNS { 823 return nil, errors.Wrapf(define.ErrInvalidArg, "container %s network namespace is not managed by libpod", c.ID()) 824 } 825 826 routes := make([]types.Route, 0) 827 828 for _, r := range c.state.NetworkStatus { 829 for _, route := range r.Routes { 830 newRoute := types.Route{ 831 Dst: route.Dst, 832 GW: route.GW, 833 } 834 routes = append(routes, newRoute) 835 } 836 } 837 838 return routes, nil 839 } 840 841 // BindMounts retrieves bind mounts that were created by libpod and will be 842 // added to the container 843 // All these mounts except /dev/shm are ignored if a mount in the given spec has 844 // the same destination 845 // These mounts include /etc/resolv.conf, /etc/hosts, and /etc/hostname 846 // The return is formatted as a map from destination (mountpoint in the 847 // container) to source (path of the file that will be mounted into the 848 // container) 849 // If the container has not been started yet, an empty map will be returned, as 850 // the files in question are only created when the container is started. 851 func (c *Container) BindMounts() (map[string]string, error) { 852 if !c.batched { 853 c.lock.Lock() 854 defer c.lock.Unlock() 855 856 if err := c.syncContainer(); err != nil { 857 return nil, err 858 } 859 } 860 861 newMap := make(map[string]string, len(c.state.BindMounts)) 862 863 for key, val := range c.state.BindMounts { 864 newMap[key] = val 865 } 866 867 return newMap, nil 868 } 869 870 // StoppedByUser returns whether the container was last stopped by an explicit 871 // call to the Stop() API, or whether it exited naturally. 872 func (c *Container) StoppedByUser() (bool, error) { 873 if !c.batched { 874 c.lock.Lock() 875 defer c.lock.Unlock() 876 877 if err := c.syncContainer(); err != nil { 878 return false, err 879 } 880 } 881 882 return c.state.StoppedByUser, nil 883 } 884 885 // Misc Accessors 886 // Most will require locking 887 888 // NamespacePath returns the path of one of the container's namespaces 889 // If the container is not running, an error will be returned 890 func (c *Container) NamespacePath(linuxNS LinuxNS) (string, error) { //nolint:interfacer 891 if !c.batched { 892 c.lock.Lock() 893 defer c.lock.Unlock() 894 if err := c.syncContainer(); err != nil { 895 return "", errors.Wrapf(err, "error updating container %s state", c.ID()) 896 } 897 } 898 899 if c.state.State != define.ContainerStateRunning && c.state.State != define.ContainerStatePaused { 900 return "", errors.Wrapf(define.ErrCtrStopped, "cannot get namespace path unless container %s is running", c.ID()) 901 } 902 903 if linuxNS == InvalidNS { 904 return "", errors.Wrapf(define.ErrInvalidArg, "invalid namespace requested from container %s", c.ID()) 905 } 906 907 return fmt.Sprintf("/proc/%d/ns/%s", c.state.PID, linuxNS.String()), nil 908 } 909 910 // CgroupManager returns the cgroup manager used by the given container. 911 func (c *Container) CgroupManager() string { 912 cgroupManager := c.config.CgroupManager 913 if cgroupManager == "" { 914 cgroupManager = c.runtime.config.Engine.CgroupManager 915 } 916 return cgroupManager 917 } 918 919 // CGroupPath returns a cgroups "path" for the given container. 920 // Note that the container must be running. Otherwise, an error 921 // is returned. 922 func (c *Container) CGroupPath() (string, error) { 923 if !c.batched { 924 c.lock.Lock() 925 defer c.lock.Unlock() 926 if err := c.syncContainer(); err != nil { 927 return "", errors.Wrapf(err, "error updating container %s state", c.ID()) 928 } 929 } 930 return c.cGroupPath() 931 } 932 933 // cGroupPath returns a cgroups "path" for the given container. 934 // Note that the container must be running. Otherwise, an error 935 // is returned. 936 // NOTE: only call this when owning the container's lock. 937 func (c *Container) cGroupPath() (string, error) { 938 if c.config.NoCgroups || c.config.CgroupsMode == "disabled" { 939 return "", errors.Wrapf(define.ErrNoCgroups, "this container is not creating cgroups") 940 } 941 if c.state.State != define.ContainerStateRunning && c.state.State != define.ContainerStatePaused { 942 return "", errors.Wrapf(define.ErrCtrStopped, "cannot get cgroup path unless container %s is running", c.ID()) 943 } 944 945 // Read /proc/{PID}/cgroup and find the *longest* cgroup entry. That's 946 // needed to account for hacks in cgroups v1, where each line in the 947 // file could potentially point to a cgroup. The longest one, however, 948 // is the libpod-specific one we're looking for. 949 // 950 // See #8397 on the need for the longest-path look up. 951 procPath := fmt.Sprintf("/proc/%d/cgroup", c.state.PID) 952 lines, err := ioutil.ReadFile(procPath) 953 if err != nil { 954 return "", err 955 } 956 957 var cgroupPath string 958 for _, line := range bytes.Split(lines, []byte("\n")) { 959 // cgroups(7) nails it down to three fields with the 3rd 960 // pointing to the cgroup's path which works both on v1 and v2. 961 fields := bytes.Split(line, []byte(":")) 962 if len(fields) != 3 { 963 logrus.Debugf("Error parsing cgroup: expected 3 fields but got %d: %s", len(fields), procPath) 964 continue 965 } 966 path := string(fields[2]) 967 if len(path) > len(cgroupPath) { 968 cgroupPath = path 969 } 970 } 971 972 if len(cgroupPath) == 0 { 973 return "", errors.Errorf("could not find any cgroup in %q", procPath) 974 } 975 976 return cgroupPath, nil 977 } 978 979 // RootFsSize returns the root FS size of the container 980 func (c *Container) RootFsSize() (int64, error) { 981 if !c.batched { 982 c.lock.Lock() 983 defer c.lock.Unlock() 984 if err := c.syncContainer(); err != nil { 985 return -1, errors.Wrapf(err, "error updating container %s state", c.ID()) 986 } 987 } 988 return c.rootFsSize() 989 } 990 991 // RWSize returns the rw size of the container 992 func (c *Container) RWSize() (int64, error) { 993 if !c.batched { 994 c.lock.Lock() 995 defer c.lock.Unlock() 996 if err := c.syncContainer(); err != nil { 997 return -1, errors.Wrapf(err, "error updating container %s state", c.ID()) 998 } 999 } 1000 return c.rwSize() 1001 } 1002 1003 // IDMappings returns the UID/GID mapping used for the container 1004 func (c *Container) IDMappings() (storage.IDMappingOptions, error) { 1005 return c.config.IDMappings, nil 1006 } 1007 1008 // RootUID returns the root user mapping from container 1009 func (c *Container) RootUID() int { 1010 for _, uidmap := range c.config.IDMappings.UIDMap { 1011 if uidmap.ContainerID == 0 { 1012 return uidmap.HostID 1013 } 1014 } 1015 return 0 1016 } 1017 1018 // RootGID returns the root user mapping from container 1019 func (c *Container) RootGID() int { 1020 for _, gidmap := range c.config.IDMappings.GIDMap { 1021 if gidmap.ContainerID == 0 { 1022 return gidmap.HostID 1023 } 1024 } 1025 return 0 1026 } 1027 1028 // IsInfra returns whether the container is an infra container 1029 func (c *Container) IsInfra() bool { 1030 return c.config.IsInfra 1031 } 1032 1033 // IsReadOnly returns whether the container is running in read only mode 1034 func (c *Container) IsReadOnly() bool { 1035 return c.config.Spec.Root.Readonly 1036 } 1037 1038 // NetworkDisabled returns whether the container is running with a disabled network 1039 func (c *Container) NetworkDisabled() (bool, error) { 1040 if c.config.NetNsCtr != "" { 1041 container, err := c.runtime.state.Container(c.config.NetNsCtr) 1042 if err != nil { 1043 return false, err 1044 } 1045 return container.NetworkDisabled() 1046 } 1047 return networkDisabled(c) 1048 1049 } 1050 1051 func networkDisabled(c *Container) (bool, error) { 1052 if c.config.CreateNetNS { 1053 return false, nil 1054 } 1055 if !c.config.PostConfigureNetNS { 1056 for _, ns := range c.config.Spec.Linux.Namespaces { 1057 if ns.Type == spec.NetworkNamespace { 1058 return ns.Path == "", nil 1059 } 1060 } 1061 } 1062 return false, nil 1063 } 1064 1065 // ContainerState returns containerstate struct 1066 func (c *Container) ContainerState() (*ContainerState, error) { 1067 if !c.batched { 1068 c.lock.Lock() 1069 defer c.lock.Unlock() 1070 1071 if err := c.syncContainer(); err != nil { 1072 return nil, err 1073 } 1074 } 1075 returnConfig := new(ContainerState) 1076 if err := JSONDeepCopy(c.state, returnConfig); err != nil { 1077 return nil, errors.Wrapf(err, "error copying container %s state", c.ID()) 1078 } 1079 return c.state, nil 1080 } 1081 1082 // HasHealthCheck returns bool as to whether there is a health check 1083 // defined for the container 1084 func (c *Container) HasHealthCheck() bool { 1085 return c.config.HealthCheckConfig != nil 1086 } 1087 1088 // HealthCheckConfig returns the command and timing attributes of the health check 1089 func (c *Container) HealthCheckConfig() *manifest.Schema2HealthConfig { 1090 return c.config.HealthCheckConfig 1091 } 1092 1093 // AutoRemove indicates whether the container will be removed after it is executed 1094 func (c *Container) AutoRemove() bool { 1095 spec := c.config.Spec 1096 if spec.Annotations == nil { 1097 return false 1098 } 1099 return c.Spec().Annotations[define.InspectAnnotationAutoremove] == define.InspectResponseTrue 1100 } 1101 1102 // Timezone returns the timezone configured inside the container. 1103 // Local means it has the same timezone as the host machine 1104 func (c *Container) Timezone() string { 1105 return c.config.Timezone 1106 } 1107 1108 // Umask returns the Umask bits configured inside the container. 1109 func (c *Container) Umask() string { 1110 return c.config.Umask 1111 } 1112 1113 // Networks gets all the networks this container is connected to. 1114 // Please do NOT use ctr.config.Networks, as this can be changed from those 1115 // values at runtime via network connect and disconnect. 1116 // If the container is configured to use CNI and this function returns an empty 1117 // array, the container will still be connected to the default network. 1118 // The second return parameter, a bool, indicates that the container container 1119 // is joining the default CNI network - the network name will be included in the 1120 // returned array of network names, but the container did not explicitly join 1121 // this network. 1122 func (c *Container) Networks() ([]string, bool, error) { 1123 if !c.batched { 1124 c.lock.Lock() 1125 defer c.lock.Unlock() 1126 1127 if err := c.syncContainer(); err != nil { 1128 return nil, false, err 1129 } 1130 } 1131 1132 return c.networks() 1133 } 1134 1135 // Unlocked accessor for networks 1136 func (c *Container) networks() ([]string, bool, error) { 1137 networks, err := c.runtime.state.GetNetworks(c) 1138 if err != nil && errors.Cause(err) == define.ErrNoSuchNetwork { 1139 if len(c.config.Networks) == 0 && !rootless.IsRootless() { 1140 return []string{c.runtime.netPlugin.GetDefaultNetworkName()}, true, nil 1141 } 1142 return c.config.Networks, false, nil 1143 } 1144 1145 return networks, false, err 1146 } 1147 1148 // networksByNameIndex provides us with a map of container networks where key 1149 // is network name and value is the index position 1150 func (c *Container) networksByNameIndex() (map[string]int, error) { 1151 networks, _, err := c.networks() 1152 if err != nil { 1153 return nil, err 1154 } 1155 networkNamesByIndex := make(map[string]int, len(networks)) 1156 for index, name := range networks { 1157 networkNamesByIndex[name] = index 1158 } 1159 return networkNamesByIndex, nil 1160 } 1161 1162 // add puts the new given CNI network name into the tracking map 1163 // and assigns it a new integer based on the map length 1164 func (d ContainerNetworkDescriptions) add(networkName string) { 1165 d[networkName] = len(d) 1166 } 1167 1168 // getInterfaceByName returns a formatted interface name for a given 1169 // network along with a bool as to whether the network existed 1170 func (d ContainerNetworkDescriptions) getInterfaceByName(networkName string) (string, bool) { 1171 val, exists := d[networkName] 1172 if !exists { 1173 return "", exists 1174 } 1175 return fmt.Sprintf("eth%d", val), exists 1176 }