1 Star 0 Fork 1

Derek Ray/podman

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
container.go 33.22 KB
一键复制 编辑 原始数据 按行查看 历史
Daniel J Walsh 提交于 2019-02-14 13:21 . Fix volume handling in podman
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087
package libpod
import (
"fmt"
"io/ioutil"
"net"
"os"
"path/filepath"
"time"
"github.com/containernetworking/cni/pkg/types"
cnitypes "github.com/containernetworking/cni/pkg/types/current"
"github.com/containers/libpod/libpod/lock"
"github.com/containers/libpod/pkg/namespaces"
"github.com/containers/storage"
"github.com/cri-o/ocicni/pkg/ocicni"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"github.com/ulule/deepcopier"
)
// ContainerStatus represents the current state of a container
type ContainerStatus int
const (
// ContainerStateUnknown indicates that the container is in an error
// state where information about it cannot be retrieved
ContainerStateUnknown ContainerStatus = iota
// ContainerStateConfigured indicates that the container has had its
// storage configured but it has not been created in the OCI runtime
ContainerStateConfigured ContainerStatus = iota
// ContainerStateCreated indicates the container has been created in
// the OCI runtime but not started
ContainerStateCreated ContainerStatus = iota
// ContainerStateRunning indicates the container is currently executing
ContainerStateRunning ContainerStatus = iota
// ContainerStateStopped indicates that the container was running but has
// exited
ContainerStateStopped ContainerStatus = iota
// ContainerStatePaused indicates that the container has been paused
ContainerStatePaused ContainerStatus = iota
// ContainerStateExited indicates the the container has stopped and been
// cleaned up
ContainerStateExited ContainerStatus = iota
)
// CgroupfsDefaultCgroupParent is the cgroup parent for CGroupFS in libpod
const CgroupfsDefaultCgroupParent = "/libpod_parent"
// SystemdDefaultCgroupParent is the cgroup parent for the systemd cgroup
// manager in libpod
const SystemdDefaultCgroupParent = "machine.slice"
// DefaultWaitInterval is the default interval between container status checks
// while waiting.
const DefaultWaitInterval = 250 * time.Millisecond
// LinuxNS represents a Linux namespace
type LinuxNS int
const (
// InvalidNS is an invalid namespace
InvalidNS LinuxNS = iota
// IPCNS is the IPC namespace
IPCNS LinuxNS = iota
// MountNS is the mount namespace
MountNS LinuxNS = iota
// NetNS is the network namespace
NetNS LinuxNS = iota
// PIDNS is the PID namespace
PIDNS LinuxNS = iota
// UserNS is the user namespace
UserNS LinuxNS = iota
// UTSNS is the UTS namespace
UTSNS LinuxNS = iota
// CgroupNS is the CGroup namespace
CgroupNS LinuxNS = iota
)
// String returns a string representation of a Linux namespace
// It is guaranteed to be the name of the namespace in /proc for valid ns types
func (ns LinuxNS) String() string {
switch ns {
case InvalidNS:
return "invalid"
case IPCNS:
return "ipc"
case MountNS:
return "mnt"
case NetNS:
return "net"
case PIDNS:
return "pid"
case UserNS:
return "user"
case UTSNS:
return "uts"
case CgroupNS:
return "cgroup"
default:
return "unknown"
}
}
// Container is a single OCI container.
// All operations on a Container that access state must begin with a call to
// syncContainer().
// There is no guarantee that state exists in a readable state before
// syncContainer() is run, and even if it does, its contents will be out of date
// and must be refreshed from the database.
// Generally, this requirement applies only to top-level functions; helpers can
// assume that their callers handled this requirement. Generally speaking, if a
// function takes the container lock and accesses any part of state, it should
// syncContainer() immediately after locking.
// ffjson: skip
type Container struct {
config *ContainerConfig
state *ContainerState
// Batched indicates that a container has been locked as part of a
// Batch() operation
// Functions called on a batched container will not lock or sync
batched bool
valid bool
lock lock.Locker
runtime *Runtime
rootlessSlirpSyncR *os.File
rootlessSlirpSyncW *os.File
// A restored container should have the same IP address as before
// being checkpointed. If requestedIP is set it will be used instead
// of config.StaticIP.
requestedIP net.IP
}
// ContainerState contains the current state of the container
// It is stored on disk in a tmpfs and recreated on reboot
// easyjson:json
type ContainerState struct {
// The current state of the running container
State ContainerStatus `json:"state"`
// The path to the JSON OCI runtime spec for this container
ConfigPath string `json:"configPath,omitempty"`
// RunDir is a per-boot directory for container content
RunDir string `json:"runDir,omitempty"`
// DestinationRunDir is where the files in RunDir will be accessible for the container.
// It is different than RunDir when using userNS
DestinationRunDir string `json:"destinationRunDir,omitempty"`
// Mounted indicates whether the container's storage has been mounted
// for use
Mounted bool `json:"mounted,omitempty"`
// Mountpoint contains the path to the container's mounted storage as given
// by containers/storage. It can be different than RealMountpoint when
// usernamespaces are used
Mountpoint string `json:"mountPoint,omitempty"`
// RealMountpoint contains the path to the container's mounted storage
RealMountpoint string `json:"realMountPoint,omitempty"`
// StartedTime is the time the container was started
StartedTime time.Time `json:"startedTime,omitempty"`
// FinishedTime is the time the container finished executing
FinishedTime time.Time `json:"finishedTime,omitempty"`
// ExitCode is the exit code returned when the container stopped
ExitCode int32 `json:"exitCode,omitempty"`
// Exited is whether the container has exited
Exited bool `json:"exited,omitempty"`
// OOMKilled indicates that the container was killed as it ran out of
// memory
OOMKilled bool `json:"oomKilled,omitempty"`
// PID is the PID of a running container
PID int `json:"pid,omitempty"`
// ExecSessions contains active exec sessions for container
// Exec session ID is mapped to PID of exec process
ExecSessions map[string]*ExecSession `json:"execSessions,omitempty"`
// NetworkStatus contains the configuration results for all networks
// the pod is attached to. Only populated if we created a network
// namespace for the container, and the network namespace is currently
// active
NetworkStatus []*cnitypes.Result `json:"networkResults,omitempty"`
// BindMounts contains files that will be bind-mounted into the
// container when it is mounted.
// These include /etc/hosts and /etc/resolv.conf
// This maps the path the file will be mounted to in the container to
// the path of the file on disk outside the container
BindMounts map[string]string `json:"bindMounts,omitempty"`
// UserNSRoot is the directory used as root for the container when using
// user namespaces.
UserNSRoot string `json:"userNSRoot,omitempty"`
// ExtensionStageHooks holds hooks which will be executed by libpod
// and not delegated to the OCI runtime.
ExtensionStageHooks map[string][]spec.Hook `json:"extensionStageHooks,omitempty"`
// containerPlatformState holds platform-specific container state.
containerPlatformState
}
// ExecSession contains information on an active exec session
// easyjson:json
type ExecSession struct {
ID string `json:"id"`
Command []string `json:"command"`
PID int `json:"pid"`
}
// ContainerConfig contains all information that was used to create the
// container. It may not be changed once created.
// It is stored, read-only, on disk
// easyjson:json
type ContainerConfig struct {
Spec *spec.Spec `json:"spec"`
ID string `json:"id"`
Name string `json:"name"`
// Full ID of the pood the container belongs to
Pod string `json:"pod,omitempty"`
// Namespace the container is in
Namespace string `json:"namespace,omitempty"`
// ID of this container's lock
LockID uint32 `json:"lockID"`
// TODO consider breaking these subsections up into smaller structs
// UID/GID mappings used by the storage
IDMappings storage.IDMappingOptions `json:"idMappingsOptions,omitempty"`
// Information on the image used for the root filesystem/
RootfsImageID string `json:"rootfsImageID,omitempty"`
RootfsImageName string `json:"rootfsImageName,omitempty"`
// Rootfs to use for the container, this conflicts with RootfsImageID
Rootfs string `json:"rootfs,omitempty"`
// Whether to mount volumes specified in the image.
ImageVolumes bool `json:"imageVolumes"`
// Src path to be mounted on /dev/shm in container.
ShmDir string `json:"ShmDir,omitempty"`
// Size of the container's SHM.
ShmSize int64 `json:"shmSize"`
// Static directory for container content that will persist across
// reboot.
StaticDir string `json:"staticDir"`
// Mounts list contains all additional mounts into the container rootfs.
// These include the SHM mount.
// These must be unmounted before the container's rootfs is unmounted.
Mounts []string `json:"mounts,omitempty"`
// Security Config
// Whether the container is privileged
Privileged bool `json:"privileged"`
// SELinux process label for container
ProcessLabel string `json:"ProcessLabel,omitempty"`
// SELinux mount label for root filesystem
MountLabel string `json:"MountLabel,omitempty"`
// LabelOpts are options passed in by the user to setup SELinux labels
LabelOpts []string `json:"labelopts,omitempty"`
// User and group to use in the container
// Can be specified by name or UID/GID
User string `json:"user,omitempty"`
// Additional groups to add
Groups []string `json:"groups,omitempty"`
// Namespace Config
// IDs of container to share namespaces with
// NetNsCtr conflicts with the CreateNetNS bool
// These containers are considered dependencies of the given container
// They must be started before the given container is started
IPCNsCtr string `json:"ipcNsCtr,omitempty"`
MountNsCtr string `json:"mountNsCtr,omitempty"`
NetNsCtr string `json:"netNsCtr,omitempty"`
PIDNsCtr string `json:"pidNsCtr,omitempty"`
UserNsCtr string `json:"userNsCtr,omitempty"`
UTSNsCtr string `json:"utsNsCtr,omitempty"`
CgroupNsCtr string `json:"cgroupNsCtr,omitempty"`
// IDs of dependency containers.
// These containers must be started before this container is started.
Dependencies []string
// Network Config
// CreateNetNS indicates that libpod should create and configure a new
// network namespace for the container.
// This cannot be set if NetNsCtr is also set.
CreateNetNS bool `json:"createNetNS"`
// StaticIP is a static IP to request for the container.
// This cannot be set unless CreateNetNS is set.
// If not set, the container will be dynamically assigned an IP by CNI.
StaticIP net.IP `json:"staticIP"`
// PortMappings are the ports forwarded to the container's network
// namespace
// These are not used unless CreateNetNS is true
PortMappings []ocicni.PortMapping `json:"portMappings,omitempty"`
// DNS servers to use in container resolv.conf
// Will override servers in host resolv if set
DNSServer []net.IP `json:"dnsServer,omitempty"`
// DNS Search domains to use in container resolv.conf
// Will override search domains in host resolv if set
DNSSearch []string `json:"dnsSearch,omitempty"`
// DNS options to be set in container resolv.conf
// With override options in host resolv if set
DNSOption []string `json:"dnsOption,omitempty"`
// Hosts to add in container
// Will be appended to host's host file
HostAdd []string `json:"hostsAdd,omitempty"`
// Network names (CNI) to add container to. Empty to use default network.
Networks []string `json:"networks,omitempty"`
// Network mode specified for the default network.
NetMode namespaces.NetworkMode `json:"networkMode,omitempty"`
// Image Config
// UserVolumes contains user-added volume mounts in the container.
// These will not be added to the container's spec, as it is assumed
// they are already present in the spec given to Libpod. Instead, it is
// used when committing containers to generate the VOLUMES field of the
// image that is created, and for triggering some OCI hooks which do not
// fire unless user-added volume mounts are present.
UserVolumes []string `json:"userVolumes,omitempty"`
// Entrypoint is the container's entrypoint.
// It is not used in spec generation, but will be used when the
// container is committed to populate the entrypoint of the new image.
Entrypoint []string `json:"entrypoint,omitempty"`
// Command is the container's command.
// It is not used in spec generation, but will be used when the
// container is committed to populate the command of the new image.
Command []string `json:"command,omitempty"`
// Misc Options
// Whether to keep container STDIN open
Stdin bool `json:"stdin,omitempty"`
// Labels is a set of key-value pairs providing additional information
// about a container
Labels map[string]string `json:"labels,omitempty"`
// StopSignal is the signal that will be used to stop the container
StopSignal uint `json:"stopSignal,omitempty"`
// StopTimeout is the signal that will be used to stop the container
StopTimeout uint `json:"stopTimeout,omitempty"`
// Time container was created
CreatedTime time.Time `json:"createdTime"`
// Cgroup parent of the container
CgroupParent string `json:"cgroupParent"`
// LogPath log location
LogPath string `json:"logPath"`
// File containing the conmon PID
ConmonPidFile string `json:"conmonPidFile,omitempty"`
// TODO log options for log drivers
PostConfigureNetNS bool `json:"postConfigureNetNS"`
// OCIRuntime used to create the container
OCIRuntime string `json:"runtime,omitempty"`
// ExitCommand is the container's exit command.
// This Command will be executed when the container exits
ExitCommand []string `json:"exitCommand,omitempty"`
// LocalVolumes are the built-in volumes we get from the --volumes-from flag
// It picks up the built-in volumes of the container used by --volumes-from
LocalVolumes []spec.Mount
// IsInfra is a bool indicating whether this container is an infra container used for
// sharing kernel namespaces in a pod
IsInfra bool `json:"pause"`
// Systemd tells libpod to setup the container in systemd mode
Systemd bool `json:"systemd"`
}
// ContainerStatus returns a string representation for users
// of a container state
func (t ContainerStatus) String() string {
switch t {
case ContainerStateUnknown:
return "unknown"
case ContainerStateConfigured:
return "configured"
case ContainerStateCreated:
return "created"
case ContainerStateRunning:
return "running"
case ContainerStateStopped:
return "stopped"
case ContainerStatePaused:
return "paused"
case ContainerStateExited:
return "exited"
}
return "bad state"
}
// Config accessors
// Unlocked
// Config returns the configuration used to create the container
func (c *Container) Config() *ContainerConfig {
returnConfig := new(ContainerConfig)
deepcopier.Copy(c.config).To(returnConfig)
return returnConfig
}
// Spec returns the container's OCI runtime spec
// The spec returned is the one used to create the container. The running
// spec may differ slightly as mounts are added based on the image
func (c *Container) Spec() *spec.Spec {
returnSpec := new(spec.Spec)
deepcopier.Copy(c.config.Spec).To(returnSpec)
return returnSpec
}
// specFromState returns the unmarshalled json config of the container. If the
// config does not exist (e.g., because the container was never started) return
// the spec from the config.
func (c *Container) specFromState() (*spec.Spec, error) {
returnSpec := c.config.Spec
if f, err := os.Open(c.state.ConfigPath); err == nil {
returnSpec = new(spec.Spec)
content, err := ioutil.ReadAll(f)
if err != nil {
return nil, errors.Wrapf(err, "error reading container config")
}
if err := json.Unmarshal([]byte(content), &returnSpec); err != nil {
return nil, errors.Wrapf(err, "error unmarshalling container config")
}
} else {
// ignore when the file does not exist
if !os.IsNotExist(err) {
return nil, errors.Wrapf(err, "error opening container config")
}
}
return returnSpec, nil
}
// ID returns the container's ID
func (c *Container) ID() string {
return c.config.ID
}
// Name returns the container's name
func (c *Container) Name() string {
return c.config.Name
}
// PodID returns the full ID of the pod the container belongs to, or "" if it
// does not belong to a pod
func (c *Container) PodID() string {
return c.config.Pod
}
// Namespace returns the libpod namespace the container is in.
// Namespaces are used to logically separate containers and pods in the state.
func (c *Container) Namespace() string {
return c.config.Namespace
}
// Image returns the ID and name of the image used as the container's rootfs
func (c *Container) Image() (string, string) {
return c.config.RootfsImageID, c.config.RootfsImageName
}
// ImageVolumes returns whether the container is configured to create
// persistent volumes requested by the image
func (c *Container) ImageVolumes() bool {
return c.config.ImageVolumes
}
// ShmDir returns the sources path to be mounted on /dev/shm in container
func (c *Container) ShmDir() string {
return c.config.ShmDir
}
// ShmSize returns the size of SHM device to be mounted into the container
func (c *Container) ShmSize() int64 {
return c.config.ShmSize
}
// StaticDir returns the directory used to store persistent container files
func (c *Container) StaticDir() string {
return c.config.StaticDir
}
// Privileged returns whether the container is privileged
func (c *Container) Privileged() bool {
return c.config.Privileged
}
// ProcessLabel returns the selinux ProcessLabel of the container
func (c *Container) ProcessLabel() string {
return c.config.ProcessLabel
}
// MountLabel returns the SELinux mount label of the container
func (c *Container) MountLabel() string {
return c.config.MountLabel
}
// User returns the user who the container is run as
func (c *Container) User() string {
return c.config.User
}
// Dependencies gets the containers this container depends upon
func (c *Container) Dependencies() []string {
// Collect in a map first to remove dupes
dependsCtrs := map[string]bool{}
// First add all namespace containers
if c.config.IPCNsCtr != "" {
dependsCtrs[c.config.IPCNsCtr] = true
}
if c.config.MountNsCtr != "" {
dependsCtrs[c.config.MountNsCtr] = true
}
if c.config.NetNsCtr != "" {
dependsCtrs[c.config.NetNsCtr] = true
}
if c.config.PIDNsCtr != "" {
dependsCtrs[c.config.PIDNsCtr] = true
}
if c.config.UserNsCtr != "" {
dependsCtrs[c.config.UserNsCtr] = true
}
if c.config.UTSNsCtr != "" {
dependsCtrs[c.config.UTSNsCtr] = true
}
if c.config.CgroupNsCtr != "" {
dependsCtrs[c.config.CgroupNsCtr] = true
}
// Add all generic dependencies
for _, id := range c.config.Dependencies {
dependsCtrs[id] = true
}
if len(dependsCtrs) == 0 {
return []string{}
}
depends := make([]string, 0, len(dependsCtrs))
for ctr := range dependsCtrs {
depends = append(depends, ctr)
}
return depends
}
// NewNetNS returns whether the container will create a new network namespace
func (c *Container) NewNetNS() bool {
return c.config.CreateNetNS
}
// PortMappings returns the ports that will be mapped into a container if
// a new network namespace is created
// If NewNetNS() is false, this value is unused
func (c *Container) PortMappings() ([]ocicni.PortMapping, error) {
// First check if the container belongs to a network namespace (like a pod)
if len(c.config.NetNsCtr) > 0 {
netNsCtr, err := c.runtime.LookupContainer(c.config.NetNsCtr)
if err != nil {
return nil, errors.Wrapf(err, "unable to lookup network namespace for container %s", c.ID())
}
return netNsCtr.PortMappings()
}
return c.config.PortMappings, nil
}
// DNSServers returns DNS servers that will be used in the container's
// resolv.conf
// If empty, DNS server from the host's resolv.conf will be used instead
func (c *Container) DNSServers() []net.IP {
return c.config.DNSServer
}
// DNSSearch returns the DNS search domains that will be used in the container's
// resolv.conf
// If empty, DNS Search domains from the host's resolv.conf will be used instead
func (c *Container) DNSSearch() []string {
return c.config.DNSSearch
}
// DNSOption returns the DNS options that will be used in the container's
// resolv.conf
// If empty, options from the host's resolv.conf will be used instead
func (c *Container) DNSOption() []string {
return c.config.DNSOption
}
// HostsAdd returns hosts that will be added to the container's hosts file
// The host system's hosts file is used as a base, and these are appended to it
func (c *Container) HostsAdd() []string {
return c.config.HostAdd
}
// UserVolumes returns user-added volume mounts in the container.
// These are not added to the spec, but are used during image commit and to
// trigger some OCI hooks.
func (c *Container) UserVolumes() []string {
volumes := make([]string, 0, len(c.config.UserVolumes))
for _, vol := range c.config.UserVolumes {
volumes = append(volumes, vol)
}
return volumes
}
// Entrypoint is the container's entrypoint.
// This is not added to the spec, but is instead used during image commit.
func (c *Container) Entrypoint() []string {
entrypoint := make([]string, 0, len(c.config.Entrypoint))
for _, str := range c.config.Entrypoint {
entrypoint = append(entrypoint, str)
}
return entrypoint
}
// Command is the container's command
// This is not added to the spec, but is instead used during image commit
func (c *Container) Command() []string {
command := make([]string, 0, len(c.config.Command))
for _, str := range c.config.Command {
command = append(command, str)
}
return command
}
// Stdin returns whether STDIN on the container will be kept open
func (c *Container) Stdin() bool {
return c.config.Stdin
}
// Labels returns the container's labels
func (c *Container) Labels() map[string]string {
labels := make(map[string]string)
for key, value := range c.config.Labels {
labels[key] = value
}
return labels
}
// StopSignal is the signal that will be used to stop the container
// If it fails to stop the container, SIGKILL will be used after a timeout
// If StopSignal is 0, the default signal of SIGTERM will be used
func (c *Container) StopSignal() uint {
return c.config.StopSignal
}
// StopTimeout returns the container's stop timeout
// If the container's default stop signal fails to kill the container, SIGKILL
// will be used after this timeout
func (c *Container) StopTimeout() uint {
return c.config.StopTimeout
}
// CreatedTime gets the time when the container was created
func (c *Container) CreatedTime() time.Time {
return c.config.CreatedTime
}
// CgroupParent gets the container's CGroup parent
func (c *Container) CgroupParent() string {
return c.config.CgroupParent
}
// LogPath returns the path to the container's log file
// This file will only be present after Init() is called to create the container
// in the runtime
func (c *Container) LogPath() string {
return c.config.LogPath
}
// RuntimeName returns the name of the runtime
func (c *Container) RuntimeName() string {
return c.runtime.ociRuntime.name
}
// Runtime spec accessors
// Unlocked
// Hostname gets the container's hostname
func (c *Container) Hostname() string {
if c.config.Spec.Hostname != "" {
return c.config.Spec.Hostname
}
if len(c.ID()) < 11 {
return c.ID()
}
return c.ID()[:12]
}
// WorkingDir returns the containers working dir
func (c *Container) WorkingDir() string {
return c.config.Spec.Process.Cwd
}
// State Accessors
// Require locking
// State returns the current state of the container
func (c *Container) State() (ContainerStatus, error) {
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
if err := c.syncContainer(); err != nil {
return ContainerStateUnknown, err
}
}
return c.state.State, nil
}
// Mounted returns whether the container is mounted and the path it is mounted
// at (if it is mounted).
// If the container is not mounted, no error is returned, and the mountpoint
// will be set to "".
func (c *Container) Mounted() (bool, string, error) {
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
if err := c.syncContainer(); err != nil {
return false, "", errors.Wrapf(err, "error updating container %s state", c.ID())
}
}
// We cannot directly return c.state.Mountpoint as it is not guaranteed
// to be set if the container is mounted, only if the container has been
// prepared with c.prepare().
// Instead, let's call into c/storage
mountedTimes, err := c.runtime.storageService.MountedContainerImage(c.ID())
if err != nil {
return false, "", err
}
if mountedTimes > 0 {
mountPoint, err := c.runtime.storageService.GetMountpoint(c.ID())
if err != nil {
return false, "", err
}
return true, mountPoint, nil
}
return false, "", nil
}
// StartedTime is the time the container was started
func (c *Container) StartedTime() (time.Time, error) {
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
if err := c.syncContainer(); err != nil {
return time.Time{}, errors.Wrapf(err, "error updating container %s state", c.ID())
}
}
return c.state.StartedTime, nil
}
// FinishedTime is the time the container was stopped
func (c *Container) FinishedTime() (time.Time, error) {
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
if err := c.syncContainer(); err != nil {
return time.Time{}, errors.Wrapf(err, "error updating container %s state", c.ID())
}
}
return c.state.FinishedTime, nil
}
// ExitCode returns the exit code of the container as
// an int32, and whether the container has exited.
// If the container has not exited, exit code will always be 0.
// If the container restarts, the exit code is reset to 0.
func (c *Container) ExitCode() (int32, bool, error) {
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
if err := c.syncContainer(); err != nil {
return 0, false, errors.Wrapf(err, "error updating container %s state", c.ID())
}
}
return c.state.ExitCode, c.state.Exited, nil
}
// OOMKilled returns whether the container was killed by an OOM condition
func (c *Container) OOMKilled() (bool, error) {
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
if err := c.syncContainer(); err != nil {
return false, errors.Wrapf(err, "error updating container %s state", c.ID())
}
}
return c.state.OOMKilled, nil
}
// PID returns the PID of the container
// If the container is not running, a pid of 0 will be returned. No error will
// occur.
func (c *Container) PID() (int, error) {
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
if err := c.syncContainer(); err != nil {
return -1, err
}
}
return c.state.PID, nil
}
// ExecSessions retrieves active exec sessions running in the container
func (c *Container) ExecSessions() ([]string, error) {
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
if err := c.syncContainer(); err != nil {
return nil, err
}
}
ids := make([]string, 0, len(c.state.ExecSessions))
for id := range c.state.ExecSessions {
ids = append(ids, id)
}
return ids, nil
}
// ExecSession retrieves detailed information on a single active exec session in
// a container
func (c *Container) ExecSession(id string) (*ExecSession, error) {
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
if err := c.syncContainer(); err != nil {
return nil, err
}
}
session, ok := c.state.ExecSessions[id]
if !ok {
return nil, errors.Wrapf(ErrNoSuchCtr, "no exec session with ID %s found in container %s", id, c.ID())
}
returnSession := new(ExecSession)
returnSession.ID = session.ID
returnSession.Command = session.Command
returnSession.PID = session.PID
return returnSession, nil
}
// IPs retrieves a container's IP address(es)
// This will only be populated if the container is configured to created a new
// network namespace, and that namespace is presently active
func (c *Container) IPs() ([]net.IPNet, error) {
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
if err := c.syncContainer(); err != nil {
return nil, err
}
}
if !c.config.CreateNetNS {
return nil, errors.Wrapf(ErrInvalidArg, "container %s network namespace is not managed by libpod", c.ID())
}
ips := make([]net.IPNet, 0)
for _, r := range c.state.NetworkStatus {
for _, ip := range r.IPs {
ips = append(ips, ip.Address)
}
}
return ips, nil
}
// Routes retrieves a container's routes
// This will only be populated if the container is configured to created a new
// network namespace, and that namespace is presently active
func (c *Container) Routes() ([]types.Route, error) {
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
if err := c.syncContainer(); err != nil {
return nil, err
}
}
if !c.config.CreateNetNS {
return nil, errors.Wrapf(ErrInvalidArg, "container %s network namespace is not managed by libpod", c.ID())
}
routes := make([]types.Route, 0)
for _, r := range c.state.NetworkStatus {
for _, route := range r.Routes {
newRoute := types.Route{
Dst: route.Dst,
GW: route.GW,
}
routes = append(routes, newRoute)
}
}
return routes, nil
}
// BindMounts retrieves bind mounts that were created by libpod and will be
// added to the container
// All these mounts except /dev/shm are ignored if a mount in the given spec has
// the same destination
// These mounts include /etc/resolv.conf, /etc/hosts, and /etc/hostname
// The return is formatted as a map from destination (mountpoint in the
// container) to source (path of the file that will be mounted into the
// container)
// If the container has not been started yet, an empty map will be returned, as
// the files in question are only created when the container is started.
func (c *Container) BindMounts() (map[string]string, error) {
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
if err := c.syncContainer(); err != nil {
return nil, err
}
}
newMap := make(map[string]string, len(c.state.BindMounts))
for key, val := range c.state.BindMounts {
newMap[key] = val
}
return newMap, nil
}
// Misc Accessors
// Most will require locking
// NamespacePath returns the path of one of the container's namespaces
// If the container is not running, an error will be returned
func (c *Container) NamespacePath(ns LinuxNS) (string, error) {
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
if err := c.syncContainer(); err != nil {
return "", errors.Wrapf(err, "error updating container %s state", c.ID())
}
}
if c.state.State != ContainerStateRunning && c.state.State != ContainerStatePaused {
return "", errors.Wrapf(ErrCtrStopped, "cannot get namespace path unless container %s is running", c.ID())
}
if ns == InvalidNS {
return "", errors.Wrapf(ErrInvalidArg, "invalid namespace requested from container %s", c.ID())
}
return fmt.Sprintf("/proc/%d/ns/%s", c.state.PID, ns.String()), nil
}
// CGroupPath returns a cgroups "path" for a given container.
func (c *Container) CGroupPath() (string, error) {
switch c.runtime.config.CgroupManager {
case CgroupfsCgroupsManager:
return filepath.Join(c.config.CgroupParent, fmt.Sprintf("libpod-%s", c.ID())), nil
case SystemdCgroupsManager:
return filepath.Join(c.config.CgroupParent, createUnitName("libpod", c.ID())), nil
default:
return "", errors.Wrapf(ErrInvalidArg, "unsupported CGroup manager %s in use", c.runtime.config.CgroupManager)
}
}
// RootFsSize returns the root FS size of the container
func (c *Container) RootFsSize() (int64, error) {
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
if err := c.syncContainer(); err != nil {
return -1, errors.Wrapf(err, "error updating container %s state", c.ID())
}
}
return c.rootFsSize()
}
// RWSize returns the rw size of the container
func (c *Container) RWSize() (int64, error) {
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
if err := c.syncContainer(); err != nil {
return -1, errors.Wrapf(err, "error updating container %s state", c.ID())
}
}
return c.rwSize()
}
// IDMappings returns the UID/GID mapping used for the container
func (c *Container) IDMappings() (storage.IDMappingOptions, error) {
return c.config.IDMappings, nil
}
// RootUID returns the root user mapping from container
func (c *Container) RootUID() int {
for _, uidmap := range c.config.IDMappings.UIDMap {
if uidmap.ContainerID == 0 {
return uidmap.HostID
}
}
return 0
}
// RootGID returns the root user mapping from container
func (c *Container) RootGID() int {
for _, gidmap := range c.config.IDMappings.GIDMap {
if gidmap.ContainerID == 0 {
return gidmap.HostID
}
}
return 0
}
// IsInfra returns whether the container is an infra container
func (c *Container) IsInfra() bool {
return c.config.IsInfra
}
// IsReadOnly returns whether the container is running in read only mode
func (c *Container) IsReadOnly() bool {
return c.config.Spec.Root.Readonly
}
// NetworkDisabled returns whether the container is running with a disabled network
func (c *Container) NetworkDisabled() (bool, error) {
if c.config.NetNsCtr != "" {
container, err := c.runtime.state.Container(c.config.NetNsCtr)
if err != nil {
return false, err
}
return networkDisabled(container)
}
return networkDisabled(c)
}
func networkDisabled(c *Container) (bool, error) {
if c.config.CreateNetNS {
return false, nil
}
if !c.config.PostConfigureNetNS {
for _, ns := range c.config.Spec.Linux.Namespaces {
if ns.Type == spec.NetworkNamespace {
return ns.Path == "", nil
}
}
}
return false, nil
}
// ContainerState returns containerstate struct
func (c *Container) ContainerState() (*ContainerState, error) {
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
if err := c.syncContainer(); err != nil {
return nil, err
}
}
returnConfig := new(ContainerState)
deepcopier.Copy(c.state).To(returnConfig)
return c.state, nil
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/derekhjray/podman.git
git@gitee.com:derekhjray/podman.git
derekhjray
podman
podman
v1.1.0

搜索帮助