Repository: containerd/containerd
File: internal/cri/server/sandbox_stop.go (Go)

Code before:

	span.AddEvent("sandbox container stopped",
		tracing.Attribute("sandbox.stop.duration", time.Since(stop).String()),
	)

	err := c.nri.StopPodSandbox(ctx, &sandbox)
	if err != nil {
		log.G(ctx).WithError(err).Errorf("NRI sandbox stop notification failed")
	}

	// Teardown network for sandbox.
	if sandbox.NetNS != nil {
		span.AddEvent("start pod network teardown")
		netStop := time.Now()
		// Use empty netns path if netns is not available. This is defined in:
		// https://github.com/containernetworking/cni/blob/v0.7.0-alpha1/SPEC.md
		if closed, err := sandbox.NetNS.Closed(); err != nil {
			return fmt.Errorf("failed to check network namespace closed: %w", err)
		} else if closed {
			sandbox.NetNSPath = ""
		}
		if sandbox.CNIResult != nil {
			if err := c.teardownPodNetwork(ctx, sandbox); err != nil {
				return fmt.Errorf("failed to destroy network for sandbox %q: %w", id, err)
			}
		} else {
			log.G(ctx).Warnf("CNI result is not found for sandbox %q, attempting teardown anyway, ignoring errors", id)
			_ = c.teardownPodNetwork(ctx, sandbox)
		}
		if err := sandbox.NetNS.Remove(); err != nil {
			return fmt.Errorf("failed to remove network namespace for sandbox %q: %w", id, err)
		}
		sandboxDeleteNetwork.UpdateSince(netStop)

		span.AddEvent("finished pod network teardown",
			tracing.Attribute("network.teardown.duration", time.Since(netStop).String()),
		)
	}

	log.G(ctx).Infof("TearDown network for sandbox %q successfully", id)

	err = c.cleanupImageMounts(ctx, id)
	if err != nil {
		return fmt.Errorf("failed to cleanup image mounts for sandbox %q: %w", id, err)
	}
	return nil
}

// waitSandboxStop waits for sandbox to be stopped until context is cancelled or
// the context deadline is exceeded.
func (c *criService) waitSandboxStop(ctx context.Context, sandbox sandboxstore.Sandbox) error {

Review comment (bug):
suggest:
```
        if err := c.teardownPodNetwork(ctx, sandbox); err != nil {
            if sandbox.CNIResult != nil {
                return fmt.Errorf("failed to destroy network for sandbox %q: %w", id, err)
            } else {
			    log.G(ctx).Warnf("failed to destroy network for sandbox %q: %w; and ignoring because the sandbox network setup result is nil indicating the network setup never completed",  id, err)
            }
        } 

```

Code after:

	span.AddEvent("sandbox container stopped",
		tracing.Attribute("sandbox.stop.duration", time.Since(stop).String()),
	)

	err := c.nri.StopPodSandbox(ctx, &sandbox)
	if err != nil {
		log.G(ctx).WithError(err).Errorf("NRI sandbox stop notification failed")
	}

	// Teardown network for sandbox.
	if sandbox.NetNS != nil {
		span.AddEvent("start pod network teardown")
		netStop := time.Now()
		// Use empty netns path if netns is not available. This is defined in:
		// https://github.com/containernetworking/cni/blob/v0.7.0-alpha1/SPEC.md
		if closed, err := sandbox.NetNS.Closed(); err != nil {
			return fmt.Errorf("failed to check network namespace closed: %w", err)
		} else if closed {
			sandbox.NetNSPath = ""
		}
		if err := c.teardownPodNetwork(ctx, sandbox); err != nil {
			if sandbox.CNIResult != nil {
				return fmt.Errorf("failed to destroy network for sandbox %q: %w", id, err)
			} else {
				log.G(ctx).WithError(err).Warnf("failed to destroy network for sandbox %q; and ignoring because the sandbox network setup result is nil indicating the network setup never completed", id)
			}
		}
		if err := sandbox.NetNS.Remove(); err != nil {
			return fmt.Errorf("failed to remove network namespace for sandbox %q: %w", id, err)
		}
		sandboxDeleteNetwork.UpdateSince(netStop)

		span.AddEvent("finished pod network teardown",
			tracing.Attribute("network.teardown.duration", time.Since(netStop).String()),
		)
	}

	log.G(ctx).Infof("TearDown network for sandbox %q successfully", id)

	err = c.cleanupImageMounts(ctx, id)
	if err != nil {
		return fmt.Errorf("failed to cleanup image mounts for sandbox %q: %w", id, err)
	}
	return nil
}

// waitSandboxStop waits for sandbox to be stopped until context is cancelled or
// the context deadline is exceeded.
func (c *criService) waitSandboxStop(ctx context.Context, sandbox sandboxstore.Sandbox) error {
	select {