diff --git a/build/build.go b/build/build.go index 45d82177..b12cfe22 100644 --- a/build/build.go +++ b/build/build.go @@ -3,6 +3,8 @@ package build import ( "bufio" "context" + "crypto/rand" + "encoding/hex" "encoding/json" "fmt" "io" @@ -334,7 +336,7 @@ func toRepoOnly(in string) (string, error) { return strings.Join(out, ","), nil } -func toSolveOpt(ctx context.Context, d driver.Driver, multiDriver bool, opt Options, bopts gateway.BuildOpts, pw progress.Writer, dl dockerLoadCallback) (solveOpt *client.SolveOpt, release func(), err error) { +func toSolveOpt(ctx context.Context, d driver.Driver, multiDriver bool, opt Options, bopts gateway.BuildOpts, configDir string, pw progress.Writer, dl dockerLoadCallback) (solveOpt *client.SolveOpt, release func(), err error) { defers := make([]func(), 0, 2) releaseF := func() { for _, f := range defers { @@ -511,6 +513,13 @@ func toSolveOpt(ctx context.Context, d driver.Driver, multiDriver bool, opt Opti } defers = append(defers, releaseLoad) + if sharedKey := so.LocalDirs["context"]; sharedKey != "" { + if p, err := filepath.Abs(sharedKey); err == nil { + sharedKey = filepath.Base(p) + } + so.SharedKey = sharedKey + ":" + tryNodeIdentifier(configDir) + } + if opt.Pull { so.FrontendAttrs["image-resolve-mode"] = "pull" } @@ -574,7 +583,7 @@ func toSolveOpt(ctx context.Context, d driver.Driver, multiDriver bool, opt Opti return &so, releaseF, nil } -func Build(ctx context.Context, drivers []DriverInfo, opt map[string]Options, docker DockerAPI, auth Auth, w progress.Writer) (resp map[string]*client.SolveResponse, err error) { +func Build(ctx context.Context, drivers []DriverInfo, opt map[string]Options, docker DockerAPI, auth Auth, configDir string, w progress.Writer) (resp map[string]*client.SolveResponse, err error) { if len(drivers) == 0 { return nil, errors.Errorf("driver required for build") } @@ -626,7 +635,7 @@ func Build(ctx context.Context, drivers []DriverInfo, opt map[string]Options, do hasMobyDriver = true } opt.Platforms = dp.platforms - so, release, err := toSolveOpt(ctx, d, multiDriver, opt, dp.bopts, w, func(name string) (io.WriteCloser, func(), error) { + so, release, err := toSolveOpt(ctx, d, multiDriver, opt, dp.bopts, configDir, w, func(name string) (io.WriteCloser, func(), error) { return newDockerLoader(ctx, docker, name, w) }) if err != nil { @@ -1175,3 +1184,28 @@ func wrapWriteCloser(wc io.WriteCloser) func(map[string]string) (io.WriteCloser, return wc, nil } } + +var nodeIdentifierMu sync.Mutex + +func tryNodeIdentifier(configDir string) (out string) { + nodeIdentifierMu.Lock() + defer nodeIdentifierMu.Unlock() + sessionFile := filepath.Join(configDir, ".buildNodeID") + if _, err := os.Lstat(sessionFile); err != nil { + if os.IsNotExist(err) { // create a new file with stored randomness + b := make([]byte, 8) + if _, err := rand.Read(b); err != nil { + return out + } + if err := ioutil.WriteFile(sessionFile, []byte(hex.EncodeToString(b)), 0600); err != nil { + return out + } + } + } + + dt, err := ioutil.ReadFile(sessionFile) + if err == nil { + return string(dt) + } + return +} diff --git a/commands/bake.go b/commands/bake.go index 2ec451b2..6f801b8c 100644 --- a/commands/bake.go +++ b/commands/bake.go @@ -9,6 +9,7 @@ import ( "github.com/containerd/containerd/platforms" "github.com/docker/buildx/bake" "github.com/docker/buildx/build" + "github.com/docker/buildx/util/confutil" "github.com/docker/buildx/util/progress" "github.com/docker/buildx/util/tracing" "github.com/docker/cli/cli/command" @@ -155,7 +156,7 @@ func runBake(dockerCli command.Cli, targets []string, in bakeOptions) (err error return nil } - resp, err := build.Build(ctx, dis, bo, dockerAPI(dockerCli), dockerCli.ConfigFile(), printer) + resp, err := build.Build(ctx, dis, bo, dockerAPI(dockerCli), dockerCli.ConfigFile(), confutil.ConfigDir(dockerCli), printer) if err != nil { return err } diff --git a/commands/build.go b/commands/build.go index 8b0be4e4..1499e3d6 100644 --- a/commands/build.go +++ b/commands/build.go @@ -10,6 +10,7 @@ import ( "github.com/docker/buildx/build" "github.com/docker/buildx/util/buildflags" + "github.com/docker/buildx/util/confutil" "github.com/docker/buildx/util/platformutil" "github.com/docker/buildx/util/progress" "github.com/docker/buildx/util/tracing" @@ -224,7 +225,7 @@ func buildTargets(ctx context.Context, dockerCli command.Cli, opts map[string]bu printer := progress.NewPrinter(ctx2, os.Stderr, progressMode) - resp, err := build.Build(ctx, dis, opts, dockerAPI(dockerCli), dockerCli.ConfigFile(), printer) + resp, err := build.Build(ctx, dis, opts, dockerAPI(dockerCli), dockerCli.ConfigFile(), confutil.ConfigDir(dockerCli), printer) err1 := printer.Wait() if err == nil { err = err1 diff --git a/commands/util.go b/commands/util.go index fbb89f7c..003d32a7 100644 --- a/commands/util.go +++ b/commands/util.go @@ -4,12 +4,12 @@ import ( "context" "net/url" "os" - "path/filepath" "strings" "github.com/docker/buildx/build" "github.com/docker/buildx/driver" "github.com/docker/buildx/store" + "github.com/docker/buildx/util/confutil" "github.com/docker/buildx/util/platformutil" "github.com/docker/buildx/util/progress" "github.com/docker/cli/cli/command" @@ -27,27 +27,13 @@ import ( // getStore returns current builder instance store func getStore(dockerCli command.Cli) (*store.Txn, func(), error) { - s, err := store.New(getConfigStorePath(dockerCli)) + s, err := store.New(confutil.ConfigDir(dockerCli)) if err != nil { return nil, nil, err } return s.Txn() } -// getConfigStorePath will look for correct configuration store path; -// if `$BUILDX_CONFIG` is set - use it, otherwise use parent directory -// of Docker config file (i.e. `${DOCKER_CONFIG}/buildx`) -func getConfigStorePath(dockerCli command.Cli) string { - if buildxConfig := os.Getenv("BUILDX_CONFIG"); buildxConfig != "" { - logrus.Debugf("using config store %q based in \"$BUILDX_CONFIG\" environment variable", buildxConfig) - return buildxConfig - } - - buildxConfig := filepath.Join(filepath.Dir(dockerCli.ConfigFile().Filename), "buildx") - logrus.Debugf("using default config store %q", buildxConfig) - return buildxConfig -} - // getCurrentEndpoint returns the current default endpoint value func getCurrentEndpoint(dockerCli command.Cli) (string, error) { name := dockerCli.CurrentContext() diff --git a/util/confutil/config.go b/util/confutil/config.go index 8aa607be..f129483a 100644 --- a/util/confutil/config.go +++ b/util/confutil/config.go @@ -2,11 +2,28 @@ package confutil import ( "os" + "path/filepath" + "github.com/docker/cli/cli/command" "github.com/pelletier/go-toml" "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) +// ConfigDir will look for correct configuration store path; +// if `$BUILDX_CONFIG` is set - use it, otherwise use parent directory +// of Docker config file (i.e. `${DOCKER_CONFIG}/buildx`) +func ConfigDir(dockerCli command.Cli) string { + if buildxConfig := os.Getenv("BUILDX_CONFIG"); buildxConfig != "" { + logrus.Debugf("using config store %q based in \"$BUILDX_CONFIG\" environment variable", buildxConfig) + return buildxConfig + } + + buildxConfig := filepath.Join(filepath.Dir(dockerCli.ConfigFile().Filename), "buildx") + logrus.Debugf("using default config store %q", buildxConfig) + return buildxConfig +} + // loadConfigTree loads BuildKit config toml tree func loadConfigTree(fp string) (*toml.Tree, error) { f, err := os.Open(fp)