Merge pull request #2302 from crazy-max/multi-load-push

build: handle push/load shorthands for multi exporters
This commit is contained in:
Tõnis Tiigi 2024-03-05 09:09:30 -08:00 committed by GitHub
commit 9ebfde4897
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 320 additions and 29 deletions

View File

@ -72,11 +72,9 @@ func runBake(ctx context.Context, dockerCli command.Cli, targets []string, in ba
overrides := in.overrides overrides := in.overrides
if in.exportPush { if in.exportPush {
if in.exportLoad { overrides = append(overrides, "*.output=type=registry")
return errors.Errorf("push and load may not be set together at the moment") }
} if in.exportLoad {
overrides = append(overrides, "*.push=true")
} else if in.exportLoad {
overrides = append(overrides, "*.output=type=docker") overrides = append(overrides, "*.output=type=docker")
} }
if cFlags.noCache != nil { if cFlags.noCache != nil {

View File

@ -99,38 +99,38 @@ func RunBuild(ctx context.Context, dockerCli command.Cli, in controllerapi.Build
return nil, nil, err return nil, nil, err
} }
if in.ExportPush { if in.ExportPush {
if in.ExportLoad { var pushUsed bool
return nil, nil, errors.Errorf("push and load may not be set together at the moment") for i := range outputs {
if outputs[i].Type == client.ExporterImage {
outputs[i].Attrs["push"] = "true"
pushUsed = true
}
} }
if len(outputs) == 0 { if !pushUsed {
outputs = []client.ExportEntry{{ outputs = append(outputs, client.ExportEntry{
Type: "image", Type: client.ExporterImage,
Attrs: map[string]string{ Attrs: map[string]string{
"push": "true", "push": "true",
}, },
}} })
} else {
switch outputs[0].Type {
case "image":
outputs[0].Attrs["push"] = "true"
default:
return nil, nil, errors.Errorf("push and %q output can't be used together", outputs[0].Type)
}
} }
} }
if in.ExportLoad { if in.ExportLoad {
if len(outputs) == 0 { var loadUsed bool
outputs = []client.ExportEntry{{ for i := range outputs {
Type: "docker", if outputs[i].Type == client.ExporterDocker {
Attrs: map[string]string{}, if _, ok := outputs[i].Attrs["dest"]; !ok {
}} loadUsed = true
} else { break
switch outputs[0].Type { }
case "docker":
default:
return nil, nil, errors.Errorf("load and %q output can't be used together", outputs[0].Type)
} }
} }
if !loadUsed {
outputs = append(outputs, client.ExportEntry{
Type: client.ExporterDocker,
Attrs: map[string]string{},
})
}
} }
annotations, err := buildflags.ParseAnnotations(in.Annotations) annotations, err := buildflags.ParseAnnotations(in.Annotations)

View File

@ -2,13 +2,19 @@ package tests
import ( import (
"encoding/json" "encoding/json"
"fmt"
"os" "os"
"path/filepath" "path/filepath"
"strings"
"testing" "testing"
"github.com/containerd/continuity/fs/fstest" "github.com/containerd/continuity/fs/fstest"
"github.com/docker/buildx/util/gitutil" "github.com/docker/buildx/util/gitutil"
"github.com/moby/buildkit/identity"
"github.com/moby/buildkit/util/contentutil"
"github.com/moby/buildkit/util/testutil"
"github.com/moby/buildkit/util/testutil/integration" "github.com/moby/buildkit/util/testutil/integration"
"github.com/pkg/errors"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -36,6 +42,8 @@ var bakeTests = []func(t *testing.T, sb integration.Sandbox){
testBakeShmSize, testBakeShmSize,
testBakeUlimits, testBakeUlimits,
testBakeRefs, testBakeRefs,
testBakeMultiExporters,
testBakeLoadPush,
} }
func testBakeLocal(t *testing.T, sb integration.Sandbox) { func testBakeLocal(t *testing.T, sb integration.Sandbox) {
@ -631,3 +639,155 @@ target "default" {
require.NotEmpty(t, md.Default.BuildRef) require.NotEmpty(t, md.Default.BuildRef)
} }
func testBakeMultiExporters(t *testing.T, sb integration.Sandbox) {
if sb.Name() != "docker" {
t.Skip("skipping test for non-docker workers")
}
registry, err := sb.NewRegistry()
if errors.Is(err, integration.ErrRequirements) {
t.Skip(err.Error())
}
require.NoError(t, err)
targetReg := registry + "/buildx/registry:latest"
targetStore := "buildx:local-" + identity.NewID()
var builderName string
t.Cleanup(func() {
if builderName == "" {
return
}
cmd := dockerCmd(sb, withArgs("image", "rm", targetStore))
cmd.Stderr = os.Stderr
require.NoError(t, cmd.Run())
out, err := rmCmd(sb, withArgs(builderName))
require.NoError(t, err, out)
})
// TODO: use stable buildkit image when v0.13.0 released
out, err := createCmd(sb, withArgs(
"--driver", "docker-container",
"--buildkitd-flags=--allow-insecure-entitlement=network.host",
"--driver-opt", "network=host",
"--driver-opt", "image=moby/buildkit:v0.13.0-rc3",
))
require.NoError(t, err, out)
builderName = strings.TrimSpace(out)
dockerfile := []byte(`
FROM scratch
COPY foo /foo
`)
bakefile := []byte(`
target "default" {
}
`)
dir := tmpdir(
t,
fstest.CreateFile("docker-bake.hcl", bakefile, 0600),
fstest.CreateFile("Dockerfile", dockerfile, 0600),
fstest.CreateFile("foo", []byte("foo"), 0600),
)
outputs := []string{
"--set", fmt.Sprintf("*.output=type=image,name=%s,push=true", targetReg),
"--set", fmt.Sprintf("*.output=type=docker,name=%s", targetStore),
"--set", fmt.Sprintf("*.output=type=oci,dest=%s/result", dir),
}
cmd := buildxCmd(sb, withDir(dir), withArgs("bake"), withArgs(outputs...))
cmd.Env = append(cmd.Env, "BUILDX_BUILDER="+builderName)
outb, err := cmd.CombinedOutput()
require.NoError(t, err, string(outb))
// test registry
desc, provider, err := contentutil.ProviderFromRef(targetReg)
require.NoError(t, err)
_, err = testutil.ReadImages(sb.Context(), provider, desc)
require.NoError(t, err)
// test docker store
cmd = dockerCmd(sb, withArgs("image", "inspect", targetStore))
cmd.Stderr = os.Stderr
require.NoError(t, cmd.Run())
// test oci
_, err = os.ReadFile(fmt.Sprintf("%s/result", dir))
require.NoError(t, err)
// TODO: test metadata file when supported by multi exporters https://github.com/docker/buildx/issues/2181
}
func testBakeLoadPush(t *testing.T, sb integration.Sandbox) {
if sb.Name() != "docker" {
t.Skip("skipping test for non-docker workers")
}
registry, err := sb.NewRegistry()
if errors.Is(err, integration.ErrRequirements) {
t.Skip(err.Error())
}
require.NoError(t, err)
target := registry + "/buildx/registry:" + identity.NewID()
var builderName string
t.Cleanup(func() {
if builderName == "" {
return
}
cmd := dockerCmd(sb, withArgs("image", "rm", target))
cmd.Stderr = os.Stderr
require.NoError(t, cmd.Run())
out, err := rmCmd(sb, withArgs(builderName))
require.NoError(t, err, out)
})
// TODO: use stable buildkit image when v0.13.0 released
out, err := createCmd(sb, withArgs(
"--driver", "docker-container",
"--buildkitd-flags=--allow-insecure-entitlement=network.host",
"--driver-opt", "network=host",
"--driver-opt", "image=moby/buildkit:v0.13.0-rc3",
))
require.NoError(t, err, out)
builderName = strings.TrimSpace(out)
dockerfile := []byte(`
FROM scratch
COPY foo /foo
`)
bakefile := []byte(`
target "default" {
}
`)
dir := tmpdir(
t,
fstest.CreateFile("docker-bake.hcl", bakefile, 0600),
fstest.CreateFile("Dockerfile", dockerfile, 0600),
fstest.CreateFile("foo", []byte("foo"), 0600),
)
cmd := buildxCmd(sb, withDir(dir), withArgs("bake", "--push", "--load", fmt.Sprintf("--set=*.tags=%s", target)))
cmd.Env = append(cmd.Env, "BUILDX_BUILDER="+builderName)
outb, err := cmd.CombinedOutput()
require.NoError(t, err, string(outb))
// test registry
desc, provider, err := contentutil.ProviderFromRef(target)
require.NoError(t, err)
_, err = testutil.ReadImages(sb.Context(), provider, desc)
require.NoError(t, err)
// test docker store
cmd = dockerCmd(sb, withArgs("image", "inspect", target))
cmd.Stderr = os.Stderr
require.NoError(t, cmd.Run())
// TODO: test metadata file when supported by multi exporters https://github.com/docker/buildx/issues/2181
}

View File

@ -16,6 +16,7 @@ import (
"github.com/containerd/containerd/platforms" "github.com/containerd/containerd/platforms"
"github.com/containerd/continuity/fs/fstest" "github.com/containerd/continuity/fs/fstest"
"github.com/creack/pty" "github.com/creack/pty"
"github.com/moby/buildkit/identity"
"github.com/moby/buildkit/util/appdefaults" "github.com/moby/buildkit/util/appdefaults"
"github.com/moby/buildkit/util/contentutil" "github.com/moby/buildkit/util/contentutil"
"github.com/moby/buildkit/util/testutil" "github.com/moby/buildkit/util/testutil"
@ -54,6 +55,8 @@ var buildTests = []func(t *testing.T, sb integration.Sandbox){
testBuildShmSize, testBuildShmSize,
testBuildUlimit, testBuildUlimit,
testBuildRef, testBuildRef,
testBuildMultiExporters,
testBuildLoadPush,
} }
func testBuild(t *testing.T, sb integration.Sandbox) { func testBuild(t *testing.T, sb integration.Sandbox) {
@ -437,7 +440,7 @@ func testBuildNetworkModeBridge(t *testing.T, sb integration.Sandbox) {
}) })
// TODO: use stable buildkit image when v0.13.0 released // TODO: use stable buildkit image when v0.13.0 released
out, err := createCmd(sb, withArgs("--driver", "docker-container", "--buildkitd-flags=--oci-worker-net=bridge --allow-insecure-entitlement=network.host", "--driver-opt", "image=moby/buildkit:master")) out, err := createCmd(sb, withArgs("--driver", "docker-container", "--buildkitd-flags=--oci-worker-net=bridge --allow-insecure-entitlement=network.host", "--driver-opt", "image=moby/buildkit:v0.13.0-rc3"))
require.NoError(t, err, out) require.NoError(t, err, out)
builderName = strings.TrimSpace(out) builderName = strings.TrimSpace(out)
@ -542,6 +545,136 @@ func testBuildRef(t *testing.T, sb integration.Sandbox) {
require.NotEmpty(t, md.BuildRef) require.NotEmpty(t, md.BuildRef)
} }
func testBuildMultiExporters(t *testing.T, sb integration.Sandbox) {
if sb.Name() != "docker" {
t.Skip("skipping test for non-docker workers")
}
registry, err := sb.NewRegistry()
if errors.Is(err, integration.ErrRequirements) {
t.Skip(err.Error())
}
require.NoError(t, err)
targetReg := registry + "/buildx/registry:latest"
targetStore := "buildx:local-" + identity.NewID()
var builderName string
t.Cleanup(func() {
if builderName == "" {
return
}
cmd := dockerCmd(sb, withArgs("image", "rm", targetStore))
cmd.Stderr = os.Stderr
require.NoError(t, cmd.Run())
out, err := rmCmd(sb, withArgs(builderName))
require.NoError(t, err, out)
})
// TODO: use stable buildkit image when v0.13.0 released
out, err := createCmd(sb, withArgs(
"--driver", "docker-container",
"--buildkitd-flags=--allow-insecure-entitlement=network.host",
"--driver-opt", "network=host",
"--driver-opt", "image=moby/buildkit:v0.13.0-rc3",
))
require.NoError(t, err, out)
builderName = strings.TrimSpace(out)
dir := createTestProject(t)
outputs := []string{
"--output", fmt.Sprintf("type=image,name=%s,push=true", targetReg),
"--output", fmt.Sprintf("type=docker,name=%s", targetStore),
"--output", fmt.Sprintf("type=oci,dest=%s/result", dir),
}
cmd := buildxCmd(sb, withArgs("build"), withArgs(outputs...), withArgs(dir))
cmd.Env = append(cmd.Env, "BUILDX_BUILDER="+builderName)
outb, err := cmd.CombinedOutput()
require.NoError(t, err, string(outb))
// test registry
desc, provider, err := contentutil.ProviderFromRef(targetReg)
require.NoError(t, err)
_, err = testutil.ReadImages(sb.Context(), provider, desc)
require.NoError(t, err)
// test docker store
cmd = dockerCmd(sb, withArgs("image", "inspect", targetStore))
cmd.Stderr = os.Stderr
require.NoError(t, cmd.Run())
// test oci
_, err = os.ReadFile(fmt.Sprintf("%s/result", dir))
require.NoError(t, err)
// TODO: test metadata file when supported by multi exporters https://github.com/docker/buildx/issues/2181
}
func testBuildLoadPush(t *testing.T, sb integration.Sandbox) {
if sb.Name() != "docker" {
t.Skip("skipping test for non-docker workers")
}
registry, err := sb.NewRegistry()
if errors.Is(err, integration.ErrRequirements) {
t.Skip(err.Error())
}
require.NoError(t, err)
target := registry + "/buildx/registry:" + identity.NewID()
var builderName string
t.Cleanup(func() {
if builderName == "" {
return
}
cmd := dockerCmd(sb, withArgs("image", "rm", target))
cmd.Stderr = os.Stderr
require.NoError(t, cmd.Run())
out, err := rmCmd(sb, withArgs(builderName))
require.NoError(t, err, out)
})
// TODO: use stable buildkit image when v0.13.0 released
out, err := createCmd(sb, withArgs(
"--driver", "docker-container",
"--buildkitd-flags=--allow-insecure-entitlement=network.host",
"--driver-opt", "network=host",
"--driver-opt", "image=moby/buildkit:v0.13.0-rc3",
))
require.NoError(t, err, out)
builderName = strings.TrimSpace(out)
dir := createTestProject(t)
cmd := buildxCmd(sb, withArgs(
"build", "--push", "--load",
fmt.Sprintf("-t=%s", target),
dir,
))
cmd.Env = append(cmd.Env, "BUILDX_BUILDER="+builderName)
outb, err := cmd.CombinedOutput()
require.NoError(t, err, string(outb))
// test registry
desc, provider, err := contentutil.ProviderFromRef(target)
require.NoError(t, err)
_, err = testutil.ReadImages(sb.Context(), provider, desc)
require.NoError(t, err)
// test docker store
cmd = dockerCmd(sb, withArgs("image", "inspect", target))
cmd.Stderr = os.Stderr
require.NoError(t, cmd.Run())
// TODO: test metadata file when supported by multi exporters https://github.com/docker/buildx/issues/2181
}
func createTestProject(t *testing.T) string { func createTestProject(t *testing.T) string {
dockerfile := []byte(` dockerfile := []byte(`
FROM busybox:latest AS base FROM busybox:latest AS base