summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'libpod')
-rw-r--r--libpod/container_internal.go24
-rw-r--r--libpod/container_internal_linux.go19
-rw-r--r--libpod/container_log.go4
-rw-r--r--libpod/define/errors.go3
-rw-r--r--libpod/define/pod_inspect.go3
-rw-r--r--libpod/filters/pods.go8
-rw-r--r--libpod/image/filters.go6
-rw-r--r--libpod/oci.go7
-rw-r--r--libpod/oci_conmon_linux.go25
-rw-r--r--libpod/oci_missing.go5
-rw-r--r--libpod/oci_util.go36
-rw-r--r--libpod/options.go24
-rw-r--r--libpod/pod.go25
-rw-r--r--libpod/pod_api.go1
-rw-r--r--libpod/runtime_ctr.go6
-rw-r--r--libpod/runtime_pod_infra_linux.go3
16 files changed, 178 insertions, 21 deletions
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 43e873bd6..f6fc3c1a4 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -1209,13 +1209,35 @@ func (c *Container) stop(timeout uint) error {
}
}
+ // Check if conmon is still alive.
+ // If it is not, we won't be getting an exit file.
+ conmonAlive, err := c.ociRuntime.CheckConmonRunning(c)
+ if err != nil {
+ return err
+ }
+
if err := c.ociRuntime.StopContainer(c, timeout, all); err != nil {
return err
}
+ c.newContainerEvent(events.Stop)
+
c.state.PID = 0
c.state.ConmonPID = 0
c.state.StoppedByUser = true
+
+ if !conmonAlive {
+ // Conmon is dead, so we can't epect an exit code.
+ c.state.ExitCode = -1
+ c.state.FinishedTime = time.Now()
+ c.state.State = define.ContainerStateStopped
+ if err := c.save(); err != nil {
+ logrus.Errorf("Error saving container %s status: %v", c.ID(), err)
+ }
+
+ return errors.Wrapf(define.ErrConmonDead, "container %s conmon process missing, cannot retrieve exit code", c.ID())
+ }
+
if err := c.save(); err != nil {
return errors.Wrapf(err, "error saving container %s state after stopping", c.ID())
}
@@ -1225,8 +1247,6 @@ func (c *Container) stop(timeout uint) error {
return err
}
- c.newContainerEvent(events.Stop)
-
return nil
}
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index d08e012a6..9afe11b2b 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -79,7 +79,8 @@ func (c *Container) prepare() error {
go func() {
defer wg.Done()
// Set up network namespace if not already set up
- if c.config.CreateNetNS && c.state.NetNS == nil && !c.config.PostConfigureNetNS {
+ noNetNS := c.state.NetNS == nil
+ if c.config.CreateNetNS && noNetNS && !c.config.PostConfigureNetNS {
netNS, networkStatus, createNetNSErr = c.runtime.createNetNS(c)
if createNetNSErr != nil {
return
@@ -94,7 +95,7 @@ func (c *Container) prepare() error {
}
// handle rootless network namespace setup
- if c.state.NetNS != nil && c.config.NetMode.IsSlirp4netns() && !c.config.PostConfigureNetNS {
+ if noNetNS && c.config.NetMode.IsSlirp4netns() && !c.config.PostConfigureNetNS {
createNetNSErr = c.runtime.setupRootlessNetNS(c)
}
}()
@@ -392,7 +393,7 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
}
for _, i := range c.config.Spec.Linux.Namespaces {
- if i.Type == spec.UTSNamespace {
+ if i.Type == spec.UTSNamespace && i.Path == "" {
hostname := c.Hostname()
g.SetHostname(hostname)
g.AddProcessEnv("HOSTNAME", hostname)
@@ -591,7 +592,8 @@ func (c *Container) addNamespaceContainer(g *generate.Generator, ns LinuxNS, ctr
if specNS == spec.UTSNamespace {
hostname := nsCtr.Hostname()
- g.SetHostname(hostname)
+ // Joining an existing namespace, cannot set the hostname
+ g.SetHostname("")
g.AddProcessEnv("HOSTNAME", hostname)
}
@@ -1171,6 +1173,15 @@ func (c *Container) makeBindMounts() error {
// finally, save it in the new container
c.state.BindMounts["/etc/hosts"] = hostsPath
}
+
+ if !hasCurrentUserMapped(c) {
+ if err := makeAccessible(resolvPath, c.RootUID(), c.RootGID()); err != nil {
+ return err
+ }
+ if err := makeAccessible(hostsPath, c.RootUID(), c.RootGID()); err != nil {
+ return err
+ }
+ }
} else {
if !c.config.UseImageResolvConf {
newResolv, err := c.generateResolvConf()
diff --git a/libpod/container_log.go b/libpod/container_log.go
index bfa303e84..c3a84d048 100644
--- a/libpod/container_log.go
+++ b/libpod/container_log.go
@@ -19,7 +19,7 @@ func (r *Runtime) Log(containers []*Container, options *logs.LogOptions, logChan
return nil
}
-// ReadLog reads a containers log based on the input options and returns loglines over a channel
+// ReadLog reads a containers log based on the input options and returns loglines over a channel.
func (c *Container) ReadLog(options *logs.LogOptions, logChannel chan *logs.LogLine) error {
// TODO Skip sending logs until journald logs can be read
// TODO make this not a magic string
@@ -61,7 +61,7 @@ func (c *Container) readFromLogFile(options *logs.LogOptions, logChannel chan *l
partial += nll.Msg
continue
} else if !nll.Partial() && len(partial) > 1 {
- nll.Msg = partial
+ nll.Msg = partial + nll.Msg
partial = ""
}
nll.CID = c.ID()
diff --git a/libpod/define/errors.go b/libpod/define/errors.go
index 16df2a1cc..083553b7e 100644
--- a/libpod/define/errors.go
+++ b/libpod/define/errors.go
@@ -141,6 +141,9 @@ var (
// ErrConmonOutdated indicates the version of conmon found (whether via the configuration or $PATH)
// is out of date for the current podman version
ErrConmonOutdated = errors.New("outdated conmon version")
+ // ErrConmonDead indicates that the container's conmon process has been
+ // killed, preventing normal operation.
+ ErrConmonDead = errors.New("conmon process killed")
// ErrImageInUse indicates the requested operation failed because the image was in use
ErrImageInUse = errors.New("image is being used")
diff --git a/libpod/define/pod_inspect.go b/libpod/define/pod_inspect.go
index 26fd2cab4..7f06e16fc 100644
--- a/libpod/define/pod_inspect.go
+++ b/libpod/define/pod_inspect.go
@@ -18,6 +18,9 @@ type InspectPodData struct {
Namespace string `json:"Namespace,omitempty"`
// Created is the time when the pod was created.
Created time.Time
+ // CreateCommand is the full command plus arguments of the process the
+ // container has been created with.
+ CreateCommand []string `json:"CreateCommand,omitempty"`
// State represents the current state of the pod.
State string `json:"State"`
// Hostname is the hostname that the pod will set.
diff --git a/libpod/filters/pods.go b/libpod/filters/pods.go
index 9bf436eab..0edb9fbf2 100644
--- a/libpod/filters/pods.go
+++ b/libpod/filters/pods.go
@@ -57,13 +57,13 @@ func GeneratePodFilterFunc(filter, filterValue string) (
return nil, errors.Errorf("%s is not a valid status", filterValue)
}
return func(p *libpod.Pod) bool {
- ctr_statuses, err := p.Status()
+ ctrStatuses, err := p.Status()
if err != nil {
return false
}
- for _, ctr_status := range ctr_statuses {
- state := ctr_status.String()
- if ctr_status == define.ContainerStateConfigured {
+ for _, ctrStatus := range ctrStatuses {
+ state := ctrStatus.String()
+ if ctrStatus == define.ContainerStateConfigured {
state = "created"
}
if state == filterValue {
diff --git a/libpod/image/filters.go b/libpod/image/filters.go
index 747eba165..9d99fb344 100644
--- a/libpod/image/filters.go
+++ b/libpod/image/filters.go
@@ -102,8 +102,8 @@ func ReferenceFilter(ctx context.Context, referenceFilter string) ResultFilter {
}
}
-// IdFilter allows you to filter by image Id
-func IdFilter(idFilter string) ResultFilter {
+// IDFilter allows you to filter by image Id
+func IDFilter(idFilter string) ResultFilter {
return func(i *Image) bool {
return i.ID() == idFilter
}
@@ -172,7 +172,7 @@ func (ir *Runtime) createFilterFuncs(filters []string, img *Image) ([]ResultFilt
case "reference":
filterFuncs = append(filterFuncs, ReferenceFilter(ctx, splitFilter[1]))
case "id":
- filterFuncs = append(filterFuncs, IdFilter(splitFilter[1]))
+ filterFuncs = append(filterFuncs, IDFilter(splitFilter[1]))
default:
return nil, errors.Errorf("invalid filter %s ", splitFilter[0])
}
diff --git a/libpod/oci.go b/libpod/oci.go
index 684a7ba42..c2f0041b1 100644
--- a/libpod/oci.go
+++ b/libpod/oci.go
@@ -107,6 +107,13 @@ type OCIRuntime interface {
// error.
CheckpointContainer(ctr *Container, options ContainerCheckpointOptions) error
+ // CheckConmonRunning verifies that the given container's Conmon
+ // instance is still running. Runtimes without Conmon, or systems where
+ // the PID of conmon is not available, should mock this as True.
+ // True indicates that Conmon for the instance is running, False
+ // indicates it is not.
+ CheckConmonRunning(ctr *Container) (bool, error)
+
// SupportsCheckpoint returns whether this OCI runtime
// implementation supports the CheckpointContainer() operation.
SupportsCheckpoint() bool
diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go
index 9c92b036e..0921a532b 100644
--- a/libpod/oci_conmon_linux.go
+++ b/libpod/oci_conmon_linux.go
@@ -669,6 +669,31 @@ func (r *ConmonOCIRuntime) CheckpointContainer(ctr *Container, options Container
return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, nil, r.path, args...)
}
+func (r *ConmonOCIRuntime) CheckConmonRunning(ctr *Container) (bool, error) {
+ if ctr.state.ConmonPID == 0 {
+ // If the container is running or paused, assume Conmon is
+ // running. We didn't record Conmon PID on some old versions, so
+ // that is likely what's going on...
+ // Unusual enough that we should print a warning message though.
+ if ctr.ensureState(define.ContainerStateRunning, define.ContainerStatePaused) {
+ logrus.Warnf("Conmon PID is not set, but container is running!")
+ return true, nil
+ }
+ // Container's not running, so conmon PID being unset is
+ // expected. Conmon is not running.
+ return false, nil
+ }
+
+ // We have a conmon PID. Ping it with signal 0.
+ if err := unix.Kill(ctr.state.ConmonPID, 0); err != nil {
+ if err == unix.ESRCH {
+ return false, nil
+ }
+ return false, errors.Wrapf(err, "error pinging container %s conmon with signal 0", ctr.ID())
+ }
+ return true, nil
+}
+
// SupportsCheckpoint checks if the OCI runtime supports checkpointing
// containers.
func (r *ConmonOCIRuntime) SupportsCheckpoint() bool {
diff --git a/libpod/oci_missing.go b/libpod/oci_missing.go
index 4da16876c..90e90cc6c 100644
--- a/libpod/oci_missing.go
+++ b/libpod/oci_missing.go
@@ -163,6 +163,11 @@ func (r *MissingRuntime) CheckpointContainer(ctr *Container, options ContainerCh
return r.printError()
}
+// CheckConmonRunning is not available as the runtime is missing
+func (r *MissingRuntime) CheckConmonRunning(ctr *Container) (bool, error) {
+ return false, r.printError()
+}
+
// SupportsCheckpoint returns false as checkpointing requires a working runtime
func (r *MissingRuntime) SupportsCheckpoint() bool {
return false
diff --git a/libpod/oci_util.go b/libpod/oci_util.go
index 53567d2d0..8b40dad81 100644
--- a/libpod/oci_util.go
+++ b/libpod/oci_util.go
@@ -36,14 +36,30 @@ func bindPorts(ports []ocicni.PortMapping) ([]*os.File, error) {
var files []*os.File
notifySCTP := false
for _, i := range ports {
+ isV6 := net.ParseIP(i.HostIP).To4() == nil
+ if i.HostIP == "" {
+ isV6 = false
+ }
switch i.Protocol {
case "udp":
- addr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", i.HostIP, i.HostPort))
+ var (
+ addr *net.UDPAddr
+ err error
+ )
+ if isV6 {
+ addr, err = net.ResolveUDPAddr("udp6", fmt.Sprintf("[%s]:%d", i.HostIP, i.HostPort))
+ } else {
+ addr, err = net.ResolveUDPAddr("udp4", fmt.Sprintf("%s:%d", i.HostIP, i.HostPort))
+ }
if err != nil {
return nil, errors.Wrapf(err, "cannot resolve the UDP address")
}
- server, err := net.ListenUDP("udp", addr)
+ proto := "udp4"
+ if isV6 {
+ proto = "udp6"
+ }
+ server, err := net.ListenUDP(proto, addr)
if err != nil {
return nil, errors.Wrapf(err, "cannot listen on the UDP port")
}
@@ -54,12 +70,24 @@ func bindPorts(ports []ocicni.PortMapping) ([]*os.File, error) {
files = append(files, f)
case "tcp":
- addr, err := net.ResolveTCPAddr("tcp4", fmt.Sprintf("%s:%d", i.HostIP, i.HostPort))
+ var (
+ addr *net.TCPAddr
+ err error
+ )
+ if isV6 {
+ addr, err = net.ResolveTCPAddr("tcp6", fmt.Sprintf("[%s]:%d", i.HostIP, i.HostPort))
+ } else {
+ addr, err = net.ResolveTCPAddr("tcp4", fmt.Sprintf("%s:%d", i.HostIP, i.HostPort))
+ }
if err != nil {
return nil, errors.Wrapf(err, "cannot resolve the TCP address")
}
- server, err := net.ListenTCP("tcp4", addr)
+ proto := "tcp4"
+ if isV6 {
+ proto = "tcp6"
+ }
+ server, err := net.ListenTCP(proto, addr)
if err != nil {
return nil, errors.Wrapf(err, "cannot listen on the TCP port")
}
diff --git a/libpod/options.go b/libpod/options.go
index 8e0d3df86..5a0f60093 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -1538,6 +1538,30 @@ func WithPodHostname(hostname string) PodCreateOption {
}
}
+// WithPodCreateCommand adds the full command plus arguments of the current
+// process to the pod config.
+func WithPodCreateCommand() PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return define.ErrPodFinalized
+ }
+ pod.config.CreateCommand = os.Args
+ return nil
+ }
+}
+
+// WithInfraConmonPidFile sets the path to a custom conmon PID file for the
+// infra container.
+func WithInfraConmonPidFile(path string) PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return define.ErrPodFinalized
+ }
+ pod.config.InfraContainer.ConmonPidFile = path
+ return nil
+ }
+}
+
// WithPodLabels sets the labels of a pod.
func WithPodLabels(labels map[string]string) PodCreateOption {
return func(pod *Pod) error {
diff --git a/libpod/pod.go b/libpod/pod.go
index 8afaa6052..bf0d7a397 100644
--- a/libpod/pod.go
+++ b/libpod/pod.go
@@ -64,6 +64,10 @@ type PodConfig struct {
// Time pod was created
CreatedTime time.Time `json:"created"`
+ // CreateCommand is the full command plus arguments of the process the
+ // container has been created with.
+ CreateCommand []string `json:"CreateCommand,omitempty"`
+
// ID of the pod's lock
LockID uint32 `json:"lockID"`
}
@@ -79,6 +83,7 @@ type podState struct {
// InfraContainerConfig is the configuration for the pod's infra container
type InfraContainerConfig struct {
+ ConmonPidFile string `json:"conmonPidFile"`
HasInfraContainer bool `json:"makeInfraContainer"`
HostNetwork bool `json:"infraHostNetwork,omitempty"`
PortBindings []ocicni.PortMapping `json:"infraPortBindings"`
@@ -124,6 +129,12 @@ func (p *Pod) CreatedTime() time.Time {
return p.config.CreatedTime
}
+// CreateCommand returns the os.Args of the process with which the pod has been
+// created.
+func (p *Pod) CreateCommand() []string {
+ return p.config.CreateCommand
+}
+
// CgroupParent returns the pod's CGroup parent
func (p *Pod) CgroupParent() string {
return p.config.CgroupParent
@@ -246,6 +257,20 @@ func (p *Pod) InfraContainerID() (string, error) {
return p.state.InfraContainerID, nil
}
+// InfraContainer returns the infra container.
+func (p *Pod) InfraContainer() (*Container, error) {
+ if !p.HasInfraContainer() {
+ return nil, errors.Wrap(define.ErrNoSuchCtr, "pod has no infra container")
+ }
+
+ id, err := p.InfraContainerID()
+ if err != nil {
+ return nil, err
+ }
+
+ return p.runtime.state.Container(id)
+}
+
// TODO add pod batching
// Lock pod to avoid lock contention
// Store and lock all containers (no RemoveContainer in batch guarantees cache will not become stale)
diff --git a/libpod/pod_api.go b/libpod/pod_api.go
index e2c4b515d..c8605eb69 100644
--- a/libpod/pod_api.go
+++ b/libpod/pod_api.go
@@ -489,6 +489,7 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) {
Name: p.Name(),
Namespace: p.Namespace(),
Created: p.CreatedTime(),
+ CreateCommand: p.config.CreateCommand,
State: podState,
Hostname: p.config.Hostname,
Labels: p.Labels(),
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index 655b42e51..aa91dff03 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -464,9 +464,11 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool,
}
}
- // Check that the container's in a good state to be removed
+ // Check that the container's in a good state to be removed.
if c.state.State == define.ContainerStateRunning {
- if err := c.stop(c.StopTimeout()); err != nil {
+ // Ignore ErrConmonDead - we couldn't retrieve the container's
+ // exit code properly, but it's still stopped.
+ if err := c.stop(c.StopTimeout()); err != nil && errors.Cause(err) != define.ErrConmonDead {
return errors.Wrapf(err, "cannot remove container %s as it could not be stopped", c.ID())
}
}
diff --git a/libpod/runtime_pod_infra_linux.go b/libpod/runtime_pod_infra_linux.go
index 06a7b3936..a0dee3aa1 100644
--- a/libpod/runtime_pod_infra_linux.go
+++ b/libpod/runtime_pod_infra_linux.go
@@ -130,6 +130,9 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, rawIm
options = append(options, WithRootFSFromImage(imgID, imgName, rawImageName))
options = append(options, WithName(containerName))
options = append(options, withIsInfra())
+ if len(p.config.InfraContainer.ConmonPidFile) > 0 {
+ options = append(options, WithConmonPidFile(p.config.InfraContainer.ConmonPidFile))
+ }
return r.newContainer(ctx, g.Config, options...)
}