From 9b723ece461bc6bd05a59fefbf19d46173bb2f6c Mon Sep 17 00:00:00 2001 From: CrazyMax Date: Fri, 26 May 2023 10:21:48 +0200 Subject: [PATCH 1/3] driver: check history capability Signed-off-by: CrazyMax --- driver/docker-container/driver.go | 13 ++++++++++--- driver/docker/driver.go | 3 +++ driver/driver.go | 26 ++++++++++++++++++++++++++ driver/features.go | 2 ++ driver/kubernetes/driver.go | 13 ++++++++++--- driver/remote/driver.go | 8 ++++++++ 6 files changed, 59 insertions(+), 6 deletions(-) diff --git a/driver/docker-container/driver.go b/driver/docker-container/driver.go index 56f99d5a..71469f57 100644 --- a/driver/docker-container/driver.go +++ b/driver/docker-container/driver.go @@ -388,12 +388,19 @@ func (d *Driver) Factory() driver.Factory { } func (d *Driver) Features() map[driver.Feature]bool { + var historyAPI bool + ctx := context.Background() + c, err := d.Client(ctx) + if err == nil { + historyAPI = driver.HistoryAPISupported(ctx, c) + c.Close() + } return map[driver.Feature]bool{ driver.OCIExporter: true, driver.DockerExporter: true, - - driver.CacheExport: true, - driver.MultiPlatform: true, + driver.CacheExport: true, + driver.MultiPlatform: true, + driver.HistoryAPI: historyAPI, } } diff --git a/driver/docker/driver.go b/driver/docker/driver.go index 797b1e9a..599e9b51 100644 --- a/driver/docker/driver.go +++ b/driver/docker/driver.go @@ -60,6 +60,7 @@ func (d *Driver) Client(ctx context.Context) (*client.Client, error) { func (d *Driver) Features() map[driver.Feature]bool { var useContainerdSnapshotter bool + var historyAPI bool ctx := context.Background() c, err := d.Client(ctx) if err == nil { @@ -69,6 +70,7 @@ func (d *Driver) Features() map[driver.Feature]bool { useContainerdSnapshotter = true } } + historyAPI = driver.HistoryAPISupported(ctx, c) c.Close() } return map[driver.Feature]bool{ @@ -76,6 +78,7 @@ func (d *Driver) Features() map[driver.Feature]bool { driver.DockerExporter: useContainerdSnapshotter, driver.CacheExport: useContainerdSnapshotter, driver.MultiPlatform: useContainerdSnapshotter, + driver.HistoryAPI: historyAPI, } } diff --git a/driver/driver.go b/driver/driver.go index ed108031..b6ca5275 100644 --- a/driver/driver.go +++ b/driver/driver.go @@ -6,8 +6,11 @@ import ( "github.com/docker/buildx/store" "github.com/docker/buildx/util/progress" clitypes "github.com/docker/cli/cli/config/types" + controlapi "github.com/moby/buildkit/api/services/control" "github.com/moby/buildkit/client" + "github.com/moby/buildkit/util/grpcerrors" "github.com/pkg/errors" + "google.golang.org/grpc/codes" ) var ErrNotRunning = errors.Errorf("driver not running") @@ -89,3 +92,26 @@ func Boot(ctx, clientContext context.Context, d Driver, pw progress.Writer) (*cl return c, nil } } + +func HistoryAPISupported(ctx context.Context, c *client.Client) (res bool) { + res = true + checkErrF := func(err error) { + if s, ok := grpcerrors.AsGRPCStatus(err); ok { + if s.Code() == codes.Unimplemented { + res = false + } + } + } + cl, err := c.ControlClient().ListenBuildHistory(ctx, &controlapi.BuildHistoryRequest{ + ActiveOnly: true, + Ref: "buildx-dummy-ref", // dummy ref to check if the server supports the API + EarlyExit: true, + }) + if err != nil { + checkErrF(err) + return + } + _, err = cl.Recv() + checkErrF(err) + return +} diff --git a/driver/features.go b/driver/features.go index 3438f7e0..d908d750 100644 --- a/driver/features.go +++ b/driver/features.go @@ -7,3 +7,5 @@ const DockerExporter Feature = "Docker exporter" const CacheExport Feature = "cache export" const MultiPlatform Feature = "multiple platforms" + +const HistoryAPI Feature = "history api" diff --git a/driver/kubernetes/driver.go b/driver/kubernetes/driver.go index d306c60c..d8fa25b9 100644 --- a/driver/kubernetes/driver.go +++ b/driver/kubernetes/driver.go @@ -229,11 +229,18 @@ func (d *Driver) Factory() driver.Factory { } func (d *Driver) Features() map[driver.Feature]bool { + var historyAPI bool + ctx := context.Background() + c, err := d.Client(ctx) + if err == nil { + historyAPI = driver.HistoryAPISupported(ctx, c) + c.Close() + } return map[driver.Feature]bool{ driver.OCIExporter: true, driver.DockerExporter: d.DockerAPI != nil, - - driver.CacheExport: true, - driver.MultiPlatform: true, // Untested (needs multiple Driver instances) + driver.CacheExport: true, + driver.MultiPlatform: true, // Untested (needs multiple Driver instances) + driver.HistoryAPI: historyAPI, } } diff --git a/driver/remote/driver.go b/driver/remote/driver.go index d446f226..58058612 100644 --- a/driver/remote/driver.go +++ b/driver/remote/driver.go @@ -88,11 +88,19 @@ func (d *Driver) Client(ctx context.Context) (*client.Client, error) { } func (d *Driver) Features() map[driver.Feature]bool { + var historyAPI bool + ctx := context.Background() + c, err := d.Client(ctx) + if err == nil { + historyAPI = driver.HistoryAPISupported(ctx, c) + c.Close() + } return map[driver.Feature]bool{ driver.OCIExporter: true, driver.DockerExporter: true, driver.CacheExport: true, driver.MultiPlatform: true, + driver.HistoryAPI: historyAPI, } } From d196ac347e5b3ef45086a42f96e3ed0f55d3ec51 Mon Sep 17 00:00:00 2001 From: CrazyMax Date: Fri, 26 May 2023 10:30:49 +0200 Subject: [PATCH 2/3] driver: cache features Signed-off-by: CrazyMax --- driver/manager.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/driver/manager.go b/driver/manager.go index 37436a22..13826cc8 100644 --- a/driver/manager.go +++ b/driver/manager.go @@ -147,9 +147,11 @@ func GetFactories(instanceRequired bool) []Factory { type cachedDriver struct { Driver - client *client.Client - err error - once sync.Once + client *client.Client + err error + once sync.Once + featuresOnce sync.Once + features map[Feature]bool } func (d *cachedDriver) Client(ctx context.Context) (*client.Client, error) { @@ -158,3 +160,10 @@ func (d *cachedDriver) Client(ctx context.Context) (*client.Client, error) { }) return d.client, d.err } + +func (d *cachedDriver) Features() map[Feature]bool { + d.featuresOnce.Do(func() { + d.features = d.Driver.Features() + }) + return d.features +} From 8c65e4fc1dbd4cd0f961081f7ffc4869d96d3c6c Mon Sep 17 00:00:00 2001 From: CrazyMax Date: Fri, 26 May 2023 11:29:46 +0200 Subject: [PATCH 3/3] driver: add context to Features interface Signed-off-by: CrazyMax --- build/build.go | 8 ++++---- driver/docker-container/driver.go | 3 +-- driver/docker/driver.go | 3 +-- driver/driver.go | 2 +- driver/kubernetes/driver.go | 3 +-- driver/manager.go | 4 ++-- driver/remote/driver.go | 3 +-- 7 files changed, 11 insertions(+), 15 deletions(-) diff --git a/build/build.go b/build/build.go index 4fd3cb11..ae027b4b 100644 --- a/build/build.go +++ b/build/build.go @@ -389,7 +389,7 @@ func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt Op } for _, e := range opt.CacheTo { - if e.Type != "inline" && !nodeDriver.Features()[driver.CacheExport] { + if e.Type != "inline" && !nodeDriver.Features(ctx)[driver.CacheExport] { return nil, nil, notSupported(nodeDriver, driver.CacheExport) } } @@ -527,7 +527,7 @@ func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt Op // set up exporters for i, e := range opt.Exports { - if e.Type == "oci" && !nodeDriver.Features()[driver.OCIExporter] { + if e.Type == "oci" && !nodeDriver.Features(ctx)[driver.OCIExporter] { return nil, nil, notSupported(nodeDriver, driver.OCIExporter) } if e.Type == "docker" { @@ -545,7 +545,7 @@ func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt Op defers = append(defers, cancel) opt.Exports[i].Output = wrapWriteCloser(w) } - } else if !nodeDriver.Features()[driver.DockerExporter] { + } else if !nodeDriver.Features(ctx)[driver.DockerExporter] { return nil, nil, notSupported(nodeDriver, driver.DockerExporter) } } @@ -614,7 +614,7 @@ func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt Op for i, p := range opt.Platforms { pp[i] = platforms.Format(p) } - if len(pp) > 1 && !nodeDriver.Features()[driver.MultiPlatform] { + if len(pp) > 1 && !nodeDriver.Features(ctx)[driver.MultiPlatform] { return nil, nil, notSupported(nodeDriver, driver.MultiPlatform) } so.FrontendAttrs["platform"] = strings.Join(pp, ",") diff --git a/driver/docker-container/driver.go b/driver/docker-container/driver.go index 71469f57..f2f1ad54 100644 --- a/driver/docker-container/driver.go +++ b/driver/docker-container/driver.go @@ -387,9 +387,8 @@ func (d *Driver) Factory() driver.Factory { return d.factory } -func (d *Driver) Features() map[driver.Feature]bool { +func (d *Driver) Features(ctx context.Context) map[driver.Feature]bool { var historyAPI bool - ctx := context.Background() c, err := d.Client(ctx) if err == nil { historyAPI = driver.HistoryAPISupported(ctx, c) diff --git a/driver/docker/driver.go b/driver/docker/driver.go index 599e9b51..3b6f16e2 100644 --- a/driver/docker/driver.go +++ b/driver/docker/driver.go @@ -58,10 +58,9 @@ func (d *Driver) Client(ctx context.Context) (*client.Client, error) { })) } -func (d *Driver) Features() map[driver.Feature]bool { +func (d *Driver) Features(ctx context.Context) map[driver.Feature]bool { var useContainerdSnapshotter bool var historyAPI bool - ctx := context.Background() c, err := d.Client(ctx) if err == nil { workers, _ := c.ListWorkers(ctx) diff --git a/driver/driver.go b/driver/driver.go index b6ca5275..aa378058 100644 --- a/driver/driver.go +++ b/driver/driver.go @@ -60,7 +60,7 @@ type Driver interface { Stop(ctx context.Context, force bool) error Rm(ctx context.Context, force, rmVolume, rmDaemon bool) error Client(ctx context.Context) (*client.Client, error) - Features() map[Feature]bool + Features(ctx context.Context) map[Feature]bool IsMobyDriver() bool Config() InitConfig } diff --git a/driver/kubernetes/driver.go b/driver/kubernetes/driver.go index d8fa25b9..be8ef697 100644 --- a/driver/kubernetes/driver.go +++ b/driver/kubernetes/driver.go @@ -228,9 +228,8 @@ func (d *Driver) Factory() driver.Factory { return d.factory } -func (d *Driver) Features() map[driver.Feature]bool { +func (d *Driver) Features(ctx context.Context) map[driver.Feature]bool { var historyAPI bool - ctx := context.Background() c, err := d.Client(ctx) if err == nil { historyAPI = driver.HistoryAPISupported(ctx, c) diff --git a/driver/manager.go b/driver/manager.go index 13826cc8..0db8254f 100644 --- a/driver/manager.go +++ b/driver/manager.go @@ -161,9 +161,9 @@ func (d *cachedDriver) Client(ctx context.Context) (*client.Client, error) { return d.client, d.err } -func (d *cachedDriver) Features() map[Feature]bool { +func (d *cachedDriver) Features(ctx context.Context) map[Feature]bool { d.featuresOnce.Do(func() { - d.features = d.Driver.Features() + d.features = d.Driver.Features(ctx) }) return d.features } diff --git a/driver/remote/driver.go b/driver/remote/driver.go index 58058612..e27897ef 100644 --- a/driver/remote/driver.go +++ b/driver/remote/driver.go @@ -87,9 +87,8 @@ func (d *Driver) Client(ctx context.Context) (*client.Client, error) { return client.New(ctx, d.InitConfig.EndpointAddr, opts...) } -func (d *Driver) Features() map[driver.Feature]bool { +func (d *Driver) Features(ctx context.Context) map[driver.Feature]bool { var historyAPI bool - ctx := context.Background() c, err := d.Client(ctx) if err == nil { historyAPI = driver.HistoryAPISupported(ctx, c)