mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-04 01:53:42 +08:00 
			
		
		
		
	Previously, the help information for buildx indicated that users could create a new instance of the docker driver - which is explicitly something we don't support, driver of this form are automatically derived from the available list of docker contexts. This patch ensures that don't have AllowsInstance set will not appear in the help text, and additionally provide a new more specific error message instead of the generic "failed to find driver". This should help point users in the correct direction. Signed-off-by: Justin Chadwell <me@jedevc.com>
		
			
				
	
	
		
			161 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			161 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package driver
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"os"
 | 
						|
	"sort"
 | 
						|
	"strings"
 | 
						|
	"sync"
 | 
						|
 | 
						|
	"k8s.io/client-go/rest"
 | 
						|
 | 
						|
	dockerclient "github.com/docker/docker/client"
 | 
						|
	"github.com/moby/buildkit/client"
 | 
						|
	specs "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						|
	"github.com/pkg/errors"
 | 
						|
)
 | 
						|
 | 
						|
type Factory interface {
 | 
						|
	Name() string
 | 
						|
	Usage() string
 | 
						|
	Priority(ctx context.Context, endpoint string, api dockerclient.APIClient) int
 | 
						|
	New(ctx context.Context, cfg InitConfig) (Driver, error)
 | 
						|
	AllowsInstances() bool
 | 
						|
}
 | 
						|
 | 
						|
type BuildkitConfig struct {
 | 
						|
	// Entitlements []string
 | 
						|
	// Rootless bool
 | 
						|
}
 | 
						|
 | 
						|
type KubeClientConfig interface {
 | 
						|
	ClientConfig() (*rest.Config, error)
 | 
						|
	Namespace() (string, bool, error)
 | 
						|
}
 | 
						|
 | 
						|
type KubeClientConfigInCluster struct{}
 | 
						|
 | 
						|
func (k KubeClientConfigInCluster) ClientConfig() (*rest.Config, error) {
 | 
						|
	return rest.InClusterConfig()
 | 
						|
}
 | 
						|
 | 
						|
func (k KubeClientConfigInCluster) Namespace() (string, bool, error) {
 | 
						|
	namespace, err := os.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace")
 | 
						|
	if err != nil {
 | 
						|
		return "", false, err
 | 
						|
	}
 | 
						|
	return strings.TrimSpace(string(namespace)), true, nil
 | 
						|
}
 | 
						|
 | 
						|
type InitConfig struct {
 | 
						|
	// This object needs updates to be generic for different drivers
 | 
						|
	Name             string
 | 
						|
	EndpointAddr     string
 | 
						|
	DockerAPI        dockerclient.APIClient
 | 
						|
	KubeClientConfig KubeClientConfig
 | 
						|
	BuildkitFlags    []string
 | 
						|
	Files            map[string][]byte
 | 
						|
	DriverOpts       map[string]string
 | 
						|
	Auth             Auth
 | 
						|
	Platforms        []specs.Platform
 | 
						|
	// ContextPathHash can be used for determining pods in the driver instance
 | 
						|
	ContextPathHash string
 | 
						|
}
 | 
						|
 | 
						|
var drivers map[string]Factory
 | 
						|
 | 
						|
func Register(f Factory) {
 | 
						|
	if drivers == nil {
 | 
						|
		drivers = map[string]Factory{}
 | 
						|
	}
 | 
						|
	drivers[f.Name()] = f
 | 
						|
}
 | 
						|
 | 
						|
func GetDefaultFactory(ctx context.Context, ep string, c dockerclient.APIClient, instanceRequired bool) (Factory, error) {
 | 
						|
	if len(drivers) == 0 {
 | 
						|
		return nil, errors.Errorf("no drivers available")
 | 
						|
	}
 | 
						|
	type p struct {
 | 
						|
		f        Factory
 | 
						|
		priority int
 | 
						|
	}
 | 
						|
	dd := make([]p, 0, len(drivers))
 | 
						|
	for _, f := range drivers {
 | 
						|
		if instanceRequired && !f.AllowsInstances() {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		dd = append(dd, p{f: f, priority: f.Priority(ctx, ep, c)})
 | 
						|
	}
 | 
						|
	sort.Slice(dd, func(i, j int) bool {
 | 
						|
		return dd[i].priority < dd[j].priority
 | 
						|
	})
 | 
						|
	return dd[0].f, nil
 | 
						|
}
 | 
						|
 | 
						|
func GetFactory(name string, instanceRequired bool) (Factory, error) {
 | 
						|
	for _, f := range drivers {
 | 
						|
		if f.Name() == name {
 | 
						|
			if instanceRequired && !f.AllowsInstances() {
 | 
						|
				return nil, errors.Errorf("additional instances of driver %q cannot be created", name)
 | 
						|
			}
 | 
						|
			return f, nil
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return nil, errors.Errorf("failed to find driver %q", name)
 | 
						|
}
 | 
						|
 | 
						|
func GetDriver(ctx context.Context, name string, f Factory, endpointAddr string, api dockerclient.APIClient, auth Auth, kcc KubeClientConfig, flags []string, files map[string][]byte, do map[string]string, platforms []specs.Platform, contextPathHash string) (Driver, error) {
 | 
						|
	ic := InitConfig{
 | 
						|
		EndpointAddr:     endpointAddr,
 | 
						|
		DockerAPI:        api,
 | 
						|
		KubeClientConfig: kcc,
 | 
						|
		Name:             name,
 | 
						|
		BuildkitFlags:    flags,
 | 
						|
		DriverOpts:       do,
 | 
						|
		Auth:             auth,
 | 
						|
		Platforms:        platforms,
 | 
						|
		ContextPathHash:  contextPathHash,
 | 
						|
		Files:            files,
 | 
						|
	}
 | 
						|
	if f == nil {
 | 
						|
		var err error
 | 
						|
		f, err = GetDefaultFactory(ctx, endpointAddr, api, false)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	d, err := f.New(ctx, ic)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	return &cachedDriver{Driver: d}, nil
 | 
						|
}
 | 
						|
 | 
						|
func GetFactories(instanceRequired bool) []Factory {
 | 
						|
	ds := make([]Factory, 0, len(drivers))
 | 
						|
	for _, d := range drivers {
 | 
						|
		if instanceRequired && !d.AllowsInstances() {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		ds = append(ds, d)
 | 
						|
	}
 | 
						|
	sort.Slice(ds, func(i, j int) bool {
 | 
						|
		return ds[i].Name() < ds[j].Name()
 | 
						|
	})
 | 
						|
	return ds
 | 
						|
}
 | 
						|
 | 
						|
type cachedDriver struct {
 | 
						|
	Driver
 | 
						|
	client *client.Client
 | 
						|
	err    error
 | 
						|
	once   sync.Once
 | 
						|
}
 | 
						|
 | 
						|
func (d *cachedDriver) Client(ctx context.Context) (*client.Client, error) {
 | 
						|
	d.once.Do(func() {
 | 
						|
		d.client, d.err = d.Driver.Client(ctx)
 | 
						|
	})
 | 
						|
	return d.client, d.err
 | 
						|
}
 |