replace.go 2.2 KB

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