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  }