policy: separate sourcemetaresolver utility to reusable pkg
Turn the current utility used by policy helper commands that allows getting gateway.Client lazily into reusable package. This is preparation for using this utility also in the policy verification, outside of commands. Only expose SourceMetaResolver as other methods of gateway client are not needed atm by any callers. Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
+5
-16
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/docker/buildx/builder"
|
||||
"github.com/docker/buildx/policy"
|
||||
"github.com/docker/buildx/util/confutil"
|
||||
"github.com/docker/buildx/util/sourcemeta"
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/moby/buildkit/client/llb/sourceresolver"
|
||||
"github.com/moby/buildkit/frontend/dockerui"
|
||||
@@ -96,11 +97,8 @@ func runEval(ctx context.Context, dockerCli command.Cli, source string, opts eva
|
||||
OS: defaultPlatform.OS,
|
||||
Variant: defaultPlatform.Variant,
|
||||
}
|
||||
openClient, release, err := gatewayClientFactory(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer release()
|
||||
metaResolver := sourcemeta.NewResolver(c)
|
||||
defer metaResolver.Close()
|
||||
|
||||
platform := &pb.Platform{
|
||||
Architecture: p.Architecture,
|
||||
@@ -148,13 +146,8 @@ func runEval(ctx context.Context, dockerCli command.Cli, source string, opts eva
|
||||
if err := policy.AddUnknowns(req, toReload); err != nil {
|
||||
return err
|
||||
}
|
||||
gwClient, err := openClient(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
opt := sourceResolverOpt(req, &p)
|
||||
resp, err := gwClient.ResolveSourceMetadata(ctx, src, opt)
|
||||
resp, err := metaResolver.ResolveSourceMetadata(ctx, src, opt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -240,12 +233,8 @@ func runEval(ctx context.Context, dockerCli command.Cli, source string, opts eva
|
||||
return evalDecisionError(decision)
|
||||
}
|
||||
|
||||
gwClient, err := openClient(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
opt := sourceResolverOpt(next, &p)
|
||||
resp, err := gwClient.ResolveSourceMetadata(ctx, src, opt)
|
||||
resp, err := metaResolver.ResolveSourceMetadata(ctx, src, opt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
package policy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/moby/buildkit/client"
|
||||
gwclient "github.com/moby/buildkit/frontend/gateway/client"
|
||||
)
|
||||
|
||||
type gatewayClientOpener func(context.Context) (gwclient.Client, error)
|
||||
|
||||
func gatewayClientFactory(c *client.Client) (gatewayClientOpener, func() error, error) {
|
||||
var (
|
||||
once sync.Once
|
||||
releaseOnce sync.Once
|
||||
started atomic.Bool
|
||||
ready = make(chan gwclient.Client, 1)
|
||||
done = make(chan error, 1)
|
||||
openErr error
|
||||
releaseErr error
|
||||
gwClient gwclient.Client
|
||||
cancel context.CancelCauseFunc
|
||||
)
|
||||
|
||||
open := func(ctx context.Context) (gwclient.Client, error) {
|
||||
once.Do(func() {
|
||||
started.Store(true)
|
||||
buildCtx, cancelFn := context.WithCancelCause(ctx)
|
||||
cancel = cancelFn
|
||||
|
||||
go func() {
|
||||
_, err := c.Build(buildCtx, client.SolveOpt{Internal: true}, "buildx", func(ctx context.Context, c gwclient.Client) (*gwclient.Result, error) {
|
||||
ready <- c
|
||||
<-buildCtx.Done()
|
||||
return nil, context.Cause(buildCtx)
|
||||
}, nil)
|
||||
done <- err
|
||||
}()
|
||||
|
||||
select {
|
||||
case gwClient = <-ready:
|
||||
case err := <-done:
|
||||
if err == nil {
|
||||
err = errors.New("gateway build finished without a client")
|
||||
}
|
||||
openErr = err
|
||||
case <-ctx.Done():
|
||||
openErr = context.Cause(ctx)
|
||||
cancelFn(openErr)
|
||||
}
|
||||
})
|
||||
|
||||
if openErr != nil {
|
||||
return nil, openErr
|
||||
}
|
||||
return gwClient, nil
|
||||
}
|
||||
|
||||
release := func() error {
|
||||
releaseOnce.Do(func() {
|
||||
if !started.Load() {
|
||||
return
|
||||
}
|
||||
if cancel != nil {
|
||||
cancel(context.Canceled)
|
||||
}
|
||||
err := <-done
|
||||
if err == nil || errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
|
||||
return
|
||||
}
|
||||
releaseErr = err
|
||||
})
|
||||
return releaseErr
|
||||
}
|
||||
|
||||
return open, release, nil
|
||||
}
|
||||
+21
-31
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/docker/buildx/policy"
|
||||
"github.com/docker/buildx/util/cobrautil"
|
||||
"github.com/docker/buildx/util/confutil"
|
||||
"github.com/docker/buildx/util/sourcemeta"
|
||||
"github.com/docker/cli/cli/command"
|
||||
gwpb "github.com/moby/buildkit/frontend/gateway/pb"
|
||||
"github.com/moby/buildkit/solver/pb"
|
||||
@@ -30,9 +31,9 @@ func testCmd(dockerCli command.Cli, rootOpts RootOptions) *cobra.Command {
|
||||
Args: cobra.ExactArgs(1),
|
||||
DisableFlagsInUseLine: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
resolver := newPolicyTestResolver(dockerCli, rootOpts.Builder)
|
||||
opts.Resolver = resolver.Options()
|
||||
defer resolver.Close()
|
||||
optionsProvider := newPolicyTestOptionsProvider(dockerCli, rootOpts.Builder)
|
||||
opts.Provider = optionsProvider.TestOptionsProvider()
|
||||
defer optionsProvider.Close()
|
||||
return runTest(cmd.Context(), cmd.OutOrStdout(), args[0], opts)
|
||||
},
|
||||
}
|
||||
@@ -114,63 +115,58 @@ func withInputPrefix(keys []string) []string {
|
||||
return out
|
||||
}
|
||||
|
||||
type policyTestResolver struct {
|
||||
type policyTestOptionsProvider struct {
|
||||
dockerCli command.Cli
|
||||
builderName *string
|
||||
|
||||
once sync.Once
|
||||
platform *ocispecs.Platform
|
||||
openClient gatewayClientOpener
|
||||
release func() error
|
||||
err error
|
||||
once sync.Once
|
||||
platform *ocispecs.Platform
|
||||
metaResolver *sourcemeta.Resolver
|
||||
err error
|
||||
}
|
||||
|
||||
func newPolicyTestResolver(dockerCli command.Cli, builderName *string) *policyTestResolver {
|
||||
return &policyTestResolver{
|
||||
func newPolicyTestOptionsProvider(dockerCli command.Cli, builderName *string) *policyTestOptionsProvider {
|
||||
return &policyTestOptionsProvider{
|
||||
dockerCli: dockerCli,
|
||||
builderName: builderName,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *policyTestResolver) Options() *policy.TestResolver {
|
||||
return &policy.TestResolver{
|
||||
func (r *policyTestOptionsProvider) TestOptionsProvider() *policy.TestOptionsProvider {
|
||||
return &policy.TestOptionsProvider{
|
||||
Resolve: r.Resolve,
|
||||
Platform: r.Platform,
|
||||
VerifierProvider: policy.SignatureVerifier(confutil.NewConfig(r.dockerCli)),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *policyTestResolver) Close() error {
|
||||
if r.release == nil {
|
||||
func (r *policyTestOptionsProvider) Close() error {
|
||||
if r.metaResolver == nil {
|
||||
return nil
|
||||
}
|
||||
return r.release()
|
||||
return r.metaResolver.Close()
|
||||
}
|
||||
|
||||
func (r *policyTestResolver) Platform(ctx context.Context) (*ocispecs.Platform, error) {
|
||||
func (r *policyTestOptionsProvider) Platform(ctx context.Context) (*ocispecs.Platform, error) {
|
||||
if err := r.init(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r.platform, nil
|
||||
}
|
||||
|
||||
func (r *policyTestResolver) Resolve(ctx context.Context, source *pb.SourceOp, req *gwpb.ResolveSourceMetaRequest) (*gwpb.ResolveSourceMetaResponse, error) {
|
||||
func (r *policyTestOptionsProvider) Resolve(ctx context.Context, source *pb.SourceOp, req *gwpb.ResolveSourceMetaRequest) (*gwpb.ResolveSourceMetaResponse, error) {
|
||||
if err := r.init(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gwClient, err := r.openClient(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opt := sourceResolverOpt(req, r.platform)
|
||||
resp, err := gwClient.ResolveSourceMetadata(ctx, source, opt)
|
||||
resp, err := r.metaResolver.ResolveSourceMetadata(ctx, source, opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buildSourceMetaResponse(resp), nil
|
||||
}
|
||||
|
||||
func (r *policyTestResolver) init(ctx context.Context) error {
|
||||
func (r *policyTestOptionsProvider) init(ctx context.Context) error {
|
||||
r.once.Do(func() {
|
||||
bopts := []builder.Option{}
|
||||
if r.builderName != nil {
|
||||
@@ -208,13 +204,7 @@ func (r *policyTestResolver) init(ctx context.Context) error {
|
||||
OS: defaultPlatform.OS,
|
||||
Variant: defaultPlatform.Variant,
|
||||
}
|
||||
openClient, release, err := gatewayClientFactory(c)
|
||||
if err != nil {
|
||||
r.err = err
|
||||
return
|
||||
}
|
||||
r.openClient = openClient
|
||||
r.release = release
|
||||
r.metaResolver = sourcemeta.NewResolver(c)
|
||||
})
|
||||
return r.err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user