mirror of
https://github.com/docker/buildx.git
synced 2024-11-22 15:37:16 +08:00
17d4369866
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
|
|
}
|