github.com/moby/docker@v26.1.3+incompatible/libcontainerd/replace.go (about)

     1  package libcontainerd // import "github.com/docker/docker/libcontainerd"
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/containerd/containerd"
     7  	"github.com/containerd/log"
     8  	"github.com/opencontainers/runtime-spec/specs-go"
     9  	"github.com/pkg/errors"
    10  
    11  	"github.com/docker/docker/errdefs"
    12  	"github.com/docker/docker/libcontainerd/types"
    13  )
    14  
    15  // ReplaceContainer creates a new container, replacing any existing container
    16  // with the same id if necessary.
    17  func ReplaceContainer(ctx context.Context, client types.Client, id string, spec *specs.Spec, shim string, runtimeOptions interface{}, opts ...containerd.NewContainerOpts) (types.Container, error) {
    18  	newContainer := func() (types.Container, error) {
    19  		return client.NewContainer(ctx, id, spec, shim, runtimeOptions, opts...)
    20  	}
    21  	ctr, err := newContainer()
    22  	if err == nil || !errdefs.IsConflict(err) {
    23  		return ctr, err
    24  	}
    25  
    26  	log := log.G(ctx).WithContext(ctx).WithField("container", id)
    27  	log.Debug("A container already exists with the same ID. Attempting to clean up the old container.")
    28  	ctr, err = client.LoadContainer(ctx, id)
    29  	if err != nil {
    30  		if errdefs.IsNotFound(err) {
    31  			// Task failed successfully: the container no longer exists,
    32  			// despite us not doing anything. May as well try to create
    33  			// the container again. It might succeed.
    34  			return newContainer()
    35  		}
    36  		return nil, errors.Wrap(err, "could not load stale containerd container object")
    37  	}
    38  	tsk, err := ctr.Task(ctx)
    39  	if err != nil {
    40  		if errdefs.IsNotFound(err) {
    41  			goto deleteContainer
    42  		}
    43  		// There is no point in trying to delete the container if we
    44  		// cannot determine whether or not it has a task. The containerd
    45  		// client would just try to load the task itself, get the same
    46  		// error, and give up.
    47  		return nil, errors.Wrap(err, "could not load stale containerd task object")
    48  	}
    49  	if err := tsk.ForceDelete(ctx); err != nil {
    50  		if !errdefs.IsNotFound(err) {
    51  			return nil, errors.Wrap(err, "could not delete stale containerd task object")
    52  		}
    53  		// The task might have exited on its own. Proceed with
    54  		// attempting to delete the container.
    55  	}
    56  deleteContainer:
    57  	if err := ctr.Delete(ctx); err != nil && !errdefs.IsNotFound(err) {
    58  		return nil, errors.Wrap(err, "could not delete stale containerd container object")
    59  	}
    60  
    61  	return newContainer()
    62  }