Skip to content

Commit 3cae574

Browse files
Merge pull request #18507 from mheon/fix_rm_depends
Fix `podman rm -fa` with dependencies
2 parents 1e1efd8 + 2ebc900 commit 3cae574

File tree

23 files changed

+511
-250
lines changed

23 files changed

+511
-250
lines changed

cmd/podman/pods/rm.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,10 @@ func removePods(namesOrIDs []string, rmOptions entities.PodRmOptions, printIDs b
113113
return nil
114114
}
115115
setExitCode(err)
116-
return append(errs, err)
116+
errs = append(errs, err)
117+
if !strings.Contains(err.Error(), define.ErrRemovingCtrs.Error()) {
118+
return errs
119+
}
117120
}
118121

119122
// in the cli, first we print out all the successful attempts
@@ -128,6 +131,11 @@ func removePods(namesOrIDs []string, rmOptions entities.PodRmOptions, printIDs b
128131
}
129132
setExitCode(r.Err)
130133
errs = append(errs, r.Err)
134+
for ctr, err := range r.RemovedCtrs {
135+
if err != nil {
136+
errs = append(errs, fmt.Errorf("error removing container %s from pod %s: %w", ctr, r.Id, err))
137+
}
138+
}
131139
}
132140
}
133141
return errs

libpod/container_graph.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,13 @@ func removeNode(ctx context.Context, node *containerNode, pod *Pod, force bool,
359359
}
360360

361361
if !ctrErrored {
362-
if err := node.container.runtime.removeContainer(ctx, node.container, force, false, true, false, timeout); err != nil {
362+
opts := ctrRmOpts{
363+
Force: force,
364+
RemovePod: true,
365+
Timeout: timeout,
366+
}
367+
368+
if _, _, err := node.container.runtime.removeContainer(ctx, node.container, opts); err != nil {
363369
ctrErrored = true
364370
ctrErrors[node.id] = err
365371
}

libpod/define/errors.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,4 +211,8 @@ var (
211211
// ErrConmonVersionFormat is used when the expected version format of conmon
212212
// has changed.
213213
ErrConmonVersionFormat = "conmon version changed format"
214+
215+
// ErrRemovingCtrs indicates that there was an error removing all
216+
// containers from a pod.
217+
ErrRemovingCtrs = errors.New("removing pod containers")
214218
)

libpod/lock/shm/shm_lock.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,14 @@ shm_struct_t *setup_lock_shm(char *path, uint32_t num_locks, int *error_code) {
142142
goto CLEANUP_UNMAP;
143143
}
144144

145+
// Ensure that recursive locking of a mutex by the same OS thread (which may
146+
// refer to numerous goroutines) blocks.
147+
ret_code = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
148+
if (ret_code != 0) {
149+
*error_code = -1 * ret_code;
150+
goto CLEANUP_FREEATTR;
151+
}
152+
145153
// Set mutexes to pshared - multiprocess-safe
146154
ret_code = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
147155
if (ret_code != 0) {

libpod/oci_conmon_common.go

Lines changed: 76 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -356,10 +356,20 @@ func generateResourceFile(res *spec.LinuxResources) (string, []string, error) {
356356
// If all is set, send to all PIDs in the container.
357357
// All is only supported if the container created cgroups.
358358
func (r *ConmonOCIRuntime) KillContainer(ctr *Container, signal uint, all bool) error {
359+
if _, err := r.killContainer(ctr, signal, all, false); err != nil {
360+
return err
361+
}
362+
363+
return nil
364+
}
365+
366+
// If captureStderr is requested, OCI runtime STDERR will be captured as a
367+
// *bytes.buffer and returned; otherwise, it is set to os.Stderr.
368+
func (r *ConmonOCIRuntime) killContainer(ctr *Container, signal uint, all, captureStderr bool) (*bytes.Buffer, error) {
359369
logrus.Debugf("Sending signal %d to container %s", signal, ctr.ID())
360370
runtimeDir, err := util.GetRuntimeDir()
361371
if err != nil {
362-
return err
372+
return nil, err
363373
}
364374
env := []string{fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir)}
365375
var args []string
@@ -369,19 +379,27 @@ func (r *ConmonOCIRuntime) KillContainer(ctr *Container, signal uint, all bool)
369379
} else {
370380
args = append(args, "kill", ctr.ID(), fmt.Sprintf("%d", signal))
371381
}
372-
if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, env, r.path, args...); err != nil {
382+
var (
383+
stderr io.Writer = os.Stderr
384+
stderrBuffer *bytes.Buffer
385+
)
386+
if captureStderr {
387+
stderrBuffer = new(bytes.Buffer)
388+
stderr = stderrBuffer
389+
}
390+
if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, stderr, env, r.path, args...); err != nil {
373391
// Update container state - there's a chance we failed because
374392
// the container exited in the meantime.
375393
if err2 := r.UpdateContainerStatus(ctr); err2 != nil {
376394
logrus.Infof("Error updating status for container %s: %v", ctr.ID(), err2)
377395
}
378396
if ctr.ensureState(define.ContainerStateStopped, define.ContainerStateExited) {
379-
return fmt.Errorf("%w: %s", define.ErrCtrStateInvalid, ctr.state.State)
397+
return stderrBuffer, fmt.Errorf("%w: %s", define.ErrCtrStateInvalid, ctr.state.State)
380398
}
381-
return fmt.Errorf("sending signal to container %s: %w", ctr.ID(), err)
399+
return stderrBuffer, fmt.Errorf("sending signal to container %s: %w", ctr.ID(), err)
382400
}
383401

384-
return nil
402+
return stderrBuffer, nil
385403
}
386404

387405
// StopContainer stops a container, first using its given stop signal (or
@@ -400,23 +418,65 @@ func (r *ConmonOCIRuntime) StopContainer(ctr *Container, timeout uint, all bool)
400418
return nil
401419
}
402420

403-
if timeout > 0 {
404-
stopSignal := ctr.config.StopSignal
405-
if stopSignal == 0 {
406-
stopSignal = uint(syscall.SIGTERM)
421+
killCtr := func(signal uint) (bool, error) {
422+
stderr, err := r.killContainer(ctr, signal, all, true)
423+
424+
// Before handling error from KillContainer, convert STDERR to a []string
425+
// (one string per line of output) and print it, ignoring known OCI runtime
426+
// errors that we don't care about
427+
stderrLines := strings.Split(stderr.String(), "\n")
428+
for _, line := range stderrLines {
429+
if line == "" {
430+
continue
431+
}
432+
if strings.Contains(line, "container not running") || strings.Contains(line, "open pidfd: No such process") {
433+
logrus.Debugf("Failure to kill container (already stopped?): logged %s", line)
434+
continue
435+
}
436+
fmt.Fprintf(os.Stderr, "%s\n", line)
407437
}
408-
if err := r.KillContainer(ctr, stopSignal, all); err != nil {
438+
439+
if err != nil {
440+
// There's an inherent race with the cleanup process (see
441+
// #16142, #17142). If the container has already been marked as
442+
// stopped or exited by the cleanup process, we can return
443+
// immediately.
444+
if errors.Is(err, define.ErrCtrStateInvalid) && ctr.ensureState(define.ContainerStateStopped, define.ContainerStateExited) {
445+
return true, nil
446+
}
447+
448+
// If the PID is 0, then the container is already stopped.
449+
if ctr.state.PID == 0 {
450+
return true, nil
451+
}
452+
409453
// Is the container gone?
410454
// If so, it probably died between the first check and
411455
// our sending the signal
412456
// The container is stopped, so exit cleanly
413457
err := unix.Kill(ctr.state.PID, 0)
414458
if err == unix.ESRCH {
415-
return nil
459+
return true, nil
416460
}
417461

462+
return false, err
463+
}
464+
return false, nil
465+
}
466+
467+
if timeout > 0 {
468+
stopSignal := ctr.config.StopSignal
469+
if stopSignal == 0 {
470+
stopSignal = uint(syscall.SIGTERM)
471+
}
472+
473+
stopped, err := killCtr(stopSignal)
474+
if err != nil {
418475
return err
419476
}
477+
if stopped {
478+
return nil
479+
}
420480

421481
if err := waitContainerStop(ctr, time.Duration(timeout)*time.Second); err != nil {
422482
logrus.Debugf("Timed out stopping container %s with %s, resorting to SIGKILL: %v", ctr.ID(), unix.SignalName(syscall.Signal(stopSignal)), err)
@@ -427,27 +487,13 @@ func (r *ConmonOCIRuntime) StopContainer(ctr *Container, timeout uint, all bool)
427487
}
428488
}
429489

430-
// If the timeout was set to 0 or if stopping the container with the
431-
// specified signal did not work, use the big hammer with SIGKILL.
432-
if err := r.KillContainer(ctr, uint(unix.SIGKILL), all); err != nil {
433-
// There's an inherent race with the cleanup process (see
434-
// #16142, #17142). If the container has already been marked as
435-
// stopped or exited by the cleanup process, we can return
436-
// immediately.
437-
if errors.Is(err, define.ErrCtrStateInvalid) && ctr.ensureState(define.ContainerStateStopped, define.ContainerStateExited) {
438-
return nil
439-
}
440-
441-
// If the PID is 0, then the container is already stopped.
442-
if ctr.state.PID == 0 {
443-
return nil
444-
}
445-
// Again, check if the container is gone. If it is, exit cleanly.
446-
if aliveErr := unix.Kill(ctr.state.PID, 0); errors.Is(aliveErr, unix.ESRCH) {
447-
return nil
448-
}
490+
stopped, err := killCtr(uint(unix.SIGKILL))
491+
if err != nil {
449492
return fmt.Errorf("sending SIGKILL to container %s: %w", ctr.ID(), err)
450493
}
494+
if stopped {
495+
return nil
496+
}
451497

452498
// Give runtime a few seconds to make it happen
453499
if err := waitContainerStop(ctr, killContainerTimeout); err != nil {

libpod/pod_api.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,12 @@ func (p *Pod) startInitContainers(ctx context.Context) error {
4040
icLock := initCon.lock
4141
icLock.Lock()
4242
var time *uint
43-
if err := p.runtime.removeContainer(ctx, initCon, false, false, true, false, time); err != nil {
43+
opts := ctrRmOpts{
44+
RemovePod: true,
45+
Timeout: time,
46+
}
47+
48+
if _, _, err := p.runtime.removeContainer(ctx, initCon, opts); err != nil {
4449
icLock.Unlock()
4550
return fmt.Errorf("failed to remove once init container %s: %w", initCon.ID(), err)
4651
}

libpod/reset.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,15 @@ func (r *Runtime) reset(ctx context.Context) error {
9797
return err
9898
}
9999
for _, p := range pods {
100-
if err := r.RemovePod(ctx, p, true, true, timeout); err != nil {
100+
if ctrs, err := r.RemovePod(ctx, p, true, true, timeout); err != nil {
101101
if errors.Is(err, define.ErrNoSuchPod) {
102102
continue
103103
}
104+
for ctr, err := range ctrs {
105+
if err != nil {
106+
logrus.Errorf("Error removing pod %s container %s: %v", p.ID(), ctr, err)
107+
}
108+
}
104109
logrus.Errorf("Removing Pod %s: %v", p.ID(), err)
105110
}
106111
}

0 commit comments

Comments
 (0)