|
|
4c4c1b |
From 25cc43c376c5ddfa70a6009526f8f03b5235c2c6 Mon Sep 17 00:00:00 2001
|
|
|
4c4c1b |
From: Matthew Heon <mheon@redhat.com>
|
|
|
4c4c1b |
Date: Mon, 11 Nov 2019 09:52:13 -0500
|
|
|
4c4c1b |
Subject: [PATCH 1/2] Add ContainerStateRemoving
|
|
|
4c4c1b |
|
|
|
4c4c1b |
When Libpod removes a container, there is the possibility that
|
|
|
4c4c1b |
removal will not fully succeed. The most notable problems are
|
|
|
4c4c1b |
storage issues, where the container cannot be removed from
|
|
|
4c4c1b |
c/storage.
|
|
|
4c4c1b |
|
|
|
4c4c1b |
When this occurs, we were faced with a choice. We can keep the
|
|
|
4c4c1b |
container in the state, appearing in `podman ps` and available for
|
|
|
4c4c1b |
other API operations, but likely unable to do any of them as it's
|
|
|
4c4c1b |
been partially removed. Or we can remove it very early and clean
|
|
|
4c4c1b |
up after it's already gone. We have, until now, used the second
|
|
|
4c4c1b |
approach.
|
|
|
4c4c1b |
|
|
|
4c4c1b |
The problem that arises is intermittent problems removing
|
|
|
4c4c1b |
storage. We end up removing a container, failing to remove its
|
|
|
4c4c1b |
storage, and ending up with a container permanently stuck in
|
|
|
4c4c1b |
c/storage that we can't remove with the normal Podman CLI, can't
|
|
|
4c4c1b |
use the name of, and generally can't interact with. A notable
|
|
|
4c4c1b |
cause is when Podman is hit by a SIGKILL midway through removal,
|
|
|
4c4c1b |
which can consistently cause `podman rm` to fail to remove
|
|
|
4c4c1b |
storage.
|
|
|
4c4c1b |
|
|
|
4c4c1b |
We now add a new state for containers that are in the process of
|
|
|
4c4c1b |
being removed, ContainerStateRemoving. We set this at the
|
|
|
4c4c1b |
beginning of the removal process. It notifies Podman that the
|
|
|
4c4c1b |
container cannot be used anymore, but preserves it in the DB
|
|
|
4c4c1b |
until it is fully removed. This will allow Remove to be run on
|
|
|
4c4c1b |
these containers again, which should successfully remove storage
|
|
|
4c4c1b |
if it fails.
|
|
|
4c4c1b |
|
|
|
4c4c1b |
Fixes #3906
|
|
|
4c4c1b |
|
|
|
4c4c1b |
Signed-off-by: Matthew Heon <mheon@redhat.com>
|
|
|
4c4c1b |
---
|
|
|
4c4c1b |
cmd/podman/shared/container.go | 2 +
|
|
|
4c4c1b |
libpod/container_api.go | 17 +++++-
|
|
|
4c4c1b |
libpod/container_internal.go | 5 +-
|
|
|
4c4c1b |
libpod/container_internal_linux.go | 5 +-
|
|
|
4c4c1b |
libpod/define/containerstate.go | 7 +++
|
|
|
4c4c1b |
libpod/options.go | 84 +++++-------------------------
|
|
|
4c4c1b |
libpod/runtime_ctr.go | 55 +++++++++++--------
|
|
|
4c4c1b |
libpod/util.go | 25 +++++++++
|
|
|
4c4c1b |
8 files changed, 105 insertions(+), 95 deletions(-)
|
|
|
4c4c1b |
|
|
|
4c4c1b |
diff --git a/cmd/podman/shared/container.go b/cmd/podman/shared/container.go
|
|
|
4c4c1b |
index f49943477f..0a2e96cf7f 100644
|
|
|
4c4c1b |
--- a/cmd/podman/shared/container.go
|
|
|
4c4c1b |
+++ b/cmd/podman/shared/container.go
|
|
|
4c4c1b |
@@ -195,6 +195,8 @@ func NewBatchContainer(ctr *libpod.Container, opts PsOptions) (PsContainerOutput
|
|
|
4c4c1b |
status = "Paused"
|
|
|
4c4c1b |
case define.ContainerStateCreated.String(), define.ContainerStateConfigured.String():
|
|
|
4c4c1b |
status = "Created"
|
|
|
4c4c1b |
+ case define.ContainerStateRemoving.String():
|
|
|
4c4c1b |
+ status = "Removing"
|
|
|
4c4c1b |
default:
|
|
|
4c4c1b |
status = "Error"
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
diff --git a/libpod/container_api.go b/libpod/container_api.go
|
|
|
4c4c1b |
index b8cfe02f6f..153a1d628e 100644
|
|
|
4c4c1b |
--- a/libpod/container_api.go
|
|
|
4c4c1b |
+++ b/libpod/container_api.go
|
|
|
4c4c1b |
@@ -404,6 +404,11 @@ func (c *Container) Mount() (string, error) {
|
|
|
4c4c1b |
return "", err
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
+
|
|
|
4c4c1b |
+ if c.state.State == define.ContainerStateRemoving {
|
|
|
4c4c1b |
+ return "", errors.Wrapf(define.ErrCtrStateInvalid, "cannot mount container %s as it is being removed", c.ID())
|
|
|
4c4c1b |
+ }
|
|
|
4c4c1b |
+
|
|
|
4c4c1b |
defer c.newContainerEvent(events.Mount)
|
|
|
4c4c1b |
return c.mount()
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
@@ -488,7 +493,12 @@ func (c *Container) Export(path string) error {
|
|
|
4c4c1b |
return err
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
- defer c.newContainerEvent(events.Export)
|
|
|
4c4c1b |
+
|
|
|
4c4c1b |
+ if c.state.State == define.ContainerStateRemoving {
|
|
|
4c4c1b |
+ return errors.Wrapf(define.ErrCtrStateInvalid, "cannot mount container %s as it is being removed", c.ID())
|
|
|
4c4c1b |
+ }
|
|
|
4c4c1b |
+
|
|
|
4c4c1b |
+ defer c.newContainerEvent(events.Mount)
|
|
|
4c4c1b |
return c.export(path)
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
|
|
|
4c4c1b |
@@ -674,6 +684,10 @@ func (c *Container) Refresh(ctx context.Context) error {
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
|
|
|
4c4c1b |
+ if c.state.State == define.ContainerStateRemoving {
|
|
|
4c4c1b |
+ return errors.Wrapf(define.ErrCtrStateInvalid, "cannot refresh containers that are being removed")
|
|
|
4c4c1b |
+ }
|
|
|
4c4c1b |
+
|
|
|
4c4c1b |
wasCreated := false
|
|
|
4c4c1b |
if c.state.State == define.ContainerStateCreated {
|
|
|
4c4c1b |
wasCreated = true
|
|
|
4c4c1b |
@@ -819,7 +833,6 @@ func (c *Container) Checkpoint(ctx context.Context, options ContainerCheckpointO
|
|
|
4c4c1b |
return err
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
- defer c.newContainerEvent(events.Checkpoint)
|
|
|
4c4c1b |
return c.checkpoint(ctx, options)
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
|
|
|
4c4c1b |
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
|
|
|
4c4c1b |
index 4ff1913b52..1e8a8a5808 100644
|
|
|
4c4c1b |
--- a/libpod/container_internal.go
|
|
|
4c4c1b |
+++ b/libpod/container_internal.go
|
|
|
4c4c1b |
@@ -719,7 +719,8 @@ func (c *Container) isStopped() (bool, error) {
|
|
|
4c4c1b |
if err != nil {
|
|
|
4c4c1b |
return true, err
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
- return c.state.State != define.ContainerStateRunning && c.state.State != define.ContainerStatePaused, nil
|
|
|
4c4c1b |
+
|
|
|
4c4c1b |
+ return !c.ensureState(define.ContainerStateRunning, define.ContainerStatePaused), nil
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
|
|
|
4c4c1b |
// save container state to the database
|
|
|
4c4c1b |
@@ -1057,6 +1058,8 @@ func (c *Container) initAndStart(ctx context.Context) (err error) {
|
|
|
4c4c1b |
// If we are ContainerStateUnknown, throw an error
|
|
|
4c4c1b |
if c.state.State == define.ContainerStateUnknown {
|
|
|
4c4c1b |
return errors.Wrapf(define.ErrCtrStateInvalid, "container %s is in an unknown state", c.ID())
|
|
|
4c4c1b |
+ } else if c.state.State == define.ContainerStateRemoving {
|
|
|
4c4c1b |
+ return errors.Wrapf(define.ErrCtrStateInvalid, "cannot start container %s as it is being removed", c.ID())
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
|
|
|
4c4c1b |
// If we are running, do nothing
|
|
|
4c4c1b |
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
|
|
|
4c4c1b |
index 26d6771b0f..aca7bdc67a 100644
|
|
|
4c4c1b |
--- a/libpod/container_internal_linux.go
|
|
|
4c4c1b |
+++ b/libpod/container_internal_linux.go
|
|
|
4c4c1b |
@@ -21,6 +21,7 @@ import (
|
|
|
4c4c1b |
"github.com/containernetworking/plugins/pkg/ns"
|
|
|
4c4c1b |
"github.com/containers/buildah/pkg/secrets"
|
|
|
4c4c1b |
"github.com/containers/libpod/libpod/define"
|
|
|
4c4c1b |
+ "github.com/containers/libpod/libpod/events"
|
|
|
4c4c1b |
"github.com/containers/libpod/pkg/annotations"
|
|
|
4c4c1b |
"github.com/containers/libpod/pkg/apparmor"
|
|
|
4c4c1b |
"github.com/containers/libpod/pkg/cgroups"
|
|
|
4c4c1b |
@@ -695,6 +696,8 @@ func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointO
|
|
|
4c4c1b |
return err
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
|
|
|
4c4c1b |
+ defer c.newContainerEvent(events.Checkpoint)
|
|
|
4c4c1b |
+
|
|
|
4c4c1b |
if options.TargetFile != "" {
|
|
|
4c4c1b |
if err = c.exportCheckpoint(options.TargetFile, options.IgnoreRootfs); err != nil {
|
|
|
4c4c1b |
return err
|
|
|
4c4c1b |
@@ -766,7 +769,7 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
|
|
|
4c4c1b |
return err
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
|
|
|
4c4c1b |
- if (c.state.State != define.ContainerStateConfigured) && (c.state.State != define.ContainerStateExited) {
|
|
|
4c4c1b |
+ if !c.ensureState(define.ContainerStateConfigured, define.ContainerStateExited) {
|
|
|
4c4c1b |
return errors.Wrapf(define.ErrCtrStateInvalid, "container %s is running or paused, cannot restore", c.ID())
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
|
|
|
4c4c1b |
diff --git a/libpod/define/containerstate.go b/libpod/define/containerstate.go
|
|
|
4c4c1b |
index ab2527b3ee..e7d258e214 100644
|
|
|
4c4c1b |
--- a/libpod/define/containerstate.go
|
|
|
4c4c1b |
+++ b/libpod/define/containerstate.go
|
|
|
4c4c1b |
@@ -25,6 +25,9 @@ const (
|
|
|
4c4c1b |
// ContainerStateExited indicates the the container has stopped and been
|
|
|
4c4c1b |
// cleaned up
|
|
|
4c4c1b |
ContainerStateExited ContainerStatus = iota
|
|
|
4c4c1b |
+ // ContainerStateRemoving indicates the container is in the process of
|
|
|
4c4c1b |
+ // being removed.
|
|
|
4c4c1b |
+ ContainerStateRemoving ContainerStatus = iota
|
|
|
4c4c1b |
)
|
|
|
4c4c1b |
|
|
|
4c4c1b |
// ContainerStatus returns a string representation for users
|
|
|
4c4c1b |
@@ -45,6 +48,8 @@ func (t ContainerStatus) String() string {
|
|
|
4c4c1b |
return "paused"
|
|
|
4c4c1b |
case ContainerStateExited:
|
|
|
4c4c1b |
return "exited"
|
|
|
4c4c1b |
+ case ContainerStateRemoving:
|
|
|
4c4c1b |
+ return "removing"
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
return "bad state"
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
@@ -67,6 +72,8 @@ func StringToContainerStatus(status string) (ContainerStatus, error) {
|
|
|
4c4c1b |
return ContainerStatePaused, nil
|
|
|
4c4c1b |
case ContainerStateExited.String():
|
|
|
4c4c1b |
return ContainerStateExited, nil
|
|
|
4c4c1b |
+ case ContainerStateRemoving.String():
|
|
|
4c4c1b |
+ return ContainerStateRemoving, nil
|
|
|
4c4c1b |
default:
|
|
|
4c4c1b |
return ContainerStateUnknown, errors.Wrapf(ErrInvalidArg, "unknown container state: %s", status)
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
diff --git a/libpod/options.go b/libpod/options.go
|
|
|
4c4c1b |
index bfbbb9e2da..19c776cf06 100644
|
|
|
4c4c1b |
--- a/libpod/options.go
|
|
|
4c4c1b |
+++ b/libpod/options.go
|
|
|
4c4c1b |
@@ -768,16 +768,8 @@ func WithIPCNSFrom(nsCtr *Container) CtrCreateOption {
|
|
|
4c4c1b |
return define.ErrCtrFinalized
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
|
|
|
4c4c1b |
- if !nsCtr.valid {
|
|
|
4c4c1b |
- return define.ErrCtrRemoved
|
|
|
4c4c1b |
- }
|
|
|
4c4c1b |
-
|
|
|
4c4c1b |
- if nsCtr.ID() == ctr.ID() {
|
|
|
4c4c1b |
- return errors.Wrapf(define.ErrInvalidArg, "must specify another container")
|
|
|
4c4c1b |
- }
|
|
|
4c4c1b |
-
|
|
|
4c4c1b |
- if ctr.config.Pod != "" && nsCtr.config.Pod != ctr.config.Pod {
|
|
|
4c4c1b |
- return errors.Wrapf(define.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, nsCtr.ID())
|
|
|
4c4c1b |
+ if err := checkDependencyContainer(nsCtr, ctr); err != nil {
|
|
|
4c4c1b |
+ return err
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
|
|
|
4c4c1b |
ctr.config.IPCNsCtr = nsCtr.ID()
|
|
|
4c4c1b |
@@ -796,16 +788,8 @@ func WithMountNSFrom(nsCtr *Container) CtrCreateOption {
|
|
|
4c4c1b |
return define.ErrCtrFinalized
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
|
|
|
4c4c1b |
- if !nsCtr.valid {
|
|
|
4c4c1b |
- return define.ErrCtrRemoved
|
|
|
4c4c1b |
- }
|
|
|
4c4c1b |
-
|
|
|
4c4c1b |
- if nsCtr.ID() == ctr.ID() {
|
|
|
4c4c1b |
- return errors.Wrapf(define.ErrInvalidArg, "must specify another container")
|
|
|
4c4c1b |
- }
|
|
|
4c4c1b |
-
|
|
|
4c4c1b |
- if ctr.config.Pod != "" && nsCtr.config.Pod != ctr.config.Pod {
|
|
|
4c4c1b |
- return errors.Wrapf(define.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, nsCtr.ID())
|
|
|
4c4c1b |
+ if err := checkDependencyContainer(nsCtr, ctr); err != nil {
|
|
|
4c4c1b |
+ return err
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
|
|
|
4c4c1b |
ctr.config.MountNsCtr = nsCtr.ID()
|
|
|
4c4c1b |
@@ -824,22 +808,14 @@ func WithNetNSFrom(nsCtr *Container) CtrCreateOption {
|
|
|
4c4c1b |
return define.ErrCtrFinalized
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
|
|
|
4c4c1b |
- if !nsCtr.valid {
|
|
|
4c4c1b |
- return define.ErrCtrRemoved
|
|
|
4c4c1b |
- }
|
|
|
4c4c1b |
-
|
|
|
4c4c1b |
- if nsCtr.ID() == ctr.ID() {
|
|
|
4c4c1b |
- return errors.Wrapf(define.ErrInvalidArg, "must specify another container")
|
|
|
4c4c1b |
+ if err := checkDependencyContainer(nsCtr, ctr); err != nil {
|
|
|
4c4c1b |
+ return err
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
|
|
|
4c4c1b |
if ctr.config.CreateNetNS {
|
|
|
4c4c1b |
return errors.Wrapf(define.ErrInvalidArg, "cannot join another container's net ns as we are making a new net ns")
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
|
|
|
4c4c1b |
- if ctr.config.Pod != "" && nsCtr.config.Pod != ctr.config.Pod {
|
|
|
4c4c1b |
- return errors.Wrapf(define.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, nsCtr.ID())
|
|
|
4c4c1b |
- }
|
|
|
4c4c1b |
-
|
|
|
4c4c1b |
ctr.config.NetNsCtr = nsCtr.ID()
|
|
|
4c4c1b |
|
|
|
4c4c1b |
return nil
|
|
|
4c4c1b |
@@ -856,16 +832,8 @@ func WithPIDNSFrom(nsCtr *Container) CtrCreateOption {
|
|
|
4c4c1b |
return define.ErrCtrFinalized
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
|
|
|
4c4c1b |
- if !nsCtr.valid {
|
|
|
4c4c1b |
- return define.ErrCtrRemoved
|
|
|
4c4c1b |
- }
|
|
|
4c4c1b |
-
|
|
|
4c4c1b |
- if nsCtr.ID() == ctr.ID() {
|
|
|
4c4c1b |
- return errors.Wrapf(define.ErrInvalidArg, "must specify another container")
|
|
|
4c4c1b |
- }
|
|
|
4c4c1b |
-
|
|
|
4c4c1b |
- if ctr.config.Pod != "" && nsCtr.config.Pod != ctr.config.Pod {
|
|
|
4c4c1b |
- return errors.Wrapf(define.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, nsCtr.ID())
|
|
|
4c4c1b |
+ if err := checkDependencyContainer(nsCtr, ctr); err != nil {
|
|
|
4c4c1b |
+ return err
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
|
|
|
4c4c1b |
if ctr.config.NoCgroups {
|
|
|
4c4c1b |
@@ -888,16 +856,8 @@ func WithUserNSFrom(nsCtr *Container) CtrCreateOption {
|
|
|
4c4c1b |
return define.ErrCtrFinalized
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
|
|
|
4c4c1b |
- if !nsCtr.valid {
|
|
|
4c4c1b |
- return define.ErrCtrRemoved
|
|
|
4c4c1b |
- }
|
|
|
4c4c1b |
-
|
|
|
4c4c1b |
- if nsCtr.ID() == ctr.ID() {
|
|
|
4c4c1b |
- return errors.Wrapf(define.ErrInvalidArg, "must specify another container")
|
|
|
4c4c1b |
- }
|
|
|
4c4c1b |
-
|
|
|
4c4c1b |
- if ctr.config.Pod != "" && nsCtr.config.Pod != ctr.config.Pod {
|
|
|
4c4c1b |
- return errors.Wrapf(define.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, nsCtr.ID())
|
|
|
4c4c1b |
+ if err := checkDependencyContainer(nsCtr, ctr); err != nil {
|
|
|
4c4c1b |
+ return err
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
|
|
|
4c4c1b |
ctr.config.UserNsCtr = nsCtr.ID()
|
|
|
4c4c1b |
@@ -917,16 +877,8 @@ func WithUTSNSFrom(nsCtr *Container) CtrCreateOption {
|
|
|
4c4c1b |
return define.ErrCtrFinalized
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
|
|
|
4c4c1b |
- if !nsCtr.valid {
|
|
|
4c4c1b |
- return define.ErrCtrRemoved
|
|
|
4c4c1b |
- }
|
|
|
4c4c1b |
-
|
|
|
4c4c1b |
- if nsCtr.ID() == ctr.ID() {
|
|
|
4c4c1b |
- return errors.Wrapf(define.ErrInvalidArg, "must specify another container")
|
|
|
4c4c1b |
- }
|
|
|
4c4c1b |
-
|
|
|
4c4c1b |
- if ctr.config.Pod != "" && nsCtr.config.Pod != ctr.config.Pod {
|
|
|
4c4c1b |
- return errors.Wrapf(define.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, nsCtr.ID())
|
|
|
4c4c1b |
+ if err := checkDependencyContainer(nsCtr, ctr); err != nil {
|
|
|
4c4c1b |
+ return err
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
|
|
|
4c4c1b |
ctr.config.UTSNsCtr = nsCtr.ID()
|
|
|
4c4c1b |
@@ -945,16 +897,8 @@ func WithCgroupNSFrom(nsCtr *Container) CtrCreateOption {
|
|
|
4c4c1b |
return define.ErrCtrFinalized
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
|
|
|
4c4c1b |
- if !nsCtr.valid {
|
|
|
4c4c1b |
- return define.ErrCtrRemoved
|
|
|
4c4c1b |
- }
|
|
|
4c4c1b |
-
|
|
|
4c4c1b |
- if nsCtr.ID() == ctr.ID() {
|
|
|
4c4c1b |
- return errors.Wrapf(define.ErrInvalidArg, "must specify another container")
|
|
|
4c4c1b |
- }
|
|
|
4c4c1b |
-
|
|
|
4c4c1b |
- if ctr.config.Pod != "" && nsCtr.config.Pod != ctr.config.Pod {
|
|
|
4c4c1b |
- return errors.Wrapf(define.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, nsCtr.ID())
|
|
|
4c4c1b |
+ if err := checkDependencyContainer(nsCtr, ctr); err != nil {
|
|
|
4c4c1b |
+ return err
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
|
|
|
4c4c1b |
ctr.config.CgroupNsCtr = nsCtr.ID()
|
|
|
4c4c1b |
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
|
|
|
4c4c1b |
index 7069d34940..ae401013c8 100644
|
|
|
4c4c1b |
--- a/libpod/runtime_ctr.go
|
|
|
4c4c1b |
+++ b/libpod/runtime_ctr.go
|
|
|
4c4c1b |
@@ -489,32 +489,19 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool,
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
|
|
|
4c4c1b |
- var cleanupErr error
|
|
|
4c4c1b |
- // Remove the container from the state
|
|
|
4c4c1b |
- if c.config.Pod != "" {
|
|
|
4c4c1b |
- // If we're removing the pod, the container will be evicted
|
|
|
4c4c1b |
- // from the state elsewhere
|
|
|
4c4c1b |
- if !removePod {
|
|
|
4c4c1b |
- if err := r.state.RemoveContainerFromPod(pod, c); err != nil {
|
|
|
4c4c1b |
- cleanupErr = err
|
|
|
4c4c1b |
- }
|
|
|
4c4c1b |
- }
|
|
|
4c4c1b |
- } else {
|
|
|
4c4c1b |
- if err := r.state.RemoveContainer(c); err != nil {
|
|
|
4c4c1b |
- cleanupErr = err
|
|
|
4c4c1b |
- }
|
|
|
4c4c1b |
+ // Set ContainerStateRemoving and remove exec sessions
|
|
|
4c4c1b |
+ c.state.State = define.ContainerStateRemoving
|
|
|
4c4c1b |
+ c.state.ExecSessions = nil
|
|
|
4c4c1b |
+
|
|
|
4c4c1b |
+ if err := c.save(); err != nil {
|
|
|
4c4c1b |
+ return errors.Wrapf(err, "unable to set container %s removing state in database", c.ID())
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
|
|
|
4c4c1b |
- // Set container as invalid so it can no longer be used
|
|
|
4c4c1b |
- c.valid = false
|
|
|
4c4c1b |
+ var cleanupErr error
|
|
|
4c4c1b |
|
|
|
4c4c1b |
// Clean up network namespace, cgroups, mounts
|
|
|
4c4c1b |
if err := c.cleanup(ctx); err != nil {
|
|
|
4c4c1b |
- if cleanupErr == nil {
|
|
|
4c4c1b |
- cleanupErr = errors.Wrapf(err, "error cleaning up container %s", c.ID())
|
|
|
4c4c1b |
- } else {
|
|
|
4c4c1b |
- logrus.Errorf("cleanup network, cgroups, mounts: %v", err)
|
|
|
4c4c1b |
- }
|
|
|
4c4c1b |
+ cleanupErr = errors.Wrapf(err, "error cleaning up container %s", c.ID())
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
|
|
|
4c4c1b |
// Stop the container's storage
|
|
|
4c4c1b |
@@ -540,6 +527,29 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool,
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
|
|
|
4c4c1b |
+ // Remove the container from the state
|
|
|
4c4c1b |
+ if c.config.Pod != "" {
|
|
|
4c4c1b |
+ // If we're removing the pod, the container will be evicted
|
|
|
4c4c1b |
+ // from the state elsewhere
|
|
|
4c4c1b |
+ if !removePod {
|
|
|
4c4c1b |
+ if err := r.state.RemoveContainerFromPod(pod, c); err != nil {
|
|
|
4c4c1b |
+ if cleanupErr == nil {
|
|
|
4c4c1b |
+ cleanupErr = err
|
|
|
4c4c1b |
+ } else {
|
|
|
4c4c1b |
+ logrus.Errorf("Error removing container %s from database: %v", c.ID(), err)
|
|
|
4c4c1b |
+ }
|
|
|
4c4c1b |
+ }
|
|
|
4c4c1b |
+ }
|
|
|
4c4c1b |
+ } else {
|
|
|
4c4c1b |
+ if err := r.state.RemoveContainer(c); err != nil {
|
|
|
4c4c1b |
+ if cleanupErr == nil {
|
|
|
4c4c1b |
+ cleanupErr = err
|
|
|
4c4c1b |
+ } else {
|
|
|
4c4c1b |
+ logrus.Errorf("Error removing container %s from database: %v", c.ID(), err)
|
|
|
4c4c1b |
+ }
|
|
|
4c4c1b |
+ }
|
|
|
4c4c1b |
+ }
|
|
|
4c4c1b |
+
|
|
|
4c4c1b |
// Deallocate the container's lock
|
|
|
4c4c1b |
if err := c.lock.Free(); err != nil {
|
|
|
4c4c1b |
if cleanupErr == nil {
|
|
|
4c4c1b |
@@ -549,6 +559,9 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool,
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
|
|
|
4c4c1b |
+ // Set container as invalid so it can no longer be used
|
|
|
4c4c1b |
+ c.valid = false
|
|
|
4c4c1b |
+
|
|
|
4c4c1b |
c.newContainerEvent(events.Remove)
|
|
|
4c4c1b |
|
|
|
4c4c1b |
if !removeVolume {
|
|
|
4c4c1b |
diff --git a/libpod/util.go b/libpod/util.go
|
|
|
4c4c1b |
index bae2f4eb83..30e5cd4c33 100644
|
|
|
4c4c1b |
--- a/libpod/util.go
|
|
|
4c4c1b |
+++ b/libpod/util.go
|
|
|
4c4c1b |
@@ -206,3 +206,28 @@ func DefaultSeccompPath() (string, error) {
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
return config.SeccompDefaultPath, nil
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
+
|
|
|
4c4c1b |
+// CheckDependencyContainer verifies the given container can be used as a
|
|
|
4c4c1b |
+// dependency of another container.
|
|
|
4c4c1b |
+// Both the dependency to check and the container that will be using the
|
|
|
4c4c1b |
+// dependency must be passed in.
|
|
|
4c4c1b |
+// It is assumed that ctr is locked, and depCtr is unlocked.
|
|
|
4c4c1b |
+func checkDependencyContainer(depCtr, ctr *Container) error {
|
|
|
4c4c1b |
+ state, err := depCtr.State()
|
|
|
4c4c1b |
+ if err != nil {
|
|
|
4c4c1b |
+ return errors.Wrapf(err, "error accessing dependency container %s state", depCtr.ID())
|
|
|
4c4c1b |
+ }
|
|
|
4c4c1b |
+ if state == define.ContainerStateRemoving {
|
|
|
4c4c1b |
+ return errors.Wrapf(define.ErrCtrStateInvalid, "cannot use container %s as a dependency as it is being removed", depCtr.ID())
|
|
|
4c4c1b |
+ }
|
|
|
4c4c1b |
+
|
|
|
4c4c1b |
+ if depCtr.ID() == ctr.ID() {
|
|
|
4c4c1b |
+ return errors.Wrapf(define.ErrInvalidArg, "must specify another container")
|
|
|
4c4c1b |
+ }
|
|
|
4c4c1b |
+
|
|
|
4c4c1b |
+ if ctr.config.Pod != "" && depCtr.PodID() != ctr.config.Pod {
|
|
|
4c4c1b |
+ return errors.Wrapf(define.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, depCtr.ID())
|
|
|
4c4c1b |
+ }
|
|
|
4c4c1b |
+
|
|
|
4c4c1b |
+ return nil
|
|
|
4c4c1b |
+}
|
|
|
4c4c1b |
|
|
|
4c4c1b |
From 6c405b5fbcc83ba49c187087eb4e1ccc1a7ff147 Mon Sep 17 00:00:00 2001
|
|
|
4c4c1b |
From: Matthew Heon <mheon@redhat.com>
|
|
|
4c4c1b |
Date: Mon, 11 Nov 2019 14:36:00 -0500
|
|
|
4c4c1b |
Subject: [PATCH 2/2] Error on netns not exist only when ctr is running
|
|
|
4c4c1b |
|
|
|
4c4c1b |
If the container is running and we need to get its netns and
|
|
|
4c4c1b |
can't, that is a serious bug deserving of errors.
|
|
|
4c4c1b |
|
|
|
4c4c1b |
If it's not running, that's not really a big deal. Log an error
|
|
|
4c4c1b |
and continue.
|
|
|
4c4c1b |
|
|
|
4c4c1b |
Signed-off-by: Matthew Heon <mheon@redhat.com>
|
|
|
4c4c1b |
---
|
|
|
4c4c1b |
libpod/boltdb_state_linux.go | 8 +++++++-
|
|
|
4c4c1b |
1 file changed, 7 insertions(+), 1 deletion(-)
|
|
|
4c4c1b |
|
|
|
4c4c1b |
diff --git a/libpod/boltdb_state_linux.go b/libpod/boltdb_state_linux.go
|
|
|
4c4c1b |
index 09a9be6067..6ccda71bd5 100644
|
|
|
4c4c1b |
--- a/libpod/boltdb_state_linux.go
|
|
|
4c4c1b |
+++ b/libpod/boltdb_state_linux.go
|
|
|
4c4c1b |
@@ -3,6 +3,8 @@
|
|
|
4c4c1b |
package libpod
|
|
|
4c4c1b |
|
|
|
4c4c1b |
import (
|
|
|
4c4c1b |
+ "github.com/containers/libpod/libpod/define"
|
|
|
4c4c1b |
+ "github.com/pkg/errors"
|
|
|
4c4c1b |
"github.com/sirupsen/logrus"
|
|
|
4c4c1b |
)
|
|
|
4c4c1b |
|
|
|
4c4c1b |
@@ -25,8 +27,12 @@ func replaceNetNS(netNSPath string, ctr *Container, newState *ContainerState) er
|
|
|
4c4c1b |
if err == nil {
|
|
|
4c4c1b |
newState.NetNS = ns
|
|
|
4c4c1b |
} else {
|
|
|
4c4c1b |
+ if ctr.ensureState(define.ContainerStateRunning, define.ContainerStatePaused) {
|
|
|
4c4c1b |
+ return errors.Wrapf(err, "error joning network namespace of container %s", ctr.ID())
|
|
|
4c4c1b |
+ }
|
|
|
4c4c1b |
+
|
|
|
4c4c1b |
logrus.Errorf("error joining network namespace for container %s: %v", ctr.ID(), err)
|
|
|
4c4c1b |
- ctr.valid = false
|
|
|
4c4c1b |
+ ctr.state.NetNS = nil
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
}
|
|
|
4c4c1b |
} else {
|