diff options
34 files changed, 563 insertions, 154 deletions
diff --git a/.github/workflows/bin-image.yml b/.github/workflows/bin-image.yml new file mode 100644 index 0000000000..f8992042cf --- /dev/null +++ b/.github/workflows/bin-image.yml @@ -0,0 +1,72 @@ +name: bin-image + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +on: + workflow_dispatch: + push: + branches: + - 'master' + - '[0-9]+.[0-9]+' + tags: + - 'v*' + pull_request: + +env: + PLATFORM: Moby Engine + PRODUCT: Moby + DEFAULT_PRODUCT_LICENSE: Moby + PACKAGER_NAME: Moby + +jobs: + validate-dco: + uses: ./.github/workflows/.dco.yml + + build: + runs-on: ubuntu-20.04 + needs: + - validate-dco + steps: + - + name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - + name: Docker meta + id: meta + uses: docker/metadata-action@v4 + with: + images: moby-bin + ### versioning strategy + ## push semver tag v23.0.0 + # moby/moby-bin:23.0.0 + # moby/moby-bin:latest + ## push semver prelease tag v23.0.0-beta.1 + # moby/moby-bin:23.0.0-beta.1 + ## push on master + # moby/moby-bin:master + ## push on 23.0 branch + # moby/moby-bin:23.0 + tags: | + type=semver,pattern={{version}} + type=ref,event=branch + type=ref,event=pr + - + name: Set up QEMU + uses: docker/setup-qemu-action@v2 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - + name: Build + uses: docker/bake-action@v2 + with: + files: | + ./docker-bake.hcl + ${{ steps.meta.outputs.bake-file }} + targets: bin-image-cross + set: | + *.output=type=cacheonly diff --git a/builder/dockerfile/evaluator_test.go b/builder/dockerfile/evaluator_test.go index 03d9270616..5c40fed558 100644 --- a/builder/dockerfile/evaluator_test.go +++ b/builder/dockerfile/evaluator_test.go @@ -21,8 +21,11 @@ type dispatchTestCase struct { files map[string]string } -func init() { - reexec.Init() +func TestMain(m *testing.M) { + if reexec.Init() { + return + } + os.Exit(m.Run()) } func TestDispatch(t *testing.T) { diff --git a/builder/remotecontext/tarsum_test.go b/builder/remotecontext/tarsum_test.go index a398839ab3..ca354d02f9 100644 --- a/builder/remotecontext/tarsum_test.go +++ b/builder/remotecontext/tarsum_test.go @@ -17,8 +17,11 @@ const ( contents = "contents test" ) -func init() { - reexec.Init() +func TestMain(m *testing.M) { + if reexec.Init() { + return + } + os.Exit(m.Run()) } func TestCloseRootDirectory(t *testing.T) { diff --git a/daemon/containerd/image_children.go b/daemon/containerd/image_children.go index ced4637aeb..ba8c939549 100644 --- a/daemon/containerd/image_children.go +++ b/daemon/containerd/image_children.go @@ -127,3 +127,71 @@ func isRootfsChildOf(child ocispec.RootFS, parent ocispec.RootFS) bool { return true } + +// parents returns a slice of image IDs whose entire rootfs contents match, +// in order, the childs first layers, excluding images with the exact same +// rootfs. +// +// Called from image_delete.go to prune dangling parents. +func (i *ImageService) parents(ctx context.Context, id image.ID) ([]imageWithRootfs, error) { + target, err := i.resolveDescriptor(ctx, id.String()) + if err != nil { + return nil, errors.Wrap(err, "failed to get child image") + } + + cs := i.client.ContentStore() + + allPlatforms, err := containerdimages.Platforms(ctx, cs, target) + if err != nil { + return nil, errdefs.System(errors.Wrap(err, "failed to list platforms supported by image")) + } + + var childRootFS []ocispec.RootFS + for _, platform := range allPlatforms { + rootfs, err := platformRootfs(ctx, cs, target, platform) + if err != nil { + if cerrdefs.IsNotFound(err) { + continue + } + return nil, errdefs.System(errors.Wrap(err, "failed to get platform-specific rootfs")) + } + + childRootFS = append(childRootFS, rootfs) + } + + imgs, err := i.client.ImageService().List(ctx) + if err != nil { + return nil, errdefs.System(errors.Wrap(err, "failed to list all images")) + } + + var parents []imageWithRootfs + for _, img := range imgs { + nextImage: + for _, platform := range allPlatforms { + rootfs, err := platformRootfs(ctx, cs, img.Target, platform) + if err != nil { + if cerrdefs.IsNotFound(err) { + continue + } + return nil, errdefs.System(errors.Wrap(err, "failed to get platform-specific rootfs")) + } + + for _, childRoot := range childRootFS { + if isRootfsChildOf(childRoot, rootfs) { + parents = append(parents, imageWithRootfs{ + img: img, + rootfs: rootfs, + }) + break nextImage + } + } + } + } + + return parents, nil +} + +type imageWithRootfs struct { + img containerdimages.Image + rootfs ocispec.RootFS +} diff --git a/daemon/containerd/image_delete.go b/daemon/containerd/image_delete.go index 1fd13cf420..3d55dba394 100644 --- a/daemon/containerd/image_delete.go +++ b/daemon/containerd/image_delete.go @@ -2,10 +2,16 @@ package containerd import ( "context" + "fmt" + "sort" + "strings" "github.com/containerd/containerd/images" "github.com/docker/distribution/reference" "github.com/docker/docker/api/types" + "github.com/docker/docker/container" + "github.com/docker/docker/image" + "github.com/docker/docker/pkg/stringid" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/sirupsen/logrus" @@ -30,8 +36,6 @@ import ( // are divided into two categories grouped by their severity: // // Hard Conflict: -// - a pull or build using the image. -// - any descendant image. // - any running container using the image. // // Soft Conflict: @@ -45,8 +49,6 @@ import ( // meaning any delete conflicts will cause the image to not be deleted and the // conflict will not be reported. // -// TODO(thaJeztah): implement ImageDelete "force" options; see https://github.com/moby/moby/issues/43850 -// TODO(thaJeztah): implement ImageDelete "prune" options; see https://github.com/moby/moby/issues/43849 // TODO(thaJeztah): image delete should send prometheus counters; see https://github.com/moby/moby/issues/45268 func (i *ImageService) ImageDelete(ctx context.Context, imageRef string, force, prune bool) ([]types.ImageDeleteResponseItem, error) { parsedRef, err := reference.ParseNormalizedNamed(imageRef) @@ -59,28 +61,278 @@ func (i *ImageService) ImageDelete(ctx context.Context, imageRef string, force, return nil, err } + imgID := image.ID(img.Target.Digest) + + if isImageIDPrefix(imgID.String(), imageRef) { + return i.deleteAll(ctx, img, force, prune) + } + + singleRef, err := i.isSingleReference(ctx, img) + if err != nil { + return nil, err + } + if !singleRef { + err := i.client.ImageService().Delete(ctx, img.Name) + if err != nil { + return nil, err + } + i.LogImageEvent(imgID.String(), imgID.String(), "untag") + records := []types.ImageDeleteResponseItem{{Untagged: reference.FamiliarString(reference.TagNameOnly(parsedRef))}} + return records, nil + } + + using := func(c *container.Container) bool { + return c.ImageID == imgID + } + ctr := i.containers.First(using) + if ctr != nil { + if !force { + // If we removed the repository reference then + // this image would remain "dangling" and since + // we really want to avoid that the client must + // explicitly force its removal. + refString := reference.FamiliarString(reference.TagNameOnly(parsedRef)) + err := &imageDeleteConflict{ + reference: refString, + used: true, + message: fmt.Sprintf("container %s is using its referenced image %s", + stringid.TruncateID(ctr.ID), + stringid.TruncateID(imgID.String())), + } + return nil, err + } + + err := i.softImageDelete(ctx, img) + if err != nil { + return nil, err + } + + i.LogImageEvent(imgID.String(), imgID.String(), "untag") + records := []types.ImageDeleteResponseItem{{Untagged: reference.FamiliarString(reference.TagNameOnly(parsedRef))}} + return records, nil + } + + return i.deleteAll(ctx, img, force, prune) +} + +// deleteAll deletes the image from the daemon, and if prune is true, +// also deletes dangling parents if there is no conflict in doing so. +// Parent images are removed quietly, and if there is any issue/conflict +// it is logged but does not halt execution/an error is not returned. +func (i *ImageService) deleteAll(ctx context.Context, img images.Image, force, prune bool) ([]types.ImageDeleteResponseItem, error) { + var records []types.ImageDeleteResponseItem + + // Workaround for: https://github.com/moby/buildkit/issues/3797 possiblyDeletedConfigs := map[digest.Digest]struct{}{} - if err := i.walkPresentChildren(ctx, img.Target, func(_ context.Context, d ocispec.Descriptor) { + err := i.walkPresentChildren(ctx, img.Target, func(_ context.Context, d ocispec.Descriptor) { if images.IsConfigType(d.MediaType) { possiblyDeletedConfigs[d.Digest] = struct{}{} } - }); err != nil { + }) + if err != nil { return nil, err } + defer func() { + if err := i.unleaseSnapshotsFromDeletedConfigs(context.Background(), possiblyDeletedConfigs); err != nil { + logrus.WithError(err).Warn("failed to unlease snapshots") + } + }() - err = i.client.ImageService().Delete(ctx, img.Name, images.SynchronousDelete()) + imgID := img.Target.Digest.String() + + var parents []imageWithRootfs + if prune { + parents, err = i.parents(ctx, image.ID(imgID)) + if err != nil { + logrus.WithError(err).Warn("failed to get image parents") + } + sortParentsByAffinity(parents) + } + + imageRefs, err := i.client.ImageService().List(ctx, "target.digest=="+imgID) if err != nil { return nil, err } + for _, imageRef := range imageRefs { + if err := i.imageDeleteHelper(ctx, imageRef, &records, force); err != nil { + return records, err + } + } + i.LogImageEvent(imgID, imgID, "delete") + records = append(records, types.ImageDeleteResponseItem{Deleted: imgID}) - // Workaround for: https://github.com/moby/buildkit/issues/3797 - if err := i.unleaseSnapshotsFromDeletedConfigs(context.Background(), possiblyDeletedConfigs); err != nil { - logrus.WithError(err).Warn("failed to unlease snapshots") + for _, parent := range parents { + if !isDanglingImage(parent.img) { + break + } + err = i.imageDeleteHelper(ctx, parent.img, &records, false) + if err != nil { + logrus.WithError(err).Warn("failed to remove image parent") + break + } + parentID := parent.img.Target.Digest.String() + i.LogImageEvent(parentID, parentID, "delete") + records = append(records, types.ImageDeleteResponseItem{Deleted: parentID}) } - imgID := string(img.Target.Digest) - i.LogImageEvent(imgID, imgID, "untag") - i.LogImageEvent(imgID, imgID, "delete") + return records, nil +} + +// isImageIDPrefix returns whether the given +// possiblePrefix is a prefix of the given imageID. +func isImageIDPrefix(imageID, possiblePrefix string) bool { + if strings.HasPrefix(imageID, possiblePrefix) { + return true + } + if i := strings.IndexRune(imageID, ':'); i >= 0 { + return strings.HasPrefix(imageID[i+1:], possiblePrefix) + } + return false +} + +func sortParentsByAffinity(parents []imageWithRootfs) { + sort.Slice(parents, func(i, j int) bool { + lenRootfsI := len(parents[i].rootfs.DiffIDs) + lenRootfsJ := len(parents[j].rootfs.DiffIDs) + if lenRootfsI == lenRootfsJ { + return isDanglingImage(parents[i].img) + } + return lenRootfsI > lenRootfsJ + }) +} + +// isSingleReference returns true if there are no other images in the +// daemon targeting the same content as `img` that are not dangling. +func (i *ImageService) isSingleReference(ctx context.Context, img images.Image) (bool, error) { + refs, err := i.client.ImageService().List(ctx, "target.digest=="+img.Target.Digest.String()) + if err != nil { + return false, err + } + for _, ref := range refs { + if !isDanglingImage(ref) && ref.Name != img.Name { + return false, nil + } + } + return true, nil +} + +type conflictType int + +const ( + conflictRunningContainer conflictType = 1 << iota + conflictActiveReference + conflictStoppedContainer + conflictHard = conflictRunningContainer + conflictSoft = conflictActiveReference | conflictStoppedContainer +) + +// imageDeleteHelper attempts to delete the given image from this daemon. +// If the image has any hard delete conflicts (running containers using +// the image) then it cannot be deleted. If the image has any soft delete +// conflicts (any tags/digests referencing the image or any stopped container +// using the image) then it can only be deleted if force is true. Any deleted +// images and untagged references are appended to the given records. If any +// error or conflict is encountered, it will be returned immediately without +// deleting the image. +func (i *ImageService) imageDeleteHelper(ctx context.Context, img images.Image, records *[]types.ImageDeleteResponseItem, force bool) error { + // First, determine if this image has any conflicts. Ignore soft conflicts + // if force is true. + c := conflictHard + if !force { + c |= conflictSoft + } + + imgID := image.ID(img.Target.Digest) + + err := i.checkImageDeleteConflict(ctx, imgID, c) + if err != nil { + return err + } + + untaggedRef, err := reference.ParseAnyReference(img.Name) + if err != nil { + return err + } + err = i.client.ImageService().Delete(ctx, img.Name, images.SynchronousDelete()) + if err != nil { + return err + } + + i.LogImageEvent(imgID.String(), imgID.String(), "untag") + *records = append(*records, types.ImageDeleteResponseItem{Untagged: reference.FamiliarString(untaggedRef)}) + + return nil +} + +// ImageDeleteConflict holds a soft or hard conflict and associated +// error. A hard conflict represents a running container using the +// image, while a soft conflict is any tags/digests referencing the +// given image or any stopped container using the image. +// Implements the error interface. +type imageDeleteConflict struct { + hard bool + used bool + reference string + message string +} + +func (idc *imageDeleteConflict) Error() string { + var forceMsg string + if idc.hard { + forceMsg = "cannot be forced" + } else { + forceMsg = "must be forced" + } + return fmt.Sprintf("conflict: unable to delete %s (%s) - %s", idc.reference, forceMsg, idc.message) +} + +func (imageDeleteConflict) Conflict() {} + +// checkImageDeleteConflict returns a conflict representing +// any issue preventing deletion of the given image ID, and +// nil if there are none. It takes a bitmask representing a +// filter for which conflict types the caller cares about, +// and will only check for these conflict types. +func (i *ImageService) checkImageDeleteConflict(ctx context.Context, imgID image.ID, mask conflictType) error { + if mask&conflictRunningContainer != 0 { + running := func(c *container.Container) bool { + return c.ImageID == imgID && c.IsRunning() + } + if ctr := i.containers.First(running); ctr != nil { + return &imageDeleteConflict{ + reference: stringid.TruncateID(imgID.String()), + hard: true, + used: true, + message: fmt.Sprintf("image is being used by running container %s", stringid.TruncateID(ctr.ID)), + } + } + } + + if mask&conflictStoppedContainer != 0 { + stopped := func(c *container.Container) bool { + return !c.IsRunning() && c.ImageID == imgID + } + if ctr := i.containers.First(stopped); ctr != nil { + return &imageDeleteConflict{ + reference: stringid.TruncateID(imgID.String()), + used: true, + message: fmt.Sprintf("image is being used by stopped container %s", stringid.TruncateID(ctr.ID)), + } + } + } + + if mask&conflictActiveReference != 0 { + refs, err := i.client.ImageService().List(ctx, "target.digest=="+imgID.String()) + if err != nil { + return err + } + if len(refs) > 1 { + return &imageDeleteConflict{ + reference: stringid.TruncateID(imgID.String()), + message: "image is referenced in multiple repositories", + } + } + } - return []types.ImageDeleteResponseItem{{Untagged: reference.FamiliarString(parsedRef)}}, nil + return nil } diff --git a/daemon/containerd/image_history.go b/daemon/containerd/image_history.go index a99716ead7..a2d0c11425 100644 --- a/daemon/containerd/image_history.go +++ b/daemon/containerd/image_history.go @@ -90,13 +90,16 @@ func (i *ImageService) ImageHistory(ctx context.Context, name string) ([]*imaget return nil, err } - tags := make([]string, len(tagged)) - for i, t := range tagged { + var tags []string + for _, t := range tagged { + if isDanglingImage(t) { + continue + } name, err := reference.ParseNamed(t.Name) if err != nil { return nil, err } - tags[i] = reference.FamiliarString(name) + tags = append(tags, reference.FamiliarString(name)) } history[0].Tags = tags } diff --git a/daemon/containerd/resolver.go b/daemon/containerd/resolver.go index 07c9ed9f0c..5b2d1dff4c 100644 --- a/daemon/containerd/resolver.go +++ b/daemon/containerd/resolver.go @@ -24,7 +24,15 @@ func (i *ImageService) newResolverFromAuthConfig(authConfig *registrytypes.AuthC }), tracker } -func hostsWrapper(hostsFn docker.RegistryHosts, authConfig *registrytypes.AuthConfig, regService RegistryConfigProvider) docker.RegistryHosts { +func hostsWrapper(hostsFn docker.RegistryHosts, optAuthConfig *registrytypes.AuthConfig, regService RegistryConfigProvider) docker.RegistryHosts { + var authorizer docker.Authorizer + if optAuthConfig != nil { + auth := *optAuthConfig + if auth != (registrytypes.AuthConfig{}) { + authorizer = docker.NewDockerAuthorizer(authorizationCredsFromAuthConfig(auth)) + } + } + return func(n string) ([]docker.RegistryHost, error) { hosts, err := hostsFn(n) if err != nil { @@ -33,12 +41,7 @@ func hostsWrapper(hostsFn docker.RegistryHosts, authConfig *registrytypes.AuthCo for i := range hosts { if hosts[i].Authorizer == nil { - var opts []docker.AuthorizerOpt - if authConfig != nil { - opts = append(opts, authorizationCredsFromAuthConfig(*authConfig)) - } - hosts[i].Authorizer = docker.NewDockerAuthorizer(opts...) - + hosts[i].Authorizer = authorizer isInsecure := regService.IsInsecureRegistry(hosts[i].Host) if hosts[i].Client.Transport != nil && isInsecure { hosts[i].Client.Transport = httpFallback{super: hosts[i].Client.Transport} @@ -51,13 +54,16 @@ func hostsWrapper(hostsFn docker.RegistryHosts, authConfig *registrytypes.AuthCo func authorizationCredsFromAuthConfig(authConfig registrytypes.AuthConfig) docker.AuthorizerOpt { cfgHost := registry.ConvertToHostname(authConfig.ServerAddress) - if cfgHost == registry.IndexHostname { + if cfgHost == "" || cfgHost == registry.IndexHostname { cfgHost = registry.DefaultRegistryHost } return docker.WithAuthCreds(func(host string) (string, string, error) { if cfgHost != host { - logrus.WithField("host", host).WithField("cfgHost", cfgHost).Warn("Host doesn't match") + logrus.WithFields(logrus.Fields{ + "host": host, + "cfgHost": cfgHost, + }).Warn("Host doesn't match") return "", "", nil } if authConfig.IdentityToken != "" { diff --git a/daemon/graphdriver/fuse-overlayfs/fuseoverlayfs_test.go b/daemon/graphdriver/fuse-overlayfs/fuseoverlayfs_test.go index 0d5b29e538..6c0ca01c5e 100644 --- a/daemon/graphdriver/fuse-overlayfs/fuseoverlayfs_test.go +++ b/daemon/graphdriver/fuse-overlayfs/fuseoverlayfs_test.go @@ -9,7 +9,6 @@ import ( "github.com/docker/docker/daemon/graphdriver" "github.com/docker/docker/daemon/graphdriver/graphtest" "github.com/docker/docker/pkg/archive" - "github.com/docker/docker/pkg/reexec" ) func init() { @@ -17,8 +16,6 @@ func init() { // errors or hangs to be debugged directly from the test process. untar = archive.UntarUncompressed graphdriver.ApplyUncompressedLayer = archive.ApplyUncompressedLayer - - reexec.Init() } // This avoids creating a new driver for each test if all tests are run diff --git a/daemon/graphdriver/overlay2/overlay_test.go b/daemon/graphdriver/overlay2/overlay_test.go index 47f3f11005..fbf25fe75b 100644 --- a/daemon/graphdriver/overlay2/overlay_test.go +++ b/daemon/graphdriver/overlay2/overlay_test.go @@ -10,7 +10,6 @@ import ( "github.com/docker/docker/daemon/graphdriver" "github.com/docker/docker/daemon/graphdriver/graphtest" "github.com/docker/docker/pkg/archive" - "github.com/docker/docker/pkg/reexec" ) func init() { @@ -18,8 +17,6 @@ func init() { // errors or hangs to be debugged directly from the test process. untar = archive.UntarUncompressed graphdriver.ApplyUncompressedLayer = archive.ApplyUncompressedLayer - - reexec.Init() } func skipIfNaive(t *testing.T) { diff --git a/daemon/graphdriver/vfs/vfs_test.go b/daemon/graphdriver/vfs/vfs_test.go index 63db564518..7cf0bf8cf6 100644 --- a/daemon/graphdriver/vfs/vfs_test.go +++ b/daemon/graphdriver/vfs/vfs_test.go @@ -7,14 +7,8 @@ import ( "testing" "github.com/docker/docker/daemon/graphdriver/graphtest" - - "github.com/docker/docker/pkg/reexec" ) -func init() { - reexec.Init() -} - // This avoids creating a new driver for each test if all tests are run // Make sure to put new tests between TestVfsSetup and TestVfsTeardown func TestVfsSetup(t *testing.T) { diff --git a/docker-bake.hcl b/docker-bake.hcl index 899551f9e4..0eb078aebc 100644 --- a/docker-bake.hcl +++ b/docker-bake.hcl @@ -59,6 +59,11 @@ variable "GITHUB_SHA" { default = "" } +# Special target: https://github.com/docker/metadata-action#bake-definition +target "docker-metadata-action" { + tags = ["moby-bin:local"] +} + # Defines the output folder variable "DESTDIR" { default = "" @@ -153,6 +158,29 @@ target "all-cross" { } # +# bin image +# + +target "bin-image" { + inherits = ["all", "docker-metadata-action"] + output = ["type=docker"] +} + +target "bin-image-cross" { + inherits = ["bin-image"] + output = ["type=image"] + platforms = [ + "linux/amd64", + "linux/arm/v6", + "linux/arm/v7", + "linux/arm64", + "linux/ppc64le", + "linux/s390x", + "windows/amd64" + ] +} + +# # dev # diff --git a/integration-cli/check_test.go b/integration-cli/check_test.go index 5353672f9c..db6683709d 100644 --- a/integration-cli/check_test.go +++ b/integration-cli/check_test.go @@ -18,7 +18,6 @@ import ( "github.com/docker/docker/integration-cli/daemon" "github.com/docker/docker/integration-cli/environment" "github.com/docker/docker/internal/test/suite" - "github.com/docker/docker/pkg/reexec" testdaemon "github.com/docker/docker/testutil/daemon" ienv "github.com/docker/docker/testutil/environment" "github.com/docker/docker/testutil/fakestorage" @@ -50,8 +49,6 @@ var ( func init() { var err error - reexec.Init() // This is required for external graphdriver tests - testEnv, err = environment.New() if err != nil { panic(err) diff --git a/integration/plugin/common/main_test.go b/integration/plugin/common/main_test.go index cd42c8f761..5bcbac2a83 100644 --- a/integration/plugin/common/main_test.go +++ b/integration/plugin/common/main_test.go @@ -5,16 +5,12 @@ import ( "os" "testing" - "github.com/docker/docker/pkg/reexec" "github.com/docker/docker/testutil/environment" ) var testEnv *environment.Execution func TestMain(m *testing.M) { - if reexec.Init() { - return - } var err error testEnv, err = environment.New() if err != nil { diff --git a/integration/plugin/graphdriver/main_test.go b/integration/plugin/graphdriver/main_test.go index 68fa02c81e..5114180fd7 100644 --- a/integration/plugin/graphdriver/main_test.go +++ b/integration/plugin/graphdriver/main_test.go @@ -5,7 +5,6 @@ import ( "os" "testing" - "github.com/docker/docker/pkg/reexec" "github.com/docker/docker/testutil/environment" ) @@ -13,10 +12,6 @@ var ( testEnv *environment.Execution ) -func init() { - reexec.Init() // This is required for external graphdriver tests -} - func TestMain(m *testing.M) { var err error testEnv, err = environment.New() diff --git a/libnetwork/cmd/readme_test/readme.go b/libnetwork/cmd/readme_test/readme.go index 7e008a9aa9..80cfae3a6c 100644 --- a/libnetwork/cmd/readme_test/readme.go +++ b/libnetwork/cmd/readme_test/readme.go @@ -8,14 +8,9 @@ import ( "github.com/docker/docker/libnetwork/config" "github.com/docker/docker/libnetwork/netlabel" "github.com/docker/docker/libnetwork/options" - "github.com/docker/docker/pkg/reexec" ) func main() { - if reexec.Init() { - return - } - // Select and configure the network driver networkType := "bridge" diff --git a/libnetwork/drivers/bridge/port_mapping_test.go b/libnetwork/drivers/bridge/port_mapping_test.go index dab375e96b..17d6e19b51 100644 --- a/libnetwork/drivers/bridge/port_mapping_test.go +++ b/libnetwork/drivers/bridge/port_mapping_test.go @@ -4,23 +4,14 @@ package bridge import ( - "os" "testing" "github.com/docker/docker/libnetwork/netlabel" "github.com/docker/docker/libnetwork/ns" "github.com/docker/docker/libnetwork/testutils" "github.com/docker/docker/libnetwork/types" - "github.com/docker/docker/pkg/reexec" ) -func TestMain(m *testing.M) { - if reexec.Init() { - return - } - os.Exit(m.Run()) -} - func TestPortMappingConfig(t *testing.T) { defer testutils.SetupTestOSContext(t)() d := newDriver() diff --git a/libnetwork/libnetwork_test.go b/libnetwork/libnetwork_test.go index 3707952ab9..e3207d4f5c 100644 --- a/libnetwork/libnetwork_test.go +++ b/libnetwork/libnetwork_test.go @@ -10,7 +10,6 @@ import ( "net/http/httptest" "os" "path/filepath" - "runtime" "testing" "github.com/docker/docker/libnetwork" @@ -23,19 +22,9 @@ import ( "github.com/docker/docker/libnetwork/testutils" "github.com/docker/docker/libnetwork/types" "github.com/docker/docker/pkg/plugins" - "github.com/docker/docker/pkg/reexec" - "github.com/sirupsen/logrus" ) func TestMain(m *testing.M) { - if runtime.GOOS == "windows" { - logrus.Info("Test suite does not currently support windows") - os.Exit(0) - } - if reexec.Init() { - return - } - // Cleanup local datastore file _ = os.Remove(datastore.DefaultScope("").Client.Address) diff --git a/libnetwork/osl/sandbox_linux_test.go b/libnetwork/osl/sandbox_linux_test.go index acda5eee9e..0dd8b1e8a5 100644 --- a/libnetwork/osl/sandbox_linux_test.go +++ b/libnetwork/osl/sandbox_linux_test.go @@ -15,7 +15,6 @@ import ( "github.com/docker/docker/libnetwork/ns" "github.com/docker/docker/libnetwork/testutils" "github.com/docker/docker/libnetwork/types" - "github.com/docker/docker/pkg/reexec" "github.com/vishvananda/netlink" "github.com/vishvananda/netlink/nl" "github.com/vishvananda/netns" @@ -382,13 +381,6 @@ func TestLiveRestore(t *testing.T) { } } -func TestMain(m *testing.M) { - if reexec.Init() { - return - } - os.Exit(m.Run()) -} - func TestSandboxCreate(t *testing.T) { defer testutils.SetupTestOSContext(t)() diff --git a/pkg/chrootarchive/archive_test.go b/pkg/chrootarchive/archive_test.go index 4e22ac6fd9..5ef8ef832b 100644 --- a/pkg/chrootarchive/archive_test.go +++ b/pkg/chrootarchive/archive_test.go @@ -14,14 +14,9 @@ import ( "github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/idtools" - "github.com/docker/docker/pkg/reexec" "gotest.tools/v3/skip" ) -func init() { - reexec.Init() -} - var chrootArchiver = NewArchiver(idtools.IdentityMapping{}) func TarUntar(src, dst string) error { diff --git a/vendor.mod b/vendor.mod index 17d7485cfb..44d53f8c91 100644 --- a/vendor.mod +++ b/vendor.mod @@ -32,7 +32,7 @@ require ( github.com/coreos/go-systemd/v22 v22.5.0 github.com/creack/pty v1.1.18 github.com/deckarep/golang-set/v2 v2.3.0 - github.com/docker/distribution v2.8.1+incompatible + github.com/docker/distribution v2.8.2+incompatible github.com/docker/go-connections v0.4.0 github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c github.com/docker/go-metrics v0.0.1 diff --git a/vendor.sum b/vendor.sum index ac001bd255..2d78b1393f 100644 --- a/vendor.sum +++ b/vendor.sum @@ -502,8 +502,8 @@ github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TT github.com/docker/distribution v2.6.0-rc.1.0.20180327202408-83389a148052+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= -github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= +github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v0.0.0-20200511152416-a93e9eb0e95c/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v1.4.2-0.20180531152204-71cd53e4a197/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= diff --git a/vendor/github.com/docker/distribution/.dockerignore b/vendor/github.com/docker/distribution/.dockerignore new file mode 100644 index 0000000000..e660fd93d3 --- /dev/null +++ b/vendor/github.com/docker/distribution/.dockerignore @@ -0,0 +1 @@ +bin/ diff --git a/vendor/github.com/docker/distribution/.golangci.yml b/vendor/github.com/docker/distribution/.golangci.yml index 1ba6cb9162..36c083b0fc 100644 --- a/vendor/github.com/docker/distribution/.golangci.yml +++ b/vendor/github.com/docker/distribution/.golangci.yml @@ -18,3 +18,10 @@ run: deadline: 2m skip-dirs: - vendor + +issues: + exclude-rules: + # io/ioutil is deprecated, but won't be removed until Go v2. It's safe to ignore for the release/2.8 branch. + - text: "SA1019: \"io/ioutil\" has been deprecated since Go 1.16" + linters: + - staticcheck diff --git a/vendor/github.com/docker/distribution/.mailmap b/vendor/github.com/docker/distribution/.mailmap index 8f3738f3d0..d94c3936e0 100644 --- a/vendor/github.com/docker/distribution/.mailmap +++ b/vendor/github.com/docker/distribution/.mailmap @@ -44,6 +44,8 @@ Thomas Berger <loki@lokis-chaos.de> Thomas Berger <tbe@users.noreply.github.com> Samuel Karp <skarp@amazon.com> Samuel Karp <samuelkarp@users.noreply.github.com> Justin Cormack <justin.cormack@docker.com> sayboras <sayboras@yahoo.com> -CrazyMax <github@crazymax.dev> CrazyMax <github@crazymax.dev> <1951866+crazy-max@users.noreply.github.com> -CrazyMax <github@crazymax.dev> <crazy-max@users.noreply.github.com> +Hayley Swimelar <hswimelar@gmail.com> +Jose D. Gomez R <jose.gomez@suse.com> +Shengjing Zhu <zhsj@debian.org> +Silvin Lubecki <31478878+silvin-lubecki@users.noreply.github.com> diff --git a/vendor/github.com/docker/distribution/Dockerfile b/vendor/github.com/docker/distribution/Dockerfile index ae8c040c73..fb54b68138 100644 --- a/vendor/github.com/docker/distribution/Dockerfile +++ b/vendor/github.com/docker/distribution/Dockerfile @@ -1,49 +1,59 @@ -# syntax=docker/dockerfile:1.3 +# syntax=docker/dockerfile:1 -ARG GO_VERSION=1.16.15 -ARG GORELEASER_XX_VERSION=1.2.5 +ARG GO_VERSION=1.19.9 +ARG ALPINE_VERSION=3.16 +ARG XX_VERSION=1.2.1 -FROM --platform=$BUILDPLATFORM crazymax/goreleaser-xx:${GORELEASER_XX_VERSION} AS goreleaser-xx -FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine AS base -COPY --from=goreleaser-xx / / -RUN apk add --no-cache file git +FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx +FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine${ALPINE_VERSION} AS base +COPY --from=xx / / +RUN apk add --no-cache bash coreutils file git +ENV GO111MODULE=auto +ENV CGO_ENABLED=0 WORKDIR /go/src/github.com/docker/distribution +FROM base AS version +ARG PKG="github.com/docker/distribution" +RUN --mount=target=. \ + VERSION=$(git describe --match 'v[0-9]*' --dirty='.m' --always --tags) REVISION=$(git rev-parse HEAD)$(if ! git diff --no-ext-diff --quiet --exit-code; then echo .m; fi); \ + echo "-X ${PKG}/version.Version=${VERSION#v} -X ${PKG}/version.Revision=${REVISION} -X ${PKG}/version.Package=${PKG}" | tee /tmp/.ldflags; \ + echo -n "${VERSION}" | tee /tmp/.version; + FROM base AS build -ENV GO111MODULE=auto -ENV CGO_ENABLED=0 -# GIT_REF is used by goreleaser-xx to handle the proper git ref when available. -# It will fallback to the working tree info if empty and use "git tag --points-at" -# or "git describe" to define the version info. -ARG GIT_REF ARG TARGETPLATFORM -ARG PKG="github.com/distribution/distribution" +ARG LDFLAGS="-s -w" ARG BUILDTAGS="include_oss include_gcs" -RUN --mount=type=bind,rw \ - --mount=type=cache,target=/root/.cache/go-build \ - --mount=target=/go/pkg/mod,type=cache \ - goreleaser-xx --debug \ - --name="registry" \ - --dist="/out" \ - --main="./cmd/registry" \ - --flags="-v" \ - --ldflags="-s -w -X '$PKG/version.Version={{.Version}}' -X '$PKG/version.Revision={{.Commit}}' -X '$PKG/version.Package=$PKG'" \ - --tags="$BUILDTAGS" \ - --files="LICENSE" \ - --files="README.md" - -FROM scratch AS artifact -COPY --from=build /out/*.tar.gz / -COPY --from=build /out/*.zip / -COPY --from=build /out/*.sha256 / +RUN --mount=type=bind,target=/go/src/github.com/docker/distribution,rw \ + --mount=type=cache,target=/root/.cache/go-build \ + --mount=target=/go/pkg/mod,type=cache \ + --mount=type=bind,source=/tmp/.ldflags,target=/tmp/.ldflags,from=version \ + set -x ; xx-go build -trimpath -ldflags "$(cat /tmp/.ldflags) ${LDFLAGS}" -o /usr/bin/registry ./cmd/registry \ + && xx-verify --static /usr/bin/registry FROM scratch AS binary -COPY --from=build /usr/local/bin/registry* / +COPY --from=build /usr/bin/registry / + +FROM base AS releaser +ARG TARGETOS +ARG TARGETARCH +ARG TARGETVARIANT +WORKDIR /work +RUN --mount=from=binary,target=/build \ + --mount=type=bind,target=/src \ + --mount=type=bind,source=/tmp/.version,target=/tmp/.version,from=version \ + VERSION=$(cat /tmp/.version) \ + && mkdir -p /out \ + && cp /build/registry /src/README.md /src/LICENSE . \ + && tar -czvf "/out/registry_${VERSION#v}_${TARGETOS}_${TARGETARCH}${TARGETVARIANT}.tar.gz" * \ + && sha256sum -z "/out/registry_${VERSION#v}_${TARGETOS}_${TARGETARCH}${TARGETVARIANT}.tar.gz" | awk '{ print $1 }' > "/out/registry_${VERSION#v}_${TARGETOS}_${TARGETARCH}${TARGETVARIANT}.tar.gz.sha256" + +FROM scratch AS artifact +COPY --from=releaser /out / -FROM alpine:3.14 +FROM alpine:${ALPINE_VERSION} RUN apk add --no-cache ca-certificates COPY cmd/registry/config-dev.yml /etc/docker/registry/config.yml -COPY --from=build /usr/local/bin/registry /bin/registry +COPY --from=binary /registry /bin/registry VOLUME ["/var/lib/registry"] EXPOSE 5000 ENTRYPOINT ["registry"] diff --git a/vendor/github.com/docker/distribution/Makefile b/vendor/github.com/docker/distribution/Makefile index 331da27328..75e1182015 100644 --- a/vendor/github.com/docker/distribution/Makefile +++ b/vendor/github.com/docker/distribution/Makefile @@ -50,7 +50,7 @@ version/version.go: check: ## run all linters (TODO: enable "unused", "varcheck", "ineffassign", "unconvert", "staticheck", "goimports", "structcheck") @echo "$(WHALE) $@" - golangci-lint run + @GO111MODULE=off golangci-lint run test: ## run tests, except integration test with test.short @echo "$(WHALE) $@" diff --git a/vendor/github.com/docker/distribution/docker-bake.hcl b/vendor/github.com/docker/distribution/docker-bake.hcl index 4dd5a100c1..91686e608a 100644 --- a/vendor/github.com/docker/distribution/docker-bake.hcl +++ b/vendor/github.com/docker/distribution/docker-bake.hcl @@ -1,15 +1,3 @@ -// GITHUB_REF is the actual ref that triggers the workflow -// https://docs.github.com/en/actions/learn-github-actions/environment-variables#default-environment-variables -variable "GITHUB_REF" { - default = "" -} - -target "_common" { - args = { - GIT_REF = GITHUB_REF - } -} - group "default" { targets = ["image-local"] } @@ -20,13 +8,11 @@ target "docker-metadata-action" { } target "binary" { - inherits = ["_common"] target = "binary" output = ["./bin"] } target "artifact" { - inherits = ["_common"] target = "artifact" output = ["./bin"] } @@ -43,8 +29,13 @@ target "artifact-all" { ] } +// Special target: https://github.com/docker/metadata-action#bake-definition +target "docker-metadata-action" { + tags = ["registry:local"] +} + target "image" { - inherits = ["_common", "docker-metadata-action"] + inherits = ["docker-metadata-action"] } target "image-local" { diff --git a/vendor/github.com/docker/distribution/reference/reference.go b/vendor/github.com/docker/distribution/reference/reference.go index 8c0c23b2fe..b7cd00b0d6 100644 --- a/vendor/github.com/docker/distribution/reference/reference.go +++ b/vendor/github.com/docker/distribution/reference/reference.go @@ -3,13 +3,13 @@ // // Grammar // -// reference := name [ ":" tag ] [ "@" digest ] +// reference := name [ ":" tag ] [ "@" digest ] // name := [domain '/'] path-component ['/' path-component]* // domain := domain-component ['.' domain-component]* [':' port-number] // domain-component := /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/ // port-number := /[0-9]+/ // path-component := alpha-numeric [separator alpha-numeric]* -// alpha-numeric := /[a-z0-9]+/ +// alpha-numeric := /[a-z0-9]+/ // separator := /[_.]|__|[-]*/ // // tag := /[\w][\w.-]{0,127}/ diff --git a/vendor/github.com/docker/distribution/registry/api/v2/descriptors.go b/vendor/github.com/docker/distribution/registry/api/v2/descriptors.go index a9616c58ad..c3bf90f71d 100644 --- a/vendor/github.com/docker/distribution/registry/api/v2/descriptors.go +++ b/vendor/github.com/docker/distribution/registry/api/v2/descriptors.go @@ -134,6 +134,19 @@ var ( }, } + invalidPaginationResponseDescriptor = ResponseDescriptor{ + Name: "Invalid pagination number", + Description: "The received parameter n was invalid in some way, as described by the error code. The client should resolve the issue and retry the request.", + StatusCode: http.StatusBadRequest, + Body: BodyDescriptor{ + ContentType: "application/json", + Format: errorsBody, + }, + ErrorCodes: []errcode.ErrorCode{ + ErrorCodePaginationNumberInvalid, + }, + } + repositoryNotFoundResponseDescriptor = ResponseDescriptor{ Name: "No Such Repository Error", StatusCode: http.StatusNotFound, @@ -490,6 +503,7 @@ var routeDescriptors = []RouteDescriptor{ }, }, Failures: []ResponseDescriptor{ + invalidPaginationResponseDescriptor, unauthorizedResponseDescriptor, repositoryNotFoundResponseDescriptor, deniedResponseDescriptor, @@ -1578,6 +1592,9 @@ var routeDescriptors = []RouteDescriptor{ }, }, }, + Failures: []ResponseDescriptor{ + invalidPaginationResponseDescriptor, + }, }, }, }, diff --git a/vendor/github.com/docker/distribution/registry/api/v2/errors.go b/vendor/github.com/docker/distribution/registry/api/v2/errors.go index 97d6923aa0..87e9f3c14b 100644 --- a/vendor/github.com/docker/distribution/registry/api/v2/errors.go +++ b/vendor/github.com/docker/distribution/registry/api/v2/errors.go @@ -133,4 +133,13 @@ var ( longer proceed.`, HTTPStatusCode: http.StatusNotFound, }) + + ErrorCodePaginationNumberInvalid = errcode.Register(errGroup, errcode.ErrorDescriptor{ + Value: "PAGINATION_NUMBER_INVALID", + Message: "invalid number of results requested", + Description: `Returned when the "n" parameter (number of results + to return) is not an integer, "n" is negative or "n" is bigger than + the maximum allowed.`, + HTTPStatusCode: http.StatusBadRequest, + }) ) diff --git a/vendor/github.com/docker/distribution/registry/client/errors.go b/vendor/github.com/docker/distribution/registry/client/errors.go index 52d49d5d29..024df43dd9 100644 --- a/vendor/github.com/docker/distribution/registry/client/errors.go +++ b/vendor/github.com/docker/distribution/registry/client/errors.go @@ -55,6 +55,8 @@ func parseHTTPErrorResponse(statusCode int, r io.Reader) error { switch statusCode { case http.StatusUnauthorized: return errcode.ErrorCodeUnauthorized.WithMessage(detailsErr.Details) + case http.StatusForbidden: + return errcode.ErrorCodeDenied.WithMessage(detailsErr.Details) case http.StatusTooManyRequests: return errcode.ErrorCodeTooManyRequests.WithMessage(detailsErr.Details) default: diff --git a/vendor/github.com/docker/distribution/registry/client/repository.go b/vendor/github.com/docker/distribution/registry/client/repository.go index 3e2ae66d3c..04e5a3ba01 100644 --- a/vendor/github.com/docker/distribution/registry/client/repository.go +++ b/vendor/github.com/docker/distribution/registry/client/repository.go @@ -114,9 +114,7 @@ func (r *registry) Repositories(ctx context.Context, entries []string, last stri return 0, err } - for cnt := range ctlg.Repositories { - entries[cnt] = ctlg.Repositories[cnt] - } + copy(entries, ctlg.Repositories) numFilled = len(ctlg.Repositories) link := resp.Header.Get("Link") diff --git a/vendor/github.com/docker/distribution/registry/client/transport/http_reader.go b/vendor/github.com/docker/distribution/registry/client/transport/http_reader.go index 1d0b382fb5..9120dbed66 100644 --- a/vendor/github.com/docker/distribution/registry/client/transport/http_reader.go +++ b/vendor/github.com/docker/distribution/registry/client/transport/http_reader.go @@ -180,7 +180,6 @@ func (hrs *httpReadSeeker) reader() (io.Reader, error) { // context.GetLogger(hrs.context).Infof("Range: %s", req.Header.Get("Range")) } - req.Header.Add("Accept-Encoding", "identity") resp, err := hrs.client.Do(req) if err != nil { return nil, err diff --git a/vendor/modules.txt b/vendor/modules.txt index e4f7cff5b9..d8e17fb540 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -362,7 +362,7 @@ github.com/deckarep/golang-set/v2 # github.com/dimchansky/utfbom v1.1.1 ## explicit github.com/dimchansky/utfbom -# github.com/docker/distribution v2.8.1+incompatible +# github.com/docker/distribution v2.8.2+incompatible ## explicit github.com/docker/distribution github.com/docker/distribution/digestset |