dotcloud/docker

View on GitHub
libcontainerd/replace.go

Summary

Maintainability
A
1 hr
Test Coverage
package libcontainerd // import "github.com/docker/docker/libcontainerd"

import (
    "context"

    "github.com/containerd/containerd"
    "github.com/containerd/log"
    "github.com/opencontainers/runtime-spec/specs-go"
    "github.com/pkg/errors"

    "github.com/docker/docker/errdefs"
    "github.com/docker/docker/libcontainerd/types"
)

// ReplaceContainer creates a new container, replacing any existing container
// with the same id if necessary.
func ReplaceContainer(ctx context.Context, client types.Client, id string, spec *specs.Spec, shim string, runtimeOptions interface{}, opts ...containerd.NewContainerOpts) (types.Container, error) {
    newContainer := func() (types.Container, error) {
        return client.NewContainer(ctx, id, spec, shim, runtimeOptions, opts...)
    }
    ctr, err := newContainer()
    if err == nil || !errdefs.IsConflict(err) {
        return ctr, err
    }

    log := log.G(ctx).WithContext(ctx).WithField("container", id)
    log.Debug("A container already exists with the same ID. Attempting to clean up the old container.")
    ctr, err = client.LoadContainer(ctx, id)
    if err != nil {
        if errdefs.IsNotFound(err) {
            // Task failed successfully: the container no longer exists,
            // despite us not doing anything. May as well try to create
            // the container again. It might succeed.
            return newContainer()
        }
        return nil, errors.Wrap(err, "could not load stale containerd container object")
    }
    tsk, err := ctr.Task(ctx)
    if err != nil {
        if errdefs.IsNotFound(err) {
            goto deleteContainer
        }
        // There is no point in trying to delete the container if we
        // cannot determine whether or not it has a task. The containerd
        // client would just try to load the task itself, get the same
        // error, and give up.
        return nil, errors.Wrap(err, "could not load stale containerd task object")
    }
    if err := tsk.ForceDelete(ctx); err != nil {
        if !errdefs.IsNotFound(err) {
            return nil, errors.Wrap(err, "could not delete stale containerd task object")
        }
        // The task might have exited on its own. Proceed with
        // attempting to delete the container.
    }
deleteContainer:
    if err := ctr.Delete(ctx); err != nil && !errdefs.IsNotFound(err) {
        return nil, errors.Wrap(err, "could not delete stale containerd container object")
    }

    return newContainer()
}