From cc01caaecb801e97e20c399176f5fe176f6eec3f Mon Sep 17 00:00:00 2001 From: CrazyMax Date: Wed, 30 Nov 2022 15:02:42 +0100 Subject: [PATCH] builder: enhance driver factory logic when loading drivers Signed-off-by: CrazyMax --- builder/builder.go | 48 +++++++++++++++++++++++++++++++++++++++++++--- builder/node.go | 30 +++-------------------------- 2 files changed, 48 insertions(+), 30 deletions(-) diff --git a/builder/builder.go b/builder/builder.go index 33ea9e9c..ba068889 100644 --- a/builder/builder.go +++ b/builder/builder.go @@ -4,10 +4,12 @@ import ( "context" "os" "sort" + "sync" "github.com/docker/buildx/driver" "github.com/docker/buildx/store" "github.com/docker/buildx/store/storeutil" + "github.com/docker/buildx/util/dockerutil" "github.com/docker/buildx/util/imagetools" "github.com/docker/buildx/util/progress" "github.com/docker/cli/cli/command" @@ -18,9 +20,10 @@ import ( // Builder represents an active builder object type Builder struct { *store.NodeGroup - nodes []Node - opts builderOpts - err error + driverFactory driverFactory + nodes []Node + opts builderOpts + err error } type builderOpts struct { @@ -201,6 +204,45 @@ func (b *Builder) Err() error { return b.err } +type driverFactory struct { + driver.Factory + once sync.Once +} + +// Factory returns the driver factory. +func (b *Builder) Factory(ctx context.Context) (_ driver.Factory, err error) { + b.driverFactory.once.Do(func() { + if b.Driver != "" { + b.driverFactory.Factory, err = driver.GetFactory(b.Driver, true) + if err != nil { + return + } + } else { + // empty driver means nodegroup was implicitly created as a default + // driver for a docker context and allows falling back to a + // docker-container driver for older daemon that doesn't support + // buildkit (< 18.06). + ep := b.nodes[0].Endpoint + var dockerapi *dockerutil.ClientAPI + dockerapi, err = dockerutil.NewClientAPI(b.opts.dockerCli, b.nodes[0].Endpoint) + if err != nil { + return + } + // check if endpoint is healthy is needed to determine the driver type. + // if this fails then can't continue with driver selection. + if _, err = dockerapi.Ping(ctx); err != nil { + return + } + b.driverFactory.Factory, err = driver.GetDefaultFactory(ctx, ep, dockerapi, false) + if err != nil { + return + } + b.Driver = b.driverFactory.Factory.Name() + } + }) + return b.driverFactory.Factory, err +} + // GetBuilders returns all builders func GetBuilders(dockerCli command.Cli, txn *store.Txn) ([]*Builder, error) { storeng, err := txn.List() diff --git a/builder/node.go b/builder/node.go index 54b0d3a6..f565738d 100644 --- a/builder/node.go +++ b/builder/node.go @@ -46,33 +46,9 @@ func (b *Builder) LoadNodes(ctx context.Context, withData bool) (_ []Node, err e } }() - // TODO: factory should be lazy and a dedicated method in Builder object - var factory driver.Factory - if b.NodeGroup.Driver != "" { - factory, err = driver.GetFactory(b.NodeGroup.Driver, true) - if err != nil { - return nil, err - } - } else { - // empty driver means nodegroup was implicitly created as a default - // driver for a docker context and allows falling back to a - // docker-container driver for older daemon that doesn't support - // buildkit (< 18.06). - ep := b.NodeGroup.Nodes[0].Endpoint - dockerapi, err := dockerutil.NewClientAPI(b.opts.dockerCli, b.NodeGroup.Nodes[0].Endpoint) - if err != nil { - return nil, err - } - // check if endpoint is healthy is needed to determine the driver type. - // if this fails then can't continue with driver selection. - if _, err = dockerapi.Ping(ctx); err != nil { - return nil, err - } - factory, err = driver.GetDefaultFactory(ctx, ep, dockerapi, false) - if err != nil { - return nil, err - } - b.NodeGroup.Driver = factory.Name() + factory, err := b.Factory(ctx) + if err != nil { + return nil, err } imageopt, err := b.ImageOpt()