vendor: update buildkit to v0.8

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
Tonis Tiigi
2020-12-07 22:01:24 -08:00
parent 080e9981c7
commit 69a1419ab1
323 changed files with 20129 additions and 8394 deletions

View File

@ -45,11 +45,14 @@ func (c *Client) Build(ctx context.Context, opt SolveOpt, product string, buildF
}
cb := func(ref string, s *session.Session) error {
g, err := grpcclient.New(ctx, feOpts, s.ID(), product, c.gatewayClientForBuild(ref), gworkers)
gwClient := c.gatewayClientForBuild(ref)
g, err := grpcclient.New(ctx, feOpts, s.ID(), product, gwClient, gworkers)
if err != nil {
return err
}
gwClient.caps = g.BuildOpts().Caps
if err := g.Run(ctx, buildFunc); err != nil {
return errors.Wrap(err, "failed to run Build function")
}
@ -59,14 +62,18 @@ func (c *Client) Build(ctx context.Context, opt SolveOpt, product string, buildF
return c.solve(ctx, nil, cb, opt, statusChan)
}
func (c *Client) gatewayClientForBuild(buildid string) gatewayapi.LLBBridgeClient {
func (c *Client) gatewayClientForBuild(buildid string) *gatewayClientForBuild {
g := gatewayapi.NewLLBBridgeClient(c.conn)
return &gatewayClientForBuild{g, buildid}
return &gatewayClientForBuild{
gateway: g,
buildID: buildid,
}
}
type gatewayClientForBuild struct {
gateway gatewayapi.LLBBridgeClient
buildID string
caps apicaps.CapSet
}
func (g *gatewayClientForBuild) ResolveImageConfig(ctx context.Context, in *gatewayapi.ResolveImageConfigRequest, opts ...grpc.CallOption) (*gatewayapi.ResolveImageConfigResponse, error) {
@ -85,11 +92,17 @@ func (g *gatewayClientForBuild) ReadFile(ctx context.Context, in *gatewayapi.Rea
}
func (g *gatewayClientForBuild) ReadDir(ctx context.Context, in *gatewayapi.ReadDirRequest, opts ...grpc.CallOption) (*gatewayapi.ReadDirResponse, error) {
if err := g.caps.Supports(gatewayapi.CapReadDir); err != nil {
return nil, err
}
ctx = buildid.AppendToOutgoingContext(ctx, g.buildID)
return g.gateway.ReadDir(ctx, in, opts...)
}
func (g *gatewayClientForBuild) StatFile(ctx context.Context, in *gatewayapi.StatFileRequest, opts ...grpc.CallOption) (*gatewayapi.StatFileResponse, error) {
if err := g.caps.Supports(gatewayapi.CapStatFile); err != nil {
return nil, err
}
ctx = buildid.AppendToOutgoingContext(ctx, g.buildID)
return g.gateway.StatFile(ctx, in, opts...)
}
@ -105,6 +118,33 @@ func (g *gatewayClientForBuild) Return(ctx context.Context, in *gatewayapi.Retur
}
func (g *gatewayClientForBuild) Inputs(ctx context.Context, in *gatewayapi.InputsRequest, opts ...grpc.CallOption) (*gatewayapi.InputsResponse, error) {
if err := g.caps.Supports(gatewayapi.CapFrontendInputs); err != nil {
return nil, err
}
ctx = buildid.AppendToOutgoingContext(ctx, g.buildID)
return g.gateway.Inputs(ctx, in, opts...)
}
func (g *gatewayClientForBuild) NewContainer(ctx context.Context, in *gatewayapi.NewContainerRequest, opts ...grpc.CallOption) (*gatewayapi.NewContainerResponse, error) {
if err := g.caps.Supports(gatewayapi.CapGatewayExec); err != nil {
return nil, err
}
ctx = buildid.AppendToOutgoingContext(ctx, g.buildID)
return g.gateway.NewContainer(ctx, in, opts...)
}
func (g *gatewayClientForBuild) ReleaseContainer(ctx context.Context, in *gatewayapi.ReleaseContainerRequest, opts ...grpc.CallOption) (*gatewayapi.ReleaseContainerResponse, error) {
if err := g.caps.Supports(gatewayapi.CapGatewayExec); err != nil {
return nil, err
}
ctx = buildid.AppendToOutgoingContext(ctx, g.buildID)
return g.gateway.ReleaseContainer(ctx, in, opts...)
}
func (g *gatewayClientForBuild) ExecProcess(ctx context.Context, opts ...grpc.CallOption) (gatewayapi.LLBBridge_ExecProcessClient, error) {
if err := g.caps.Supports(gatewayapi.CapGatewayExec); err != nil {
return nil, err
}
ctx = buildid.AppendToOutgoingContext(ctx, g.buildID)
return g.gateway.ExecProcess(ctx, opts...)
}

View File

@ -8,6 +8,7 @@ import (
"net"
"net/url"
"github.com/containerd/containerd/defaults"
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
"github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc"
controlapi "github.com/moby/buildkit/api/services/control"
@ -30,7 +31,10 @@ type ClientOpt interface{}
// New returns a new buildkit client. Address can be empty for the system-default address.
func New(ctx context.Context, address string, opts ...ClientOpt) (*Client, error) {
gopts := []grpc.DialOption{}
gopts := []grpc.DialOption{
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(defaults.DefaultMaxRecvMsgSize)),
grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(defaults.DefaultMaxSendMsgSize)),
}
needDialer := true
needWithInsecure := true

View File

@ -153,7 +153,13 @@ func (e *ExecOp) Marshal(ctx context.Context, c *Constraints) (digest.Digest, []
}
if c.Caps != nil {
if err := c.Caps.Supports(pb.CapExecMetaSetsDefaultPath); err != nil {
env = env.SetDefault("PATH", system.DefaultPathEnv)
os := "linux"
if c.Platform != nil {
os = c.Platform.OS
} else if e.constraints.Platform != nil {
os = e.constraints.Platform.OS
}
env = env.SetDefault("PATH", system.DefaultPathEnv(os))
} else {
addCap(&e.constraints, pb.CapExecMetaSetsDefaultPath)
}
@ -174,11 +180,17 @@ func (e *ExecOp) Marshal(ctx context.Context, c *Constraints) (digest.Digest, []
return "", nil, nil, nil, err
}
hostname, err := getHostname(e.base)(ctx)
if err != nil {
return "", nil, nil, nil, err
}
meta := &pb.Meta{
Args: args,
Env: env.ToArray(),
Cwd: cwd,
User: user,
Args: args,
Env: env.ToArray(),
Cwd: cwd,
User: user,
Hostname: hostname,
}
extraHosts, err := getExtraHosts(e.base)(ctx)
if err != nil {

View File

@ -19,6 +19,7 @@ var (
keyDir = contextKeyT("llb.exec.dir")
keyEnv = contextKeyT("llb.exec.env")
keyUser = contextKeyT("llb.exec.user")
keyHostname = contextKeyT("llb.exec.hostname")
keyExtraHost = contextKeyT("llb.exec.extrahost")
keyPlatform = contextKeyT("llb.platform")
keyNetwork = contextKeyT("llb.network")
@ -143,6 +144,25 @@ func getUser(s State) func(context.Context) (string, error) {
}
}
func Hostname(str string) StateOption {
return func(s State) State {
return s.WithValue(keyHostname, str)
}
}
func getHostname(s State) func(context.Context) (string, error) {
return func(ctx context.Context) (string, error) {
v, err := s.getValue(keyHostname)(ctx)
if err != nil {
return "", err
}
if v != nil {
return v.(string), nil
}
return "", nil
}
}
func args(args ...string) StateOption {
return func(s State) State {
return s.WithValue(keyArgs, args)

View File

@ -5,12 +5,14 @@ import (
_ "crypto/sha256" // for opencontainers/go-digest
"encoding/json"
"os"
"regexp"
"strconv"
"strings"
"github.com/docker/distribution/reference"
"github.com/moby/buildkit/solver/pb"
"github.com/moby/buildkit/util/apicaps"
"github.com/moby/buildkit/util/sshutil"
digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors"
)
@ -197,15 +199,59 @@ type ImageInfo struct {
RecordType string
}
func Git(remote, ref string, opts ...GitOption) State {
url := ""
const (
gitProtocolHTTP = iota + 1
gitProtocolHTTPS
gitProtocolSSH
gitProtocolGit
gitProtocolUnknown
)
for _, prefix := range []string{
"http://", "https://", "git://", "git@",
} {
var gitSSHRegex = regexp.MustCompile("^([a-z0-9]+@)?[^:]+:.*$")
func getGitProtocol(remote string) (string, int) {
prefixes := map[string]int{
"http://": gitProtocolHTTP,
"https://": gitProtocolHTTPS,
"git://": gitProtocolGit,
"ssh://": gitProtocolSSH,
}
protocolType := gitProtocolUnknown
for prefix, potentialType := range prefixes {
if strings.HasPrefix(remote, prefix) {
url = strings.Split(remote, "#")[0]
remote = strings.TrimPrefix(remote, prefix)
protocolType = potentialType
}
}
if protocolType == gitProtocolUnknown && gitSSHRegex.MatchString(remote) {
protocolType = gitProtocolSSH
}
// remove name from ssh
if protocolType == gitProtocolSSH {
parts := strings.SplitN(remote, "@", 2)
if len(parts) == 2 {
remote = parts[1]
}
}
return remote, protocolType
}
func Git(remote, ref string, opts ...GitOption) State {
url := strings.Split(remote, "#")[0]
var protocolType int
remote, protocolType = getGitProtocol(remote)
var sshHost string
if protocolType == gitProtocolSSH {
parts := strings.SplitN(remote, ":", 2)
if len(parts) == 2 {
sshHost = parts[0]
// keep remote consistent with http(s) version
remote = parts[0] + "/" + parts[1]
}
}
@ -243,6 +289,25 @@ func Git(remote, ref string, opts ...GitOption) State {
addCap(&gi.Constraints, pb.CapSourceGitHTTPAuth)
}
}
if protocolType == gitProtocolSSH {
if gi.KnownSSHHosts != "" {
attrs[pb.AttrKnownSSHHosts] = gi.KnownSSHHosts
} else if sshHost != "" {
keyscan, err := sshutil.SSHKeyScan(sshHost)
if err == nil {
// best effort
attrs[pb.AttrKnownSSHHosts] = keyscan
}
}
addCap(&gi.Constraints, pb.CapSourceGitKnownSSHHosts)
if gi.MountSSHSock == "" {
attrs[pb.AttrMountSSHSock] = "default"
} else {
attrs[pb.AttrMountSSHSock] = gi.MountSSHSock
}
addCap(&gi.Constraints, pb.CapSourceGitMountSSHSock)
}
addCap(&gi.Constraints, pb.CapSourceGit)
@ -265,6 +330,8 @@ type GitInfo struct {
AuthTokenSecret string
AuthHeaderSecret string
addAuthCap bool
KnownSSHHosts string
MountSSHSock string
}
func KeepGitDir() GitOption {
@ -287,6 +354,19 @@ func AuthHeaderSecret(v string) GitOption {
})
}
func KnownSSHHosts(key string) GitOption {
key = strings.TrimSuffix(key, "\n")
return gitOptionFunc(func(gi *GitInfo) {
gi.KnownSSHHosts = gi.KnownSSHHosts + key + "\n"
})
}
func MountSSHSock(sshID string) GitOption {
return gitOptionFunc(func(gi *GitInfo) {
gi.MountSSHSock = sshID
})
}
func Scratch() State {
return NewState(nil)
}

View File

@ -320,6 +320,14 @@ func (s State) User(v string) State {
return User(v)(s)
}
func (s State) Hostname(v string) State {
return Hostname(v)(s)
}
func (s State) GetHostname(ctx context.Context) (string, error) {
return getHostname(s)(ctx)
}
func (s State) Platform(p specs.Platform) State {
return platform(p)(s)
}

View File

@ -2,6 +2,7 @@ package client
import (
"context"
"io"
"github.com/moby/buildkit/client/llb"
"github.com/moby/buildkit/solver/pb"
@ -16,6 +17,64 @@ type Client interface {
ResolveImageConfig(ctx context.Context, ref string, opt llb.ResolveImageConfigOpt) (digest.Digest, []byte, error)
BuildOpts() BuildOpts
Inputs(ctx context.Context) (map[string]llb.State, error)
NewContainer(ctx context.Context, req NewContainerRequest) (Container, error)
}
// NewContainerRequest encapsulates the requirements for a client to define a
// new container, without defining the initial process.
type NewContainerRequest struct {
Mounts []Mount
NetMode pb.NetMode
Platform *pb.Platform
Constraints *pb.WorkerConstraints
}
// Mount allows clients to specify a filesystem mount. A Reference to a
// previously solved Result is required.
type Mount struct {
Selector string
Dest string
ResultID string
Ref Reference
Readonly bool
MountType pb.MountType
CacheOpt *pb.CacheOpt
SecretOpt *pb.SecretOpt
SSHOpt *pb.SSHOpt
}
// Container is used to start new processes inside a container and release the
// container resources when done.
type Container interface {
Start(context.Context, StartRequest) (ContainerProcess, error)
Release(context.Context) error
}
// StartRequest encapsulates the arguments to define a process within a
// container.
type StartRequest struct {
Args []string
Env []string
User string
Cwd string
Tty bool
Stdin io.ReadCloser
Stdout, Stderr io.WriteCloser
SecurityMode pb.SecurityMode
}
// WinSize is same as executor.WinSize, copied here to prevent circular package
// dependencies.
type WinSize struct {
Rows uint32
Cols uint32
}
// ContainerProcess represents a process within a container.
type ContainerProcess interface {
Wait() error
Resize(ctx context.Context, size WinSize) error
// TODO Signal(ctx context.Context, sig os.Signal)
}
type Reference interface {
@ -46,6 +105,7 @@ type StatRequest struct {
// SolveRequest is same as frontend.SolveRequest but avoiding dependency
type SolveRequest struct {
Evaluate bool
Definition *pb.Definition
Frontend string
FrontendOpt map[string]string

View File

@ -3,10 +3,12 @@ package grpcclient
import (
"context"
"encoding/json"
"fmt"
"io"
"net"
"os"
"strings"
"sync"
"time"
"github.com/gogo/googleapis/google/rpc"
@ -15,26 +17,33 @@ import (
"github.com/moby/buildkit/client/llb"
"github.com/moby/buildkit/frontend/gateway/client"
pb "github.com/moby/buildkit/frontend/gateway/pb"
"github.com/moby/buildkit/identity"
"github.com/moby/buildkit/solver/errdefs"
opspb "github.com/moby/buildkit/solver/pb"
"github.com/moby/buildkit/util/apicaps"
"github.com/moby/buildkit/util/grpcerrors"
digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
fstypes "github.com/tonistiigi/fsutil/types"
"golang.org/x/sync/errgroup"
spb "google.golang.org/genproto/googleapis/rpc/status"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
const frontendPrefix = "BUILDKIT_FRONTEND_OPT_"
type GrpcClient interface {
client.Client
Run(context.Context, client.BuildFunc) error
}
func New(ctx context.Context, opts map[string]string, session, product string, c pb.LLBBridgeClient, w []client.WorkerInfo) (GrpcClient, error) {
ctx, cancel := context.WithTimeout(ctx, 15*time.Second)
defer cancel()
resp, err := c.Ping(ctx, &pb.PingRequest{})
pingCtx, pingCancel := context.WithTimeout(ctx, 15*time.Second)
defer pingCancel()
resp, err := c.Ping(pingCtx, &pb.PingRequest{})
if err != nil {
return nil, err
}
@ -56,6 +65,7 @@ func New(ctx context.Context, opts map[string]string, session, product string, c
caps: pb.Caps.CapSet(resp.FrontendAPICaps),
llbCaps: opspb.Caps.CapSet(resp.LLBCaps),
requests: map[string]*pb.SolveRequest{},
execMsgs: newMessageForwarder(ctx, c),
}, nil
}
@ -167,6 +177,13 @@ func (c *grpcClient) Run(ctx context.Context, f client.BuildFunc) (retError erro
}()
}
defer func() {
err = c.execMsgs.Release()
if err != nil && retError != nil {
retError = err
}
}()
if res, err = f(ctx, c); err != nil {
return err
}
@ -257,6 +274,7 @@ type grpcClient struct {
caps apicaps.CapSet
llbCaps apicaps.CapSet
requests map[string]*pb.SolveRequest
execMsgs *messageForwarder
}
func (c *grpcClient) requestForRef(ref client.Reference) (*pb.SolveRequest, error) {
@ -280,7 +298,7 @@ func (c *grpcClient) requestForRef(ref client.Reference) (*pb.SolveRequest, erro
return req, nil
}
func (c *grpcClient) Solve(ctx context.Context, creq client.SolveRequest) (*client.Result, error) {
func (c *grpcClient) Solve(ctx context.Context, creq client.SolveRequest) (res *client.Result, err error) {
if creq.Definition != nil {
for _, md := range creq.Definition.Metadata {
for cap := range md.Caps {
@ -326,13 +344,45 @@ func (c *grpcClient) Solve(ctx context.Context, creq client.SolveRequest) (*clie
req.ExporterAttr = []byte("{}")
}
if creq.Evaluate {
if c.caps.Supports(pb.CapGatewayEvaluateSolve) == nil {
req.Evaluate = creq.Evaluate
} else {
// If evaluate is not supported, fallback to running Stat(".") in order to
// trigger an evaluation of the result.
defer func() {
if res == nil {
return
}
var (
id string
ref client.Reference
)
ref, err = res.SingleRef()
if err != nil {
for refID := range res.Refs {
id = refID
break
}
} else {
id = ref.(*reference).id
}
_, err = c.client.StatFile(ctx, &pb.StatFileRequest{
Ref: id,
Path: ".",
})
}()
}
}
resp, err := c.client.Solve(ctx, req)
if err != nil {
return nil, err
}
res := &client.Result{}
res = &client.Result{}
if resp.Result == nil {
if id := resp.Ref; id != "" {
c.requests[id] = req
@ -427,7 +477,454 @@ func (c *grpcClient) Inputs(ctx context.Context) (map[string]llb.State, error) {
inputs[key] = llb.NewState(op)
}
return inputs, nil
}
// procMessageForwarder is created per container process to act as the
// communication channel between the process and the ExecProcess message
// stream.
type procMessageForwarder struct {
done chan struct{}
closeOnce sync.Once
msgs chan *pb.ExecMessage
}
func newProcMessageForwarder() *procMessageForwarder {
return &procMessageForwarder{
done: make(chan struct{}),
msgs: make(chan *pb.ExecMessage),
}
}
func (b *procMessageForwarder) Send(ctx context.Context, m *pb.ExecMessage) {
select {
case <-ctx.Done():
case <-b.done:
b.closeOnce.Do(func() {
close(b.msgs)
})
case b.msgs <- m:
}
}
func (b *procMessageForwarder) Recv(ctx context.Context) (m *pb.ExecMessage, ok bool) {
select {
case <-ctx.Done():
return nil, true
case <-b.done:
return nil, false
case m = <-b.msgs:
return m, true
}
}
func (b *procMessageForwarder) Close() {
close(b.done)
b.Recv(context.Background()) // flush any messages in queue
b.Send(context.Background(), nil) // ensure channel is closed
}
// messageForwarder manages a single grpc stream for ExecProcess to facilitate
// a pub/sub message channel for each new process started from the client
// connection.
type messageForwarder struct {
client pb.LLBBridgeClient
ctx context.Context
cancel func()
eg *errgroup.Group
mu sync.Mutex
pids map[string]*procMessageForwarder
stream pb.LLBBridge_ExecProcessClient
// startOnce used to only start the exec message forwarder once,
// so we only have one exec stream per client
startOnce sync.Once
// startErr tracks the error when initializing the stream, it will
// be returned on subsequent calls to Start
startErr error
}
func newMessageForwarder(ctx context.Context, client pb.LLBBridgeClient) *messageForwarder {
ctx, cancel := context.WithCancel(ctx)
eg, ctx := errgroup.WithContext(ctx)
return &messageForwarder{
client: client,
pids: map[string]*procMessageForwarder{},
ctx: ctx,
cancel: cancel,
eg: eg,
}
}
func (m *messageForwarder) Start() (err error) {
defer func() {
if err != nil {
m.startErr = err
}
}()
if m.startErr != nil {
return m.startErr
}
m.startOnce.Do(func() {
m.stream, err = m.client.ExecProcess(m.ctx)
if err != nil {
return
}
m.eg.Go(func() error {
for {
msg, err := m.stream.Recv()
if errors.Is(err, io.EOF) || grpcerrors.Code(err) == codes.Canceled {
return nil
}
logrus.Debugf("|<--- %s", debugMessage(msg))
if err != nil {
return err
}
m.mu.Lock()
msgs, ok := m.pids[msg.ProcessID]
m.mu.Unlock()
if !ok {
logrus.Debugf("Received exec message for unregistered process: %s", msg.String())
continue
}
msgs.Send(m.ctx, msg)
}
})
})
return err
}
func debugMessage(msg *pb.ExecMessage) string {
switch m := msg.GetInput().(type) {
case *pb.ExecMessage_Init:
return fmt.Sprintf("Init Message %s", msg.ProcessID)
case *pb.ExecMessage_File:
if m.File.EOF {
return fmt.Sprintf("File Message %s, fd=%d, EOF", msg.ProcessID, m.File.Fd)
}
return fmt.Sprintf("File Message %s, fd=%d, %d bytes", msg.ProcessID, m.File.Fd, len(m.File.Data))
case *pb.ExecMessage_Resize:
return fmt.Sprintf("Resize Message %s", msg.ProcessID)
case *pb.ExecMessage_Started:
return fmt.Sprintf("Started Message %s", msg.ProcessID)
case *pb.ExecMessage_Exit:
return fmt.Sprintf("Exit Message %s, code=%d, err=%s", msg.ProcessID, m.Exit.Code, m.Exit.Error)
case *pb.ExecMessage_Done:
return fmt.Sprintf("Done Message %s", msg.ProcessID)
}
return fmt.Sprintf("Unknown Message %s", msg.String())
}
func (m *messageForwarder) Send(msg *pb.ExecMessage) error {
m.mu.Lock()
_, ok := m.pids[msg.ProcessID]
defer m.mu.Unlock()
if !ok {
return errors.Errorf("process %s has ended, not sending message %#v", msg.ProcessID, msg.Input)
}
logrus.Debugf("|---> %s", debugMessage(msg))
return m.stream.Send(msg)
}
func (m *messageForwarder) Release() error {
m.cancel()
return m.eg.Wait()
}
func (m *messageForwarder) Register(pid string) *procMessageForwarder {
m.mu.Lock()
defer m.mu.Unlock()
sender := newProcMessageForwarder()
m.pids[pid] = sender
return sender
}
func (m *messageForwarder) Deregister(pid string) {
m.mu.Lock()
defer m.mu.Unlock()
sender, ok := m.pids[pid]
if !ok {
return
}
delete(m.pids, pid)
sender.Close()
}
type msgWriter struct {
mux *messageForwarder
fd uint32
processID string
}
func (w *msgWriter) Write(msg []byte) (int, error) {
err := w.mux.Send(&pb.ExecMessage{
ProcessID: w.processID,
Input: &pb.ExecMessage_File{
File: &pb.FdMessage{
Fd: w.fd,
Data: msg,
},
},
})
if err != nil {
return 0, err
}
return len(msg), nil
}
func (c *grpcClient) NewContainer(ctx context.Context, req client.NewContainerRequest) (client.Container, error) {
err := c.caps.Supports(pb.CapGatewayExec)
if err != nil {
return nil, err
}
id := identity.NewID()
var mounts []*opspb.Mount
for _, m := range req.Mounts {
resultID := m.ResultID
if m.Ref != nil {
ref, ok := m.Ref.(*reference)
if !ok {
return nil, errors.Errorf("unexpected type for reference, got %T", m.Ref)
}
resultID = ref.id
}
mounts = append(mounts, &opspb.Mount{
Dest: m.Dest,
Selector: m.Selector,
Readonly: m.Readonly,
MountType: m.MountType,
ResultID: resultID,
CacheOpt: m.CacheOpt,
SecretOpt: m.SecretOpt,
SSHOpt: m.SSHOpt,
})
}
logrus.Debugf("|---> NewContainer %s", id)
_, err = c.client.NewContainer(ctx, &pb.NewContainerRequest{
ContainerID: id,
Mounts: mounts,
Platform: req.Platform,
Constraints: req.Constraints,
})
if err != nil {
return nil, err
}
// ensure message forwarder is started, only sets up stream first time called
err = c.execMsgs.Start()
if err != nil {
return nil, err
}
return &container{
client: c.client,
id: id,
execMsgs: c.execMsgs,
}, nil
}
type container struct {
client pb.LLBBridgeClient
id string
execMsgs *messageForwarder
}
func (ctr *container) Start(ctx context.Context, req client.StartRequest) (client.ContainerProcess, error) {
pid := fmt.Sprintf("%s:%s", ctr.id, identity.NewID())
msgs := ctr.execMsgs.Register(pid)
init := &pb.InitMessage{
ContainerID: ctr.id,
Meta: &opspb.Meta{
Args: req.Args,
Env: req.Env,
Cwd: req.Cwd,
User: req.User,
},
Tty: req.Tty,
Security: req.SecurityMode,
}
if req.Stdin != nil {
init.Fds = append(init.Fds, 0)
}
if req.Stdout != nil {
init.Fds = append(init.Fds, 1)
}
if req.Stderr != nil {
init.Fds = append(init.Fds, 2)
}
err := ctr.execMsgs.Send(&pb.ExecMessage{
ProcessID: pid,
Input: &pb.ExecMessage_Init{
Init: init,
},
})
if err != nil {
return nil, err
}
msg, _ := msgs.Recv(ctx)
if msg == nil {
return nil, errors.Errorf("failed to receive started message")
}
started := msg.GetStarted()
if started == nil {
return nil, errors.Errorf("expecting started message, got %T", msg.GetInput())
}
eg, ctx := errgroup.WithContext(ctx)
done := make(chan struct{})
ctrProc := &containerProcess{
execMsgs: ctr.execMsgs,
id: pid,
eg: eg,
}
var stdinReader *io.PipeReader
ctrProc.eg.Go(func() error {
<-done
if stdinReader != nil {
return stdinReader.Close()
}
return nil
})
if req.Stdin != nil {
var stdinWriter io.WriteCloser
stdinReader, stdinWriter = io.Pipe()
// This go routine is intentionally not part of the errgroup because
// if os.Stdin is used for req.Stdin then this will block until
// the user closes the input, which will likely be after we are done
// with the container, so we can't Wait on it.
go func() {
io.Copy(stdinWriter, req.Stdin)
stdinWriter.Close()
}()
ctrProc.eg.Go(func() error {
m := &msgWriter{
mux: ctr.execMsgs,
processID: pid,
fd: 0,
}
_, err := io.Copy(m, stdinReader)
// ignore ErrClosedPipe, it is EOF for our usage.
if err != nil && !errors.Is(err, io.ErrClosedPipe) {
return err
}
// not an error so must be eof
return ctr.execMsgs.Send(&pb.ExecMessage{
ProcessID: pid,
Input: &pb.ExecMessage_File{
File: &pb.FdMessage{
Fd: 0,
EOF: true,
},
},
})
})
}
ctrProc.eg.Go(func() error {
var closeDoneOnce sync.Once
var exitError error
for {
msg, ok := msgs.Recv(ctx)
if !ok {
// no more messages, return
return exitError
}
if msg == nil {
// empty message from ctx cancel, so just start shutting down
// input, but continue processing more exit/done messages
closeDoneOnce.Do(func() {
close(done)
})
continue
}
if file := msg.GetFile(); file != nil {
var out io.WriteCloser
switch file.Fd {
case 1:
out = req.Stdout
case 2:
out = req.Stderr
}
if out == nil {
// if things are plumbed correctly this should never happen
return errors.Errorf("missing writer for output fd %d", file.Fd)
}
if len(file.Data) > 0 {
_, err := out.Write(file.Data)
if err != nil {
return err
}
}
} else if exit := msg.GetExit(); exit != nil {
// capture exit message to exitError so we can return it after
// the server sends the Done message
closeDoneOnce.Do(func() {
close(done)
})
if exit.Code == 0 {
continue
}
exitError = grpcerrors.FromGRPC(status.ErrorProto(&spb.Status{
Code: exit.Error.Code,
Message: exit.Error.Message,
Details: convertGogoAny(exit.Error.Details),
}))
if exit.Code != errdefs.ContainerdUnknownExitStatus {
exitError = &errdefs.ExitError{ExitCode: exit.Code, Err: exitError}
}
} else if serverDone := msg.GetDone(); serverDone != nil {
return exitError
} else {
return errors.Errorf("unexpected Exec Message for pid %s: %T", pid, msg.GetInput())
}
}
})
return ctrProc, nil
}
func (ctr *container) Release(ctx context.Context) error {
logrus.Debugf("|---> ReleaseContainer %s", ctr.id)
_, err := ctr.client.ReleaseContainer(ctx, &pb.ReleaseContainerRequest{
ContainerID: ctr.id,
})
return err
}
type containerProcess struct {
execMsgs *messageForwarder
id string
eg *errgroup.Group
}
func (ctrProc *containerProcess) Wait() error {
defer ctrProc.execMsgs.Deregister(ctrProc.id)
return ctrProc.eg.Wait()
}
func (ctrProc *containerProcess) Resize(_ context.Context, size client.WinSize) error {
return ctrProc.execMsgs.Send(&pb.ExecMessage{
ProcessID: ctrProc.id,
Input: &pb.ExecMessage_Resize{
Resize: &pb.ResizeMessage{
Cols: size.Cols,
Rows: size.Rows,
},
},
})
}
type reference struct {
@ -509,7 +1006,7 @@ func grpcClientConn(ctx context.Context) (context.Context, *grpc.ClientConn, err
return stdioConn(), nil
})
cc, err := grpc.DialContext(ctx, "", dialOpt, grpc.WithInsecure(), grpc.WithUnaryInterceptor(grpcerrors.UnaryClientInterceptor), grpc.WithStreamInterceptor(grpcerrors.StreamClientInterceptor))
cc, err := grpc.DialContext(ctx, "localhost", dialOpt, grpc.WithInsecure(), grpc.WithUnaryInterceptor(grpcerrors.UnaryClientInterceptor), grpc.WithStreamInterceptor(grpcerrors.StreamClientInterceptor))
if err != nil {
return nil, nil, errors.Wrap(err, "failed to create grpc client")
}
@ -596,6 +1093,14 @@ func product() string {
return os.Getenv("BUILDKIT_EXPORTEDPRODUCT")
}
func convertGogoAny(in []*gogotypes.Any) []*any.Any {
out := make([]*any.Any, len(in))
for i := range in {
out[i] = &any.Any{TypeUrl: in[i].TypeUrl, Value: in[i].Value}
}
return out
}
func convertToGogoAny(in []*any.Any) []*gogotypes.Any {
out := make([]*gogotypes.Any, len(in))
for i := range in {

View File

@ -35,6 +35,18 @@ const (
// CapGatewaySolveMetadata can be used to check if solve calls from gateway reliably return metadata
CapGatewaySolveMetadata apicaps.CapID = "gateway.solve.metadata"
// CapGatewayExec is the capability to create and interact with new
// containers directly through the gateway
CapGatewayExec apicaps.CapID = "gateway.exec"
// CapFrontendCaps can be used to check that frontends define support for certain capabilities
CapFrontendCaps apicaps.CapID = "frontend.caps"
// CapGatewayEvaluateSolve is a capability to immediately unlazy solve
// results. This is generally used by the client to return and handle solve
// errors.
CapGatewayEvaluateSolve apicaps.CapID = "gateway.solve.evaluate"
)
func init() {
@ -136,4 +148,25 @@ func init() {
Enabled: true,
Status: apicaps.CapStatusExperimental,
})
Caps.Init(apicaps.Cap{
ID: CapGatewayExec,
Name: "gateway exec",
Enabled: true,
Status: apicaps.CapStatusExperimental,
})
Caps.Init(apicaps.Cap{
ID: CapFrontendCaps,
Name: "frontend capabilities",
Enabled: true,
Status: apicaps.CapStatusExperimental,
})
Caps.Init(apicaps.Cap{
ID: CapGatewayEvaluateSolve,
Name: "gateway evaluate solve",
Enabled: true,
Status: apicaps.CapStatusExperimental,
})
}

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,10 @@ service LLBBridge {
rpc Return(ReturnRequest) returns (ReturnResponse);
// apicaps:CapFrontendInputs
rpc Inputs(InputsRequest) returns (InputsResponse);
rpc NewContainer(NewContainerRequest) returns (NewContainerResponse);
rpc ReleaseContainer(ReleaseContainerRequest) returns (ReleaseContainerResponse);
rpc ExecProcess(stream ExecMessage) returns (stream ExecMessage);
}
message Result {
@ -103,6 +107,8 @@ message SolveRequest {
// apicaps:CapFrontendInputs
map<string, pb.Definition> FrontendInputs = 13;
bool Evaluate = 14;
}
// CacheOptionsEntry corresponds to the control.CacheOptionsEntry
@ -162,3 +168,71 @@ message PongResponse{
repeated moby.buildkit.v1.apicaps.APICap LLBCaps = 2 [(gogoproto.nullable) = false];
repeated moby.buildkit.v1.types.WorkerRecord Workers = 3;
}
message NewContainerRequest {
string ContainerID = 1;
// For mount input values we can use random identifiers passed with ref
repeated pb.Mount Mounts = 2;
pb.NetMode Network = 3;
pb.Platform platform = 4;
pb.WorkerConstraints constraints = 5;
}
message NewContainerResponse{}
message ReleaseContainerRequest {
string ContainerID = 1;
}
message ReleaseContainerResponse{}
message ExecMessage {
string ProcessID = 1;
oneof Input {
// InitMessage sent from client to server will start a new process in a
// container
InitMessage Init = 2;
// FdMessage used from client to server for input (stdin) and
// from server to client for output (stdout, stderr)
FdMessage File = 3;
// ResizeMessage used from client to server for terminal resize events
ResizeMessage Resize = 4;
// StartedMessage sent from server to client after InitMessage to
// indicate the process has started.
StartedMessage Started = 5;
// ExitMessage sent from server to client will contain the exit code
// when the process ends.
ExitMessage Exit = 6;
// DoneMessage from server to client will be the last message for any
// process. Note that FdMessage might be sent after ExitMessage.
DoneMessage Done = 7;
}
}
message InitMessage{
string ContainerID = 1;
pb.Meta Meta = 2;
repeated uint32 Fds = 3;
bool Tty = 4;
pb.SecurityMode Security = 5;
}
message ExitMessage {
uint32 Code = 1;
google.rpc.Status Error = 2;
}
message StartedMessage{}
message DoneMessage{}
message FdMessage{
uint32 Fd = 1; // what fd the data was from
bool EOF = 2; // true if eof was reached
bytes Data = 3;
}
message ResizeMessage{
uint32 Rows = 1;
uint32 Cols = 2;
}

View File

@ -2,12 +2,29 @@ package auth
import (
"context"
"crypto/subtle"
"math/rand"
"sync"
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/util/grpcerrors"
"github.com/pkg/errors"
"golang.org/x/crypto/nacl/sign"
"google.golang.org/grpc/codes"
)
var salt []byte
var saltOnce sync.Once
// getSalt returns unique component per daemon restart to avoid persistent keys
func getSalt() []byte {
saltOnce.Do(func() {
salt = make([]byte, 32)
rand.Read(salt)
})
return salt
}
func CredentialsFunc(sm *session.Manager, g session.Group) func(string) (session, username, secret string, err error) {
return func(host string) (string, string, string, error) {
var sessionID, user, secret string
@ -34,3 +51,80 @@ func CredentialsFunc(sm *session.Manager, g session.Group) func(string) (session
return sessionID, user, secret, nil
}
}
func FetchToken(req *FetchTokenRequest, sm *session.Manager, g session.Group) (resp *FetchTokenResponse, err error) {
err = sm.Any(context.TODO(), g, func(ctx context.Context, id string, c session.Caller) error {
client := NewAuthClient(c.Conn())
resp, err = client.FetchToken(ctx, req)
if err != nil {
return err
}
return nil
})
if err != nil {
return nil, err
}
return resp, nil
}
func VerifyTokenAuthority(host string, pubKey *[32]byte, sm *session.Manager, g session.Group) (sessionID string, ok bool, err error) {
var verified bool
err = sm.Any(context.TODO(), g, func(ctx context.Context, id string, c session.Caller) error {
client := NewAuthClient(c.Conn())
payload := make([]byte, 32)
rand.Read(payload)
resp, err := client.VerifyTokenAuthority(ctx, &VerifyTokenAuthorityRequest{
Host: host,
Salt: getSalt(),
Payload: payload,
})
if err != nil {
if grpcerrors.Code(err) == codes.Unimplemented {
return nil
}
return err
}
var dt []byte
dt, ok = sign.Open(nil, resp.Signed, pubKey)
if ok && subtle.ConstantTimeCompare(dt, payload) == 1 {
verified = true
}
sessionID = id
return nil
})
if err != nil {
return "", false, err
}
return sessionID, verified, nil
}
func GetTokenAuthority(host string, sm *session.Manager, g session.Group) (sessionID string, pubKey *[32]byte, err error) {
err = sm.Any(context.TODO(), g, func(ctx context.Context, id string, c session.Caller) error {
client := NewAuthClient(c.Conn())
resp, err := client.GetTokenAuthority(ctx, &GetTokenAuthorityRequest{
Host: host,
Salt: getSalt(),
})
if err != nil {
if grpcerrors.Code(err) == codes.Unimplemented || grpcerrors.Code(err) == codes.Unavailable {
return nil
}
return err
}
if len(resp.PublicKey) != 32 {
return errors.Errorf("invalid pubkey length %d", len(pubKey))
}
sessionID = id
pubKey = new([32]byte)
copy((*pubKey)[:], resp.PublicKey)
return nil
})
if err != nil {
return "", nil, err
}
return sessionID, pubKey, nil
}

File diff suppressed because it is too large Load Diff

View File

@ -6,9 +6,11 @@ option go_package = "auth";
service Auth{
rpc Credentials(CredentialsRequest) returns (CredentialsResponse);
rpc FetchToken(FetchTokenRequest) returns (FetchTokenResponse);
rpc GetTokenAuthority(GetTokenAuthorityRequest) returns (GetTokenAuthorityResponse);
rpc VerifyTokenAuthority(VerifyTokenAuthorityRequest) returns (VerifyTokenAuthorityResponse);
}
message CredentialsRequest {
string Host = 1;
}
@ -17,3 +19,36 @@ message CredentialsResponse {
string Username = 1;
string Secret = 2;
}
message FetchTokenRequest {
string ClientID = 1;
string Host = 2;
string Realm = 3;
string Service = 4;
repeated string Scopes = 5;
}
message FetchTokenResponse {
string Token = 1;
int64 ExpiresIn = 2; // seconds
int64 IssuedAt = 3; // timestamp
}
message GetTokenAuthorityRequest {
string Host = 1;
bytes Salt = 2;
}
message GetTokenAuthorityResponse {
bytes PublicKey = 1;
}
message VerifyTokenAuthorityRequest {
string Host = 1;
bytes Payload = 2;
bytes Salt = 3;
}
message VerifyTokenAuthorityResponse {
bytes Signed = 1;
}

View File

@ -2,24 +2,46 @@ package authprovider
import (
"context"
"crypto/ed25519"
"crypto/hmac"
"crypto/sha256"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"strconv"
"strings"
"sync"
"time"
authutil "github.com/containerd/containerd/remotes/docker/auth"
remoteserrors "github.com/containerd/containerd/remotes/errors"
"github.com/docker/cli/cli/config"
"github.com/docker/cli/cli/config/configfile"
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/session/auth"
"github.com/moby/buildkit/util/progress/progresswriter"
"github.com/pkg/errors"
"golang.org/x/crypto/nacl/sign"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
func NewDockerAuthProvider(stderr io.Writer) session.Attachable {
return &authProvider{
config: config.LoadDefaultConfigFile(stderr),
config: config.LoadDefaultConfigFile(stderr),
seeds: &tokenSeeds{dir: config.Dir()},
loggerCache: map[string]struct{}{},
}
}
type authProvider struct {
config *configfile.ConfigFile
config *configfile.ConfigFile
seeds *tokenSeeds
logger progresswriter.Logger
loggerCache map[string]struct{}
// The need for this mutex is not well understood.
// Without it, the docker cli on OS X hangs when
@ -28,17 +50,80 @@ type authProvider struct {
mu sync.Mutex
}
func (ap *authProvider) SetLogger(l progresswriter.Logger) {
ap.mu.Lock()
ap.logger = l
ap.mu.Unlock()
}
func (ap *authProvider) Register(server *grpc.Server) {
auth.RegisterAuthServer(server, ap)
}
func (ap *authProvider) Credentials(ctx context.Context, req *auth.CredentialsRequest) (*auth.CredentialsResponse, error) {
func (ap *authProvider) FetchToken(ctx context.Context, req *auth.FetchTokenRequest) (rr *auth.FetchTokenResponse, err error) {
creds, err := ap.credentials(req.Host)
if err != nil {
return nil, err
}
to := authutil.TokenOptions{
Realm: req.Realm,
Service: req.Service,
Scopes: req.Scopes,
Username: creds.Username,
Secret: creds.Secret,
}
if creds.Secret != "" {
done := func(progresswriter.SubLogger) error {
return err
}
defer func() {
err = errors.Wrap(err, "failed to fetch oauth token")
}()
ap.mu.Lock()
name := fmt.Sprintf("[auth] %v token for %s", strings.Join(trimScopePrefix(req.Scopes), " "), req.Host)
if _, ok := ap.loggerCache[name]; !ok {
progresswriter.Wrap(name, ap.logger, done)
}
ap.mu.Unlock()
// try GET first because Docker Hub does not support POST
// switch once support has landed
resp, err := authutil.FetchToken(ctx, http.DefaultClient, nil, to)
if err != nil {
var errStatus remoteserrors.ErrUnexpectedStatus
if errors.As(err, &errStatus) {
// retry with POST request
// As of September 2017, GCR is known to return 404.
// As of February 2018, JFrog Artifactory is known to return 401.
if (errStatus.StatusCode == 405 && to.Username != "") || errStatus.StatusCode == 404 || errStatus.StatusCode == 401 {
resp, err := authutil.FetchTokenWithOAuth(ctx, http.DefaultClient, nil, "buildkit-client", to)
if err != nil {
return nil, err
}
return toTokenResponse(resp.AccessToken, resp.IssuedAt, resp.ExpiresIn), nil
}
}
return nil, err
}
return toTokenResponse(resp.Token, resp.IssuedAt, resp.ExpiresIn), nil
}
// do request anonymously
resp, err := authutil.FetchToken(ctx, http.DefaultClient, nil, to)
if err != nil {
return nil, errors.Wrap(err, "failed to fetch anonymous token")
}
return toTokenResponse(resp.Token, resp.IssuedAt, resp.ExpiresIn), nil
}
func (ap *authProvider) credentials(host string) (*auth.CredentialsResponse, error) {
ap.mu.Lock()
defer ap.mu.Unlock()
if req.Host == "registry-1.docker.io" {
req.Host = "https://index.docker.io/v1/"
if host == "registry-1.docker.io" {
host = "https://index.docker.io/v1/"
}
ac, err := ap.config.GetAuthConfig(req.Host)
ac, err := ap.config.GetAuthConfig(host)
if err != nil {
return nil, err
}
@ -51,3 +136,85 @@ func (ap *authProvider) Credentials(ctx context.Context, req *auth.CredentialsRe
}
return res, nil
}
func (ap *authProvider) Credentials(ctx context.Context, req *auth.CredentialsRequest) (*auth.CredentialsResponse, error) {
resp, err := ap.credentials(req.Host)
if err != nil || resp.Secret != "" {
ap.mu.Lock()
defer ap.mu.Unlock()
_, ok := ap.loggerCache[req.Host]
ap.loggerCache[req.Host] = struct{}{}
if !ok {
return resp, progresswriter.Wrap(fmt.Sprintf("[auth] sharing credentials for %s", req.Host), ap.logger, func(progresswriter.SubLogger) error {
return err
})
}
}
return resp, err
}
func (ap *authProvider) GetTokenAuthority(ctx context.Context, req *auth.GetTokenAuthorityRequest) (*auth.GetTokenAuthorityResponse, error) {
key, err := ap.getAuthorityKey(req.Host, req.Salt)
if err != nil {
return nil, err
}
return &auth.GetTokenAuthorityResponse{PublicKey: key[32:]}, nil
}
func (ap *authProvider) VerifyTokenAuthority(ctx context.Context, req *auth.VerifyTokenAuthorityRequest) (*auth.VerifyTokenAuthorityResponse, error) {
key, err := ap.getAuthorityKey(req.Host, req.Salt)
if err != nil {
return nil, err
}
priv := new([64]byte)
copy((*priv)[:], key)
return &auth.VerifyTokenAuthorityResponse{Signed: sign.Sign(nil, req.Payload, priv)}, nil
}
func (ap *authProvider) getAuthorityKey(host string, salt []byte) (ed25519.PrivateKey, error) {
if v, err := strconv.ParseBool(os.Getenv("BUILDKIT_NO_CLIENT_TOKEN")); err == nil && v {
return nil, status.Errorf(codes.Unavailable, "client side tokens disabled")
}
creds, err := ap.credentials(host)
if err != nil {
return nil, err
}
seed, err := ap.seeds.getSeed(host)
if err != nil {
return nil, err
}
mac := hmac.New(sha256.New, salt)
if creds.Secret != "" {
mac.Write(seed)
enc := json.NewEncoder(mac)
enc.Encode(creds)
}
sum := mac.Sum(nil)
return ed25519.NewKeyFromSeed(sum[:ed25519.SeedSize]), nil
}
func toTokenResponse(token string, issuedAt time.Time, expires int) *auth.FetchTokenResponse {
resp := &auth.FetchTokenResponse{
Token: token,
ExpiresIn: int64(expires),
}
if !issuedAt.IsZero() {
resp.IssuedAt = issuedAt.Unix()
}
return resp
}
func trimScopePrefix(scopes []string) []string {
out := make([]string, len(scopes))
for i, s := range scopes {
out[i] = strings.TrimPrefix(s, "repository:")
}
return out
}

View File

@ -0,0 +1,84 @@
package authprovider
import (
"crypto/rand"
"encoding/json"
"io/ioutil"
"os"
"path/filepath"
"sync"
"syscall"
"github.com/gofrs/flock"
"github.com/pkg/errors"
)
type tokenSeeds struct {
mu sync.Mutex
dir string
m map[string]seed
}
type seed struct {
Seed []byte
}
func (ts *tokenSeeds) getSeed(host string) ([]byte, error) {
ts.mu.Lock()
defer ts.mu.Unlock()
if err := os.MkdirAll(ts.dir, 0755); err != nil {
return nil, err
}
if ts.m == nil {
ts.m = map[string]seed{}
}
l := flock.New(filepath.Join(ts.dir, ".token_seed.lock"))
if err := l.Lock(); err != nil {
if !errors.Is(err, syscall.EROFS) && errors.Is(err, syscall.EPERM) {
return nil, err
}
} else {
defer l.Unlock()
}
fp := filepath.Join(ts.dir, ".token_seed")
// we include client side randomness to avoid chosen plaintext attack from the daemon side
dt, err := ioutil.ReadFile(fp)
if err != nil {
if !errors.Is(err, os.ErrNotExist) && !errors.Is(err, syscall.ENOTDIR) {
return nil, err
}
} else {
if err := json.Unmarshal(dt, &ts.m); err != nil {
return nil, errors.Wrapf(err, "failed to parse %s", fp)
}
}
v, ok := ts.m[host]
if !ok {
v = seed{Seed: newSeed()}
}
ts.m[host] = v
dt, err = json.MarshalIndent(ts.m, "", " ")
if err != nil {
return nil, err
}
if err := ioutil.WriteFile(fp, dt, 0600); err != nil {
if !errors.Is(err, syscall.EROFS) && !errors.Is(err, syscall.EPERM) {
return nil, err
}
}
return v.Seed, nil
}
func newSeed() []byte {
b := make([]byte, 16)
rand.Read(b)
return b
}

View File

@ -64,7 +64,7 @@ func grpcClientConn(ctx context.Context, conn net.Conn) (context.Context, *grpc.
dialOpts = append(dialOpts, grpc.WithStreamInterceptor(grpc_middleware.ChainStreamClient(stream...)))
}
cc, err := grpc.DialContext(ctx, "", dialOpts...)
cc, err := grpc.DialContext(ctx, "localhost", dialOpts...)
if err != nil {
return nil, nil, errors.Wrap(err, "failed to create grpc client")
}

View File

@ -6,6 +6,8 @@ import (
"io/ioutil"
"net"
"os"
"runtime"
"strings"
"time"
"github.com/moby/buildkit/session"
@ -139,7 +141,7 @@ func toAgentSource(paths []string) (source, error) {
socket = p
continue
}
keys = true
f, err := os.Open(p)
if err != nil {
return source{}, errors.Wrapf(err, "failed to open %s", p)
@ -151,11 +153,24 @@ func toAgentSource(paths []string) (source, error) {
k, err := ssh.ParseRawPrivateKey(dt)
if err != nil {
// On Windows, os.ModeSocket isn't appropriately set on the file mode.
// https://github.com/golang/go/issues/33357
// If parsing the file fails, check to see if it kind of looks like socket-shaped.
if runtime.GOOS == "windows" && strings.Contains(string(dt), "socket") {
if keys {
return source{}, errors.Errorf("invalid combination of keys and sockets")
}
socket = p
continue
}
return source{}, errors.Wrapf(err, "failed to parse %s", p) // TODO: prompt passphrase?
}
if err := a.Add(agent.AddedKey{PrivateKey: k}); err != nil {
return source{}, errors.Wrapf(err, "failed to add %s to agent", p)
}
keys = true
}
if socket != "" {

View File

@ -0,0 +1,13 @@
package errdefs
import (
"context"
"errors"
"github.com/moby/buildkit/util/grpcerrors"
"google.golang.org/grpc/codes"
)
func IsCanceled(err error) bool {
return errors.Is(err, context.Canceled) || grpcerrors.Code(err) == codes.Canceled
}

View File

@ -105,25 +105,295 @@ func (m *Source) GetRanges() []*pb.Range {
return nil
}
type FrontendCap struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *FrontendCap) Reset() { *m = FrontendCap{} }
func (m *FrontendCap) String() string { return proto.CompactTextString(m) }
func (*FrontendCap) ProtoMessage() {}
func (*FrontendCap) Descriptor() ([]byte, []int) {
return fileDescriptor_689dc58a5060aff5, []int{2}
}
func (m *FrontendCap) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_FrontendCap.Unmarshal(m, b)
}
func (m *FrontendCap) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_FrontendCap.Marshal(b, m, deterministic)
}
func (m *FrontendCap) XXX_Merge(src proto.Message) {
xxx_messageInfo_FrontendCap.Merge(m, src)
}
func (m *FrontendCap) XXX_Size() int {
return xxx_messageInfo_FrontendCap.Size(m)
}
func (m *FrontendCap) XXX_DiscardUnknown() {
xxx_messageInfo_FrontendCap.DiscardUnknown(m)
}
var xxx_messageInfo_FrontendCap proto.InternalMessageInfo
func (m *FrontendCap) GetName() string {
if m != nil {
return m.Name
}
return ""
}
type Subrequest struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Subrequest) Reset() { *m = Subrequest{} }
func (m *Subrequest) String() string { return proto.CompactTextString(m) }
func (*Subrequest) ProtoMessage() {}
func (*Subrequest) Descriptor() ([]byte, []int) {
return fileDescriptor_689dc58a5060aff5, []int{3}
}
func (m *Subrequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Subrequest.Unmarshal(m, b)
}
func (m *Subrequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Subrequest.Marshal(b, m, deterministic)
}
func (m *Subrequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_Subrequest.Merge(m, src)
}
func (m *Subrequest) XXX_Size() int {
return xxx_messageInfo_Subrequest.Size(m)
}
func (m *Subrequest) XXX_DiscardUnknown() {
xxx_messageInfo_Subrequest.DiscardUnknown(m)
}
var xxx_messageInfo_Subrequest proto.InternalMessageInfo
func (m *Subrequest) GetName() string {
if m != nil {
return m.Name
}
return ""
}
type Solve struct {
InputIDs []string `protobuf:"bytes,1,rep,name=inputIDs,proto3" json:"inputIDs,omitempty"`
MountIDs []string `protobuf:"bytes,2,rep,name=mountIDs,proto3" json:"mountIDs,omitempty"`
Op *pb.Op `protobuf:"bytes,3,opt,name=op,proto3" json:"op,omitempty"`
// Types that are valid to be assigned to Subject:
// *Solve_File
// *Solve_Cache
Subject isSolve_Subject `protobuf_oneof:"subject"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Solve) Reset() { *m = Solve{} }
func (m *Solve) String() string { return proto.CompactTextString(m) }
func (*Solve) ProtoMessage() {}
func (*Solve) Descriptor() ([]byte, []int) {
return fileDescriptor_689dc58a5060aff5, []int{4}
}
func (m *Solve) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Solve.Unmarshal(m, b)
}
func (m *Solve) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Solve.Marshal(b, m, deterministic)
}
func (m *Solve) XXX_Merge(src proto.Message) {
xxx_messageInfo_Solve.Merge(m, src)
}
func (m *Solve) XXX_Size() int {
return xxx_messageInfo_Solve.Size(m)
}
func (m *Solve) XXX_DiscardUnknown() {
xxx_messageInfo_Solve.DiscardUnknown(m)
}
var xxx_messageInfo_Solve proto.InternalMessageInfo
type isSolve_Subject interface {
isSolve_Subject()
}
type Solve_File struct {
File *FileAction `protobuf:"bytes,4,opt,name=file,proto3,oneof" json:"file,omitempty"`
}
type Solve_Cache struct {
Cache *ContentCache `protobuf:"bytes,5,opt,name=cache,proto3,oneof" json:"cache,omitempty"`
}
func (*Solve_File) isSolve_Subject() {}
func (*Solve_Cache) isSolve_Subject() {}
func (m *Solve) GetSubject() isSolve_Subject {
if m != nil {
return m.Subject
}
return nil
}
func (m *Solve) GetInputIDs() []string {
if m != nil {
return m.InputIDs
}
return nil
}
func (m *Solve) GetMountIDs() []string {
if m != nil {
return m.MountIDs
}
return nil
}
func (m *Solve) GetOp() *pb.Op {
if m != nil {
return m.Op
}
return nil
}
func (m *Solve) GetFile() *FileAction {
if x, ok := m.GetSubject().(*Solve_File); ok {
return x.File
}
return nil
}
func (m *Solve) GetCache() *ContentCache {
if x, ok := m.GetSubject().(*Solve_Cache); ok {
return x.Cache
}
return nil
}
// XXX_OneofWrappers is for the internal use of the proto package.
func (*Solve) XXX_OneofWrappers() []interface{} {
return []interface{}{
(*Solve_File)(nil),
(*Solve_Cache)(nil),
}
}
type FileAction struct {
// Index of the file action that failed the exec.
Index int64 `protobuf:"varint,1,opt,name=index,proto3" json:"index,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *FileAction) Reset() { *m = FileAction{} }
func (m *FileAction) String() string { return proto.CompactTextString(m) }
func (*FileAction) ProtoMessage() {}
func (*FileAction) Descriptor() ([]byte, []int) {
return fileDescriptor_689dc58a5060aff5, []int{5}
}
func (m *FileAction) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_FileAction.Unmarshal(m, b)
}
func (m *FileAction) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_FileAction.Marshal(b, m, deterministic)
}
func (m *FileAction) XXX_Merge(src proto.Message) {
xxx_messageInfo_FileAction.Merge(m, src)
}
func (m *FileAction) XXX_Size() int {
return xxx_messageInfo_FileAction.Size(m)
}
func (m *FileAction) XXX_DiscardUnknown() {
xxx_messageInfo_FileAction.DiscardUnknown(m)
}
var xxx_messageInfo_FileAction proto.InternalMessageInfo
func (m *FileAction) GetIndex() int64 {
if m != nil {
return m.Index
}
return 0
}
type ContentCache struct {
// Original index of result that failed the slow cache calculation.
Index int64 `protobuf:"varint,1,opt,name=index,proto3" json:"index,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ContentCache) Reset() { *m = ContentCache{} }
func (m *ContentCache) String() string { return proto.CompactTextString(m) }
func (*ContentCache) ProtoMessage() {}
func (*ContentCache) Descriptor() ([]byte, []int) {
return fileDescriptor_689dc58a5060aff5, []int{6}
}
func (m *ContentCache) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ContentCache.Unmarshal(m, b)
}
func (m *ContentCache) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ContentCache.Marshal(b, m, deterministic)
}
func (m *ContentCache) XXX_Merge(src proto.Message) {
xxx_messageInfo_ContentCache.Merge(m, src)
}
func (m *ContentCache) XXX_Size() int {
return xxx_messageInfo_ContentCache.Size(m)
}
func (m *ContentCache) XXX_DiscardUnknown() {
xxx_messageInfo_ContentCache.DiscardUnknown(m)
}
var xxx_messageInfo_ContentCache proto.InternalMessageInfo
func (m *ContentCache) GetIndex() int64 {
if m != nil {
return m.Index
}
return 0
}
func init() {
proto.RegisterType((*Vertex)(nil), "errdefs.Vertex")
proto.RegisterType((*Source)(nil), "errdefs.Source")
proto.RegisterType((*FrontendCap)(nil), "errdefs.FrontendCap")
proto.RegisterType((*Subrequest)(nil), "errdefs.Subrequest")
proto.RegisterType((*Solve)(nil), "errdefs.Solve")
proto.RegisterType((*FileAction)(nil), "errdefs.FileAction")
proto.RegisterType((*ContentCache)(nil), "errdefs.ContentCache")
}
func init() { proto.RegisterFile("errdefs.proto", fileDescriptor_689dc58a5060aff5) }
var fileDescriptor_689dc58a5060aff5 = []byte{
// 177 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x2c, 0xcd, 0xc1, 0x8a, 0x83, 0x30,
0x10, 0x80, 0x61, 0xdc, 0x5d, 0xb2, 0x18, 0xd9, 0x3d, 0xe4, 0x50, 0xa4, 0x27, 0xeb, 0xc9, 0x43,
0x49, 0xc0, 0x3e, 0x45, 0x4f, 0x85, 0x14, 0x7a, 0x6f, 0x74, 0xb4, 0xa1, 0xea, 0x84, 0x49, 0x2c,
0xed, 0xdb, 0x17, 0x6d, 0x8e, 0xff, 0x7c, 0x33, 0x0c, 0xff, 0x03, 0xa2, 0x16, 0x3a, 0x2f, 0x1d,
0x61, 0x40, 0xf1, 0x1b, 0x73, 0xbb, 0xef, 0x6d, 0xb8, 0xcd, 0x46, 0x36, 0x38, 0xaa, 0x11, 0xcd,
0x4b, 0x99, 0xd9, 0x0e, 0xed, 0xdd, 0x06, 0xe5, 0x71, 0x78, 0x00, 0x29, 0x67, 0x14, 0xba, 0x78,
0x56, 0x16, 0x9c, 0x5d, 0x80, 0x02, 0x3c, 0xc5, 0x86, 0xb3, 0xd6, 0xf6, 0xe0, 0x43, 0x9e, 0x14,
0x49, 0x95, 0xea, 0x58, 0xe5, 0x89, 0xb3, 0x33, 0xce, 0xd4, 0x80, 0x28, 0xf9, 0x8f, 0x9d, 0x3a,
0x5c, 0x3d, 0xab, 0xff, 0xa5, 0x33, 0xf2, 0x23, 0xc7, 0xa9, 0x43, 0xbd, 0x9a, 0xd8, 0x71, 0x46,
0xd7, 0xa9, 0x07, 0x9f, 0x7f, 0x15, 0xdf, 0x55, 0x56, 0xa7, 0xcb, 0x96, 0x5e, 0x26, 0x3a, 0x82,
0x61, 0xeb, 0xe7, 0xc3, 0x3b, 0x00, 0x00, 0xff, 0xff, 0x93, 0xb5, 0x8b, 0x2a, 0xc1, 0x00, 0x00,
0x00,
// 348 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x91, 0xcd, 0x8e, 0xd3, 0x30,
0x14, 0x85, 0x27, 0xbf, 0x43, 0x6e, 0x81, 0x85, 0x81, 0x51, 0x34, 0xab, 0x8c, 0xc5, 0xa2, 0x48,
0x90, 0x48, 0xc3, 0x13, 0x40, 0xd1, 0x68, 0x66, 0x55, 0xc9, 0x95, 0xd8, 0xc7, 0xc9, 0x4d, 0x6b,
0x48, 0x6c, 0xe3, 0xd8, 0xa8, 0xbc, 0x1b, 0x0f, 0x87, 0xe2, 0xa4, 0x65, 0x16, 0xdd, 0xe5, 0xe4,
0xfb, 0x7c, 0xed, 0x63, 0xc3, 0x2b, 0x34, 0xa6, 0xc5, 0x6e, 0x2c, 0xb5, 0x51, 0x56, 0x91, 0xeb,
0x25, 0xde, 0x7e, 0xdc, 0x0b, 0x7b, 0x70, 0xbc, 0x6c, 0xd4, 0x50, 0x0d, 0x8a, 0xff, 0xa9, 0xb8,
0x13, 0x7d, 0xfb, 0x53, 0xd8, 0x6a, 0x54, 0xfd, 0x6f, 0x34, 0x95, 0xe6, 0x95, 0xd2, 0xcb, 0x32,
0x5a, 0x40, 0xfa, 0x1d, 0x8d, 0xc5, 0x23, 0xb9, 0x81, 0xb4, 0x15, 0x7b, 0x1c, 0x6d, 0x1e, 0x14,
0xc1, 0x3a, 0x63, 0x4b, 0xa2, 0x5b, 0x48, 0x77, 0xca, 0x99, 0x06, 0x09, 0x85, 0x58, 0xc8, 0x4e,
0x79, 0xbe, 0xba, 0x7f, 0x5d, 0x6a, 0x5e, 0xce, 0xe4, 0x49, 0x76, 0x8a, 0x79, 0x46, 0xee, 0x20,
0x35, 0xb5, 0xdc, 0xe3, 0x98, 0x87, 0x45, 0xb4, 0x5e, 0xdd, 0x67, 0x93, 0xc5, 0xa6, 0x3f, 0x6c,
0x01, 0xf4, 0x0e, 0x56, 0x0f, 0x46, 0x49, 0x8b, 0xb2, 0xdd, 0xd4, 0x9a, 0x10, 0x88, 0x65, 0x3d,
0xe0, 0xb2, 0xab, 0xff, 0xa6, 0x05, 0xc0, 0xce, 0x71, 0x83, 0xbf, 0x1c, 0x8e, 0xf6, 0xa2, 0xf1,
0x37, 0x80, 0x64, 0x37, 0xf5, 0x21, 0xb7, 0xf0, 0x42, 0x48, 0xed, 0xec, 0xd3, 0xb7, 0x31, 0x0f,
0x8a, 0x68, 0x9d, 0xb1, 0x73, 0x9e, 0xd8, 0xa0, 0x9c, 0xf4, 0x2c, 0x9c, 0xd9, 0x29, 0x93, 0x1b,
0x08, 0x95, 0xce, 0x23, 0xdf, 0x25, 0x9d, 0x4e, 0xb9, 0xd5, 0x2c, 0x54, 0x9a, 0x7c, 0x80, 0xb8,
0x13, 0x3d, 0xe6, 0xb1, 0x27, 0x6f, 0xca, 0xd3, 0x35, 0x3f, 0x88, 0x1e, 0xbf, 0x34, 0x56, 0x28,
0xf9, 0x78, 0xc5, 0xbc, 0x42, 0x3e, 0x41, 0xd2, 0xd4, 0xcd, 0x01, 0xf3, 0xc4, 0xbb, 0xef, 0xce,
0xee, 0xc6, 0xd7, 0xb3, 0x9b, 0x09, 0x3e, 0x5e, 0xb1, 0xd9, 0xfa, 0x9a, 0xc1, 0xf5, 0xe8, 0xf8,
0x0f, 0x6c, 0x2c, 0xa5, 0x00, 0xff, 0xe7, 0x91, 0xb7, 0x90, 0x08, 0xd9, 0xe2, 0xd1, 0x37, 0x8c,
0xd8, 0x1c, 0xe8, 0x7b, 0x78, 0xf9, 0x7c, 0xce, 0x65, 0x8b, 0xa7, 0xfe, 0x1d, 0x3f, 0xff, 0x0b,
0x00, 0x00, 0xff, 0xff, 0x1e, 0xfa, 0x9c, 0x6f, 0x0f, 0x02, 0x00, 0x00,
}

View File

@ -12,3 +12,32 @@ message Source {
pb.SourceInfo info = 1;
repeated pb.Range ranges = 2;
}
message FrontendCap {
string name = 1;
}
message Subrequest {
string name = 1;
}
message Solve {
repeated string inputIDs = 1;
repeated string mountIDs = 2;
pb.Op op = 3;
oneof subject {
FileAction file = 4;
ContentCache cache = 5;
}
}
message FileAction {
// Index of the file action that failed the exec.
int64 index = 1;
}
message ContentCache {
// Original index of result that failed the slow cache calculation.
int64 index = 1;
}

34
vendor/github.com/moby/buildkit/solver/errdefs/exit.go generated vendored Normal file
View File

@ -0,0 +1,34 @@
package errdefs
import "fmt"
const (
// ContainerdUnknownExitStatus is returned when containerd is unable to
// determine the exit status of a process. This can happen if the process never starts
// or if an error was encountered when obtaining the exit status, it is set to 255.
//
// This const is defined here to prevent importing github.com/containerd/containerd
// and corresponds with https://github.com/containerd/containerd/blob/40b22ef0741028917761d8c5d5d29e0d19038836/task.go#L52-L55
ContainerdUnknownExitStatus = 255
)
// ExitError will be returned when the container process exits with a non-zero
// exit code.
type ExitError struct {
ExitCode uint32
Err error
}
func (err *ExitError) Error() string {
if err.Err != nil {
return err.Err.Error()
}
return fmt.Sprintf("exit code: %d", err.ExitCode)
}
func (err *ExitError) Unwrap() error {
if err.Err == nil {
return fmt.Errorf("exit code: %d", err.ExitCode)
}
return err.Err
}

View File

@ -0,0 +1,41 @@
package errdefs
import (
fmt "fmt"
"github.com/containerd/typeurl"
"github.com/moby/buildkit/util/grpcerrors"
)
func init() {
typeurl.Register((*FrontendCap)(nil), "github.com/moby/buildkit", "errdefs.FrontendCap+json")
}
type UnsupportedFrontendCapError struct {
FrontendCap
error
}
func (e *UnsupportedFrontendCapError) Error() string {
msg := fmt.Sprintf("unsupported frontend capability %s", e.FrontendCap.Name)
if e.error != nil {
msg += ": " + e.error.Error()
}
return msg
}
func (e *UnsupportedFrontendCapError) Unwrap() error {
return e.error
}
func (e *UnsupportedFrontendCapError) ToProto() grpcerrors.TypedErrorProto {
return &e.FrontendCap
}
func NewUnsupportedFrontendCapError(name string) error {
return &UnsupportedFrontendCapError{FrontendCap: FrontendCap{Name: name}}
}
func (v *FrontendCap) WrapError(err error) error {
return &UnsupportedFrontendCapError{error: err, FrontendCap: *v}
}

20
vendor/github.com/moby/buildkit/solver/errdefs/op.go generated vendored Normal file
View File

@ -0,0 +1,20 @@
package errdefs
import "github.com/moby/buildkit/solver/pb"
type OpError struct {
error
Op *pb.Op
}
func (e *OpError) Unwrap() error {
return e.error
}
func WithOp(err error, iface interface{}) error {
op, ok := iface.(*pb.Op)
if err == nil || !ok {
return err
}
return &OpError{error: err, Op: op}
}

View File

@ -0,0 +1,74 @@
package errdefs
import (
"bytes"
"errors"
"github.com/containerd/typeurl"
"github.com/golang/protobuf/jsonpb"
"github.com/moby/buildkit/solver/pb"
"github.com/moby/buildkit/util/grpcerrors"
)
func init() {
typeurl.Register((*Solve)(nil), "github.com/moby/buildkit", "errdefs.Solve+json")
}
//nolint:golint
type IsSolve_Subject isSolve_Subject
// SolveError will be returned when an error is encountered during a solve that
// has an exec op.
type SolveError struct {
Solve
Err error
}
func (e *SolveError) Error() string {
return e.Err.Error()
}
func (e *SolveError) Unwrap() error {
return e.Err
}
func (e *SolveError) ToProto() grpcerrors.TypedErrorProto {
return &e.Solve
}
func WithSolveError(err error, subject IsSolve_Subject, inputIDs, mountIDs []string) error {
if err == nil {
return nil
}
var (
oe *OpError
op *pb.Op
)
if errors.As(err, &oe) {
op = oe.Op
}
return &SolveError{
Err: err,
Solve: Solve{
InputIDs: inputIDs,
MountIDs: mountIDs,
Op: op,
Subject: subject,
},
}
}
func (v *Solve) WrapError(err error) error {
return &SolveError{Err: err, Solve: *v}
}
func (v *Solve) MarshalJSON() ([]byte, error) {
m := jsonpb.Marshaler{}
buf := new(bytes.Buffer)
err := m.Marshal(buf, v)
return buf.Bytes(), err
}
func (v *Solve) UnmarshalJSON(b []byte) error {
return jsonpb.Unmarshal(bytes.NewReader(b), v)
}

View File

@ -0,0 +1,41 @@
package errdefs
import (
fmt "fmt"
"github.com/containerd/typeurl"
"github.com/moby/buildkit/util/grpcerrors"
)
func init() {
typeurl.Register((*Subrequest)(nil), "github.com/moby/buildkit", "errdefs.Subrequest+json")
}
type UnsupportedSubrequestError struct {
Subrequest
error
}
func (e *UnsupportedSubrequestError) Error() string {
msg := fmt.Sprintf("unsupported request %s", e.Subrequest.Name)
if e.error != nil {
msg += ": " + e.error.Error()
}
return msg
}
func (e *UnsupportedSubrequestError) Unwrap() error {
return e.error
}
func (e *UnsupportedSubrequestError) ToProto() grpcerrors.TypedErrorProto {
return &e.Subrequest
}
func NewUnsupportedSubrequestError(name string) error {
return &UnsupportedSubrequestError{Subrequest: Subrequest{Name: name}}
}
func (v *Subrequest) WrapError(err error) error {
return &UnsupportedSubrequestError{error: err, Subrequest: *v}
}

View File

@ -4,6 +4,8 @@ const AttrKeepGitDir = "git.keepgitdir"
const AttrFullRemoteURL = "git.fullurl"
const AttrAuthHeaderSecret = "git.authheadersecret"
const AttrAuthTokenSecret = "git.authtokensecret"
const AttrKnownSSHHosts = "git.knownsshhosts"
const AttrMountSSHSock = "git.mountsshsock"
const AttrLocalSessionID = "local.session"
const AttrLocalUniqueID = "local.unique"
const AttrIncludePatterns = "local.includepattern"

View File

@ -19,10 +19,12 @@ const (
CapSourceLocalExcludePatterns apicaps.CapID = "source.local.excludepatterns"
CapSourceLocalSharedKeyHint apicaps.CapID = "source.local.sharedkeyhint"
CapSourceGit apicaps.CapID = "source.git"
CapSourceGitKeepDir apicaps.CapID = "source.git.keepgitdir"
CapSourceGitFullURL apicaps.CapID = "source.git.fullurl"
CapSourceGitHTTPAuth apicaps.CapID = "source.git.httpauth"
CapSourceGit apicaps.CapID = "source.git"
CapSourceGitKeepDir apicaps.CapID = "source.git.keepgitdir"
CapSourceGitFullURL apicaps.CapID = "source.git.fullurl"
CapSourceGitHTTPAuth apicaps.CapID = "source.git.httpauth"
CapSourceGitKnownSSHHosts apicaps.CapID = "source.git.knownsshhosts"
CapSourceGitMountSSHSock apicaps.CapID = "source.git.mountsshsock"
CapSourceHTTP apicaps.CapID = "source.http"
CapSourceHTTPChecksum apicaps.CapID = "source.http.checksum"
@ -138,6 +140,18 @@ func init() {
Status: apicaps.CapStatusExperimental,
})
Caps.Init(apicaps.Cap{
ID: CapSourceGitKnownSSHHosts,
Enabled: true,
Status: apicaps.CapStatusExperimental,
})
Caps.Init(apicaps.Cap{
ID: CapSourceGitMountSSHSock,
Enabled: true,
Status: apicaps.CapStatusExperimental,
})
Caps.Init(apicaps.Cap{
ID: CapSourceHTTP,
Enabled: true,

View File

@ -467,6 +467,7 @@ type Meta struct {
User string `protobuf:"bytes,4,opt,name=user,proto3" json:"user,omitempty"`
ProxyEnv *ProxyEnv `protobuf:"bytes,5,opt,name=proxy_env,json=proxyEnv,proto3" json:"proxy_env,omitempty"`
ExtraHosts []*HostIP `protobuf:"bytes,6,rep,name=extraHosts,proto3" json:"extraHosts,omitempty"`
Hostname string `protobuf:"bytes,7,opt,name=hostname,proto3" json:"hostname,omitempty"`
}
func (m *Meta) Reset() { *m = Meta{} }
@ -540,6 +541,13 @@ func (m *Meta) GetExtraHosts() []*HostIP {
return nil
}
func (m *Meta) GetHostname() string {
if m != nil {
return m.Hostname
}
return ""
}
// Mount specifies how to mount an input Op as a filesystem.
type Mount struct {
Input InputIndex `protobuf:"varint,1,opt,name=input,proto3,customtype=InputIndex" json:"input"`
@ -551,6 +559,7 @@ type Mount struct {
CacheOpt *CacheOpt `protobuf:"bytes,20,opt,name=cacheOpt,proto3" json:"cacheOpt,omitempty"`
SecretOpt *SecretOpt `protobuf:"bytes,21,opt,name=secretOpt,proto3" json:"secretOpt,omitempty"`
SSHOpt *SSHOpt `protobuf:"bytes,22,opt,name=SSHOpt,proto3" json:"SSHOpt,omitempty"`
ResultID string `protobuf:"bytes,23,opt,name=resultID,proto3" json:"resultID,omitempty"`
}
func (m *Mount) Reset() { *m = Mount{} }
@ -631,6 +640,13 @@ func (m *Mount) GetSSHOpt() *SSHOpt {
return nil
}
func (m *Mount) GetResultID() string {
if m != nil {
return m.ResultID
}
return ""
}
// CacheOpt defines options specific to cache mounts
type CacheOpt struct {
// ID is an optional namespace for the mount
@ -2316,144 +2332,146 @@ func init() {
func init() { proto.RegisterFile("ops.proto", fileDescriptor_8de16154b2733812) }
var fileDescriptor_8de16154b2733812 = []byte{
// 2189 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0x4b, 0x6f, 0x1b, 0xc9,
0xf1, 0x17, 0xdf, 0x64, 0x51, 0x92, 0xf9, 0xef, 0xf5, 0xee, 0x9f, 0xab, 0x38, 0x92, 0x76, 0xec,
0x2c, 0x64, 0xd9, 0xa6, 0x00, 0x2d, 0xb0, 0x5e, 0x2c, 0x82, 0x20, 0xe2, 0xc3, 0x10, 0xd7, 0xb6,
0x28, 0x34, 0xfd, 0xc8, 0xcd, 0x18, 0x0d, 0x9b, 0xd4, 0x40, 0xe4, 0xf4, 0xa0, 0xa7, 0x69, 0x8b,
0x97, 0x1c, 0xfc, 0x09, 0x16, 0x08, 0x90, 0x5b, 0x02, 0xe4, 0x12, 0x20, 0xf7, 0x5c, 0x73, 0xdf,
0xe3, 0x22, 0xc8, 0x61, 0x91, 0xc3, 0x26, 0xb0, 0x3f, 0x47, 0x80, 0xa0, 0xaa, 0x7b, 0x1e, 0x94,
0x65, 0xd8, 0x46, 0x82, 0x9c, 0xd8, 0xfd, 0xab, 0x5f, 0x57, 0x57, 0x57, 0x55, 0xd7, 0x54, 0x13,
0x6a, 0x32, 0x8c, 0x5a, 0xa1, 0x92, 0x5a, 0xb2, 0x7c, 0x78, 0xb2, 0x71, 0x67, 0xe2, 0xeb, 0xd3,
0xf9, 0x49, 0xcb, 0x93, 0xb3, 0xbd, 0x89, 0x9c, 0xc8, 0x3d, 0x12, 0x9d, 0xcc, 0xc7, 0x34, 0xa3,
0x09, 0x8d, 0xcc, 0x12, 0xe7, 0x0f, 0x79, 0xc8, 0x0f, 0x42, 0xf6, 0x19, 0x94, 0xfd, 0x20, 0x9c,
0xeb, 0xa8, 0x99, 0xdb, 0x2e, 0xec, 0xd4, 0xf7, 0x6b, 0xad, 0xf0, 0xa4, 0xd5, 0x47, 0x84, 0x5b,
0x01, 0xdb, 0x86, 0xa2, 0x38, 0x17, 0x5e, 0x33, 0xbf, 0x9d, 0xdb, 0xa9, 0xef, 0x03, 0x12, 0x7a,
0xe7, 0xc2, 0x1b, 0x84, 0x87, 0x2b, 0x9c, 0x24, 0xec, 0x73, 0x28, 0x47, 0x72, 0xae, 0x3c, 0xd1,
0x2c, 0x10, 0x67, 0x15, 0x39, 0x43, 0x42, 0x88, 0x65, 0xa5, 0xa8, 0x69, 0xec, 0x4f, 0x45, 0xb3,
0x98, 0x6a, 0xba, 0xe7, 0x4f, 0x0d, 0x87, 0x24, 0xec, 0x3a, 0x94, 0x4e, 0xe6, 0xfe, 0x74, 0xd4,
0x2c, 0x11, 0xa5, 0x8e, 0x94, 0x36, 0x02, 0xc4, 0x31, 0x32, 0xb6, 0x03, 0xd5, 0x70, 0xea, 0xea,
0xb1, 0x54, 0xb3, 0x26, 0xa4, 0x1b, 0x1e, 0x5b, 0x8c, 0x27, 0x52, 0x76, 0x17, 0xea, 0x9e, 0x0c,
0x22, 0xad, 0x5c, 0x3f, 0xd0, 0x51, 0xb3, 0x4e, 0xe4, 0x8f, 0x91, 0xfc, 0x54, 0xaa, 0x33, 0xa1,
0x3a, 0xa9, 0x90, 0x67, 0x99, 0xed, 0x22, 0xe4, 0x65, 0xe8, 0xfc, 0x36, 0x07, 0xd5, 0x58, 0x2b,
0x73, 0x60, 0xf5, 0x40, 0x79, 0xa7, 0xbe, 0x16, 0x9e, 0x9e, 0x2b, 0xd1, 0xcc, 0x6d, 0xe7, 0x76,
0x6a, 0x7c, 0x09, 0x63, 0xeb, 0x90, 0x1f, 0x0c, 0xc9, 0x51, 0x35, 0x9e, 0x1f, 0x0c, 0x59, 0x13,
0x2a, 0x4f, 0x5c, 0xe5, 0xbb, 0x81, 0x26, 0xcf, 0xd4, 0x78, 0x3c, 0x65, 0xd7, 0xa0, 0x36, 0x18,
0x3e, 0x11, 0x2a, 0xf2, 0x65, 0x40, 0xfe, 0xa8, 0xf1, 0x14, 0x60, 0x9b, 0x00, 0x83, 0xe1, 0x3d,
0xe1, 0xa2, 0xd2, 0xa8, 0x59, 0xda, 0x2e, 0xec, 0xd4, 0x78, 0x06, 0x71, 0x7e, 0x0d, 0x25, 0x8a,
0x11, 0xfb, 0x06, 0xca, 0x23, 0x7f, 0x22, 0x22, 0x6d, 0xcc, 0x69, 0xef, 0x7f, 0xf7, 0xe3, 0xd6,
0xca, 0xdf, 0x7f, 0xdc, 0xda, 0xcd, 0x24, 0x83, 0x0c, 0x45, 0xe0, 0xc9, 0x40, 0xbb, 0x7e, 0x20,
0x54, 0xb4, 0x37, 0x91, 0x77, 0xcc, 0x92, 0x56, 0x97, 0x7e, 0xb8, 0xd5, 0xc0, 0x6e, 0x42, 0xc9,
0x0f, 0x46, 0xe2, 0x9c, 0xec, 0x2f, 0xb4, 0x3f, 0xb2, 0xaa, 0xea, 0x83, 0xb9, 0x0e, 0xe7, 0xba,
0x8f, 0x22, 0x6e, 0x18, 0xce, 0xef, 0x73, 0x50, 0x36, 0x39, 0xc0, 0xae, 0x41, 0x71, 0x26, 0xb4,
0x4b, 0xfb, 0xd7, 0xf7, 0xab, 0xe8, 0xdb, 0x87, 0x42, 0xbb, 0x9c, 0x50, 0x4c, 0xaf, 0x99, 0x9c,
0xa3, 0xef, 0xf3, 0x69, 0x7a, 0x3d, 0x44, 0x84, 0x5b, 0x01, 0xfb, 0x19, 0x54, 0x02, 0xa1, 0x5f,
0x48, 0x75, 0x46, 0x3e, 0x5a, 0x37, 0x41, 0x3f, 0x12, 0xfa, 0xa1, 0x1c, 0x09, 0x1e, 0xcb, 0xd8,
0x6d, 0xa8, 0x46, 0xc2, 0x9b, 0x2b, 0x5f, 0x2f, 0xc8, 0x5f, 0xeb, 0xfb, 0x0d, 0xca, 0x32, 0x8b,
0x11, 0x39, 0x61, 0x38, 0x7f, 0xca, 0x41, 0x11, 0xcd, 0x60, 0x0c, 0x8a, 0xae, 0x9a, 0x98, 0xec,
0xae, 0x71, 0x1a, 0xb3, 0x06, 0x14, 0x44, 0xf0, 0x9c, 0x2c, 0xaa, 0x71, 0x1c, 0x22, 0xe2, 0xbd,
0x18, 0xd9, 0x18, 0xe1, 0x10, 0xd7, 0xcd, 0x23, 0xa1, 0x6c, 0x68, 0x68, 0xcc, 0x6e, 0x42, 0x2d,
0x54, 0xf2, 0x7c, 0xf1, 0x0c, 0x57, 0x97, 0x32, 0x89, 0x87, 0x60, 0x2f, 0x78, 0xce, 0xab, 0xa1,
0x1d, 0xb1, 0x5d, 0x00, 0x71, 0xae, 0x95, 0x7b, 0x28, 0x23, 0x1d, 0x35, 0xcb, 0x74, 0x76, 0xca,
0x77, 0x04, 0xfa, 0xc7, 0x3c, 0x23, 0x75, 0xfe, 0x9a, 0x87, 0x12, 0xb9, 0x84, 0xed, 0x60, 0x04,
0xc2, 0xb9, 0x09, 0x66, 0xa1, 0xcd, 0x6c, 0x04, 0x80, 0x62, 0x9d, 0x04, 0x00, 0xe3, 0xbe, 0x81,
0xde, 0x98, 0x0a, 0x4f, 0x4b, 0x65, 0xd3, 0x2d, 0x99, 0xa3, 0xe9, 0x23, 0xcc, 0x08, 0x73, 0x1a,
0x1a, 0xb3, 0x5b, 0x50, 0x96, 0x14, 0x46, 0x3a, 0xd0, 0x5b, 0x82, 0x6b, 0x29, 0xa8, 0x5c, 0x09,
0x77, 0x24, 0x83, 0xe9, 0x82, 0x8e, 0x59, 0xe5, 0xc9, 0x9c, 0xdd, 0x82, 0x1a, 0xc5, 0xed, 0xd1,
0x22, 0x14, 0xcd, 0x32, 0xc5, 0x61, 0x2d, 0x89, 0x29, 0x82, 0x3c, 0x95, 0xe3, 0x45, 0xf5, 0x5c,
0xef, 0x54, 0x0c, 0x42, 0xdd, 0xbc, 0x9a, 0xfa, 0xab, 0x63, 0x31, 0x9e, 0x48, 0x51, 0x6d, 0x24,
0x3c, 0x25, 0x34, 0x52, 0x3f, 0x26, 0xea, 0x9a, 0x0d, 0xaf, 0x01, 0x79, 0x2a, 0x67, 0x0e, 0x94,
0x87, 0xc3, 0x43, 0x64, 0x7e, 0x92, 0x16, 0x12, 0x83, 0x70, 0x2b, 0x71, 0xfa, 0x50, 0x8d, 0xb7,
0xc1, 0x5b, 0xd9, 0xef, 0xda, 0xfb, 0x9a, 0xef, 0x77, 0xd9, 0x1d, 0xa8, 0x44, 0xa7, 0xae, 0xf2,
0x83, 0x09, 0xf9, 0x6e, 0x7d, 0xff, 0xa3, 0xc4, 0xaa, 0xa1, 0xc1, 0x51, 0x53, 0xcc, 0x71, 0x24,
0xd4, 0x12, 0x33, 0xde, 0xd0, 0xd5, 0x80, 0xc2, 0xdc, 0x1f, 0x91, 0x9e, 0x35, 0x8e, 0x43, 0x44,
0x26, 0xbe, 0xc9, 0xa5, 0x35, 0x8e, 0x43, 0x0c, 0xc8, 0x4c, 0x8e, 0x4c, 0xd9, 0x5b, 0xe3, 0x34,
0x46, 0x1f, 0xcb, 0x50, 0xfb, 0x32, 0x70, 0xa7, 0xb1, 0x8f, 0xe3, 0xb9, 0x33, 0x8d, 0xcf, 0xf7,
0x3f, 0xd9, 0xed, 0x37, 0x39, 0xa8, 0xc6, 0xb5, 0x1a, 0x0b, 0x8f, 0x3f, 0x12, 0x81, 0xf6, 0xc7,
0xbe, 0x50, 0x76, 0xe3, 0x0c, 0xc2, 0xee, 0x40, 0xc9, 0xd5, 0x5a, 0xc5, 0xd7, 0xf9, 0xff, 0xb3,
0x85, 0xbe, 0x75, 0x80, 0x92, 0x5e, 0xa0, 0xd5, 0x82, 0x1b, 0xd6, 0xc6, 0x57, 0x00, 0x29, 0x88,
0xb6, 0x9e, 0x89, 0x85, 0xd5, 0x8a, 0x43, 0x76, 0x15, 0x4a, 0xcf, 0xdd, 0xe9, 0x5c, 0xd8, 0x1c,
0x36, 0x93, 0xaf, 0xf3, 0x5f, 0xe5, 0x9c, 0xbf, 0xe4, 0xa1, 0x62, 0x0b, 0x3f, 0xbb, 0x0d, 0x15,
0x2a, 0xfc, 0xd6, 0xa2, 0xcb, 0x2f, 0x46, 0x4c, 0x61, 0x7b, 0xc9, 0x17, 0x2d, 0x63, 0xa3, 0x55,
0x65, 0xbe, 0x6c, 0xd6, 0xc6, 0xf4, 0xfb, 0x56, 0x18, 0x89, 0xb1, 0xfd, 0x74, 0xad, 0x23, 0xbb,
0x2b, 0xc6, 0x7e, 0xe0, 0xa3, 0x7f, 0x38, 0x8a, 0xd8, 0xed, 0xf8, 0xd4, 0x45, 0xd2, 0xf8, 0x49,
0x56, 0xe3, 0x9b, 0x87, 0xee, 0x43, 0x3d, 0xb3, 0xcd, 0x25, 0xa7, 0xbe, 0x91, 0x3d, 0xb5, 0xdd,
0x92, 0xd4, 0x99, 0xef, 0x6e, 0xea, 0x85, 0xff, 0xc0, 0x7f, 0x5f, 0x02, 0xa4, 0x2a, 0xdf, 0xbf,
0xb0, 0x38, 0x2f, 0x0b, 0x00, 0x83, 0x10, 0x4b, 0xe7, 0xc8, 0xa5, 0xfa, 0xbd, 0xea, 0x4f, 0x02,
0xa9, 0xc4, 0x33, 0xba, 0xaa, 0xb4, 0xbe, 0xca, 0xeb, 0x06, 0xa3, 0x1b, 0xc3, 0x0e, 0xa0, 0x3e,
0x12, 0x91, 0xa7, 0x7c, 0x4a, 0x28, 0xeb, 0xf4, 0x2d, 0x3c, 0x53, 0xaa, 0xa7, 0xd5, 0x4d, 0x19,
0xc6, 0x57, 0xd9, 0x35, 0x6c, 0x1f, 0x56, 0xc5, 0x79, 0x28, 0x95, 0xb6, 0xbb, 0x98, 0xfe, 0xe0,
0x8a, 0xe9, 0x34, 0x10, 0xa7, 0x9d, 0x78, 0x5d, 0xa4, 0x13, 0xe6, 0x42, 0xd1, 0x73, 0x43, 0xf3,
0x71, 0xac, 0xef, 0x37, 0x2f, 0xec, 0xd7, 0x71, 0x43, 0xe3, 0xb4, 0xf6, 0x17, 0x78, 0xd6, 0x97,
0xff, 0xd8, 0xba, 0x95, 0xf9, 0x22, 0xce, 0xe4, 0xc9, 0x62, 0x8f, 0xf2, 0xe5, 0xcc, 0xd7, 0x7b,
0x73, 0xed, 0x4f, 0xf7, 0xdc, 0xd0, 0x47, 0x75, 0xb8, 0xb0, 0xdf, 0xe5, 0xa4, 0x7a, 0xe3, 0x17,
0xd0, 0xb8, 0x68, 0xf7, 0x87, 0xc4, 0x60, 0xe3, 0x2e, 0xd4, 0x12, 0x3b, 0xde, 0xb5, 0xb0, 0x9a,
0x0d, 0xde, 0x9f, 0x73, 0x50, 0x36, 0xb7, 0x8a, 0xdd, 0x85, 0xda, 0x54, 0x7a, 0x2e, 0x1a, 0x10,
0xb7, 0x68, 0x9f, 0xa6, 0x97, 0xae, 0xf5, 0x20, 0x96, 0x19, 0xaf, 0xa6, 0x5c, 0x4c, 0x32, 0x3f,
0x18, 0xcb, 0xf8, 0x16, 0xac, 0xa7, 0x8b, 0xfa, 0xc1, 0x58, 0x72, 0x23, 0xdc, 0xb8, 0x0f, 0xeb,
0xcb, 0x2a, 0x2e, 0xb1, 0xf3, 0xfa, 0x72, 0xba, 0x52, 0x5d, 0x4e, 0x16, 0x65, 0xcd, 0xbe, 0x0b,
0xb5, 0x04, 0x67, 0xbb, 0x6f, 0x1a, 0xbe, 0x9a, 0x5d, 0x99, 0xb1, 0xd5, 0x99, 0x02, 0xa4, 0xa6,
0x61, 0xb1, 0xc2, 0x5e, 0x30, 0x70, 0x67, 0x71, 0x93, 0x95, 0xcc, 0xe9, 0xdb, 0xe6, 0x6a, 0x97,
0x4c, 0x59, 0xe5, 0x34, 0x66, 0x2d, 0x80, 0x51, 0x72, 0x61, 0xdf, 0x72, 0x8d, 0x33, 0x0c, 0x67,
0x00, 0xd5, 0xd8, 0x08, 0xb6, 0x0d, 0xf5, 0xc8, 0xee, 0x8c, 0x9d, 0x0f, 0x6e, 0x57, 0xe2, 0x59,
0x08, 0x3b, 0x18, 0xe5, 0x06, 0x13, 0xb1, 0xd4, 0xc1, 0x70, 0x44, 0xb8, 0x15, 0x38, 0x4f, 0xa1,
0x44, 0x00, 0x5e, 0xb3, 0x48, 0xbb, 0x4a, 0xdb, 0x66, 0xc8, 0x34, 0x07, 0x32, 0xa2, 0x6d, 0xdb,
0x45, 0x4c, 0x44, 0x6e, 0x08, 0xec, 0x06, 0xb6, 0x20, 0x23, 0xeb, 0xd1, 0xcb, 0x78, 0x28, 0x76,
0x7e, 0x0e, 0xd5, 0x18, 0xc6, 0x93, 0x3f, 0xf0, 0x03, 0x61, 0x4d, 0xa4, 0x31, 0x36, 0x91, 0x9d,
0x53, 0x57, 0xb9, 0x9e, 0x16, 0xa6, 0x0d, 0x28, 0xf1, 0x14, 0x70, 0xae, 0x43, 0x3d, 0x73, 0x7b,
0x30, 0xdd, 0x9e, 0x50, 0x18, 0xcd, 0x1d, 0x36, 0x13, 0xe7, 0x25, 0xb6, 0xb8, 0x71, 0xd7, 0xf2,
0x53, 0x80, 0x53, 0xad, 0xc3, 0x67, 0xd4, 0xc6, 0x58, 0xdf, 0xd7, 0x10, 0x21, 0x06, 0xdb, 0x82,
0x3a, 0x4e, 0x22, 0x2b, 0x37, 0xf9, 0x4e, 0x2b, 0x22, 0x43, 0xf8, 0x09, 0xd4, 0xc6, 0xc9, 0xf2,
0x82, 0x0d, 0x5d, 0xbc, 0xfa, 0x53, 0xa8, 0x06, 0xd2, 0xca, 0x4c, 0x57, 0x55, 0x09, 0x24, 0x89,
0x9c, 0x5b, 0xf0, 0x7f, 0x6f, 0xf4, 0xe3, 0xec, 0x13, 0x28, 0x8f, 0xfd, 0xa9, 0xa6, 0xa2, 0x8f,
0x8d, 0x9a, 0x9d, 0x39, 0xff, 0xca, 0x01, 0xa4, 0x91, 0xc5, 0x7c, 0xc5, 0xea, 0x8d, 0x9c, 0x55,
0x53, 0xad, 0xa7, 0x50, 0x9d, 0xd9, 0x3a, 0x60, 0x63, 0x76, 0x6d, 0x39, 0x1b, 0x5a, 0x71, 0x99,
0x30, 0x15, 0x62, 0xdf, 0x56, 0x88, 0x0f, 0xe9, 0x99, 0x93, 0x1d, 0xa8, 0x19, 0xc9, 0xbe, 0x7d,
0x20, 0xbd, 0x68, 0xdc, 0x4a, 0x36, 0xee, 0xc3, 0xda, 0xd2, 0x96, 0xef, 0xf9, 0x4d, 0x48, 0xeb,
0x59, 0xf6, 0x96, 0xdd, 0x86, 0xb2, 0x69, 0x22, 0x31, 0x25, 0x70, 0x64, 0xd5, 0xd0, 0x98, 0x3a,
0x86, 0xe3, 0xf8, 0x05, 0xd2, 0x3f, 0x76, 0xf6, 0xa1, 0x6c, 0x9e, 0x58, 0x6c, 0x07, 0x2a, 0xae,
0x67, 0xae, 0x63, 0xa6, 0x24, 0xa0, 0xf0, 0x80, 0x60, 0x1e, 0x8b, 0x9d, 0xbf, 0xe5, 0x01, 0x52,
0xfc, 0x03, 0xba, 0xd2, 0xaf, 0x61, 0x3d, 0x12, 0x9e, 0x0c, 0x46, 0xae, 0x5a, 0x90, 0xd4, 0x3e,
0x25, 0x2e, 0x5b, 0x72, 0x81, 0x99, 0xe9, 0x50, 0x0b, 0xef, 0xee, 0x50, 0x77, 0xa0, 0xe8, 0xc9,
0x70, 0x61, 0x3f, 0x14, 0x6c, 0xf9, 0x20, 0x1d, 0x19, 0x2e, 0xf0, 0x41, 0x89, 0x0c, 0xd6, 0x82,
0xf2, 0xec, 0x8c, 0x1e, 0x9d, 0xa6, 0x61, 0xbf, 0xba, 0xcc, 0x7d, 0x78, 0x86, 0x63, 0x7c, 0xa2,
0x1a, 0x16, 0xbb, 0x05, 0xa5, 0xd9, 0xd9, 0xc8, 0x57, 0xd4, 0xdb, 0xd6, 0x4d, 0x67, 0x98, 0xa5,
0x77, 0x7d, 0x85, 0x0f, 0x51, 0xe2, 0x30, 0x07, 0xf2, 0x6a, 0xd6, 0xac, 0x10, 0xb3, 0x71, 0xc1,
0x9b, 0xb3, 0xc3, 0x15, 0x9e, 0x57, 0xb3, 0x76, 0x15, 0xca, 0xc6, 0xaf, 0xce, 0x1f, 0x0b, 0xb0,
0xbe, 0x6c, 0x25, 0xe6, 0x41, 0xa4, 0xbc, 0x38, 0x0f, 0x22, 0xe5, 0x25, 0xcd, 0x7b, 0x3e, 0xd3,
0xbc, 0x3b, 0x50, 0x92, 0x2f, 0x02, 0xa1, 0xb2, 0xaf, 0xeb, 0xce, 0xa9, 0x7c, 0x11, 0x60, 0x9b,
0x6a, 0x44, 0x4b, 0x5d, 0x5f, 0xc9, 0x76, 0x7d, 0x37, 0x60, 0x6d, 0x2c, 0xa7, 0x53, 0xf9, 0x62,
0xb8, 0x98, 0x4d, 0xfd, 0xe0, 0xcc, 0xb6, 0x7e, 0xcb, 0x20, 0xdb, 0x81, 0x2b, 0x23, 0x5f, 0xa1,
0x39, 0x1d, 0x19, 0x68, 0x11, 0xd0, 0x7b, 0x05, 0x79, 0x17, 0x61, 0xf6, 0x0d, 0x6c, 0xbb, 0x5a,
0x8b, 0x59, 0xa8, 0x1f, 0x07, 0xa1, 0xeb, 0x9d, 0x75, 0xa5, 0x47, 0x77, 0x76, 0x16, 0xba, 0xda,
0x3f, 0xf1, 0xa7, 0xf8, 0x34, 0xab, 0xd0, 0xd2, 0x77, 0xf2, 0xd8, 0xe7, 0xb0, 0xee, 0x29, 0xe1,
0x6a, 0xd1, 0x15, 0x91, 0x3e, 0x76, 0xf5, 0x69, 0xb3, 0x4a, 0x2b, 0x2f, 0xa0, 0x78, 0x06, 0x17,
0xad, 0x7d, 0xea, 0x4f, 0x47, 0x9e, 0xab, 0x46, 0xcd, 0x9a, 0x39, 0xc3, 0x12, 0xc8, 0x5a, 0xc0,
0x08, 0xe8, 0xcd, 0x42, 0xbd, 0x48, 0xa8, 0x40, 0xd4, 0x4b, 0x24, 0x58, 0x38, 0xb5, 0x3f, 0x13,
0x91, 0x76, 0x67, 0x21, 0xfd, 0x2b, 0x50, 0xe0, 0x29, 0xe0, 0x7c, 0x9b, 0x83, 0xc6, 0xc5, 0x14,
0x41, 0x07, 0x87, 0x68, 0xa6, 0xbd, 0x6c, 0x38, 0x4e, 0x9c, 0x9e, 0xcf, 0x38, 0x3d, 0xfe, 0x42,
0x15, 0x32, 0x5f, 0xa8, 0x24, 0x80, 0xc5, 0xb7, 0x07, 0x70, 0xc9, 0xa4, 0xd2, 0x45, 0x93, 0x7e,
0x97, 0x83, 0x2b, 0x17, 0xd2, 0xf0, 0xbd, 0x2d, 0xda, 0x86, 0xfa, 0xcc, 0x3d, 0x13, 0xc7, 0xae,
0xa2, 0xe0, 0x16, 0x4c, 0x0b, 0x97, 0x81, 0xfe, 0x0b, 0xf6, 0x05, 0xb0, 0x9a, 0xcd, 0xfd, 0x4b,
0x6d, 0x8b, 0x43, 0x79, 0x24, 0xf5, 0x3d, 0x39, 0xb7, 0x5f, 0xbf, 0x38, 0x94, 0x31, 0xf8, 0x66,
0xc0, 0x0b, 0x97, 0x04, 0xdc, 0x39, 0x82, 0x6a, 0x6c, 0x20, 0xdb, 0xb2, 0x4f, 0xf5, 0x5c, 0xfa,
0x97, 0xd1, 0xe3, 0x48, 0x28, 0xb4, 0xdd, 0xbc, 0xdb, 0x3f, 0x83, 0xd2, 0x44, 0xc9, 0x79, 0x68,
0x6b, 0xeb, 0x12, 0xc3, 0x48, 0x9c, 0x21, 0x54, 0x2c, 0xc2, 0x76, 0xa1, 0x7c, 0xb2, 0x38, 0x8a,
0x9b, 0x0f, 0x7b, 0xb1, 0x71, 0x3e, 0xb2, 0x0c, 0xac, 0x16, 0x86, 0xc1, 0xae, 0x42, 0xf1, 0x64,
0xd1, 0xef, 0x9a, 0x07, 0x19, 0xd6, 0x1c, 0x9c, 0xb5, 0xcb, 0xc6, 0x20, 0xe7, 0x01, 0xac, 0x66,
0xd7, 0xa1, 0x53, 0x32, 0x4d, 0x0d, 0x8d, 0xd3, 0xe2, 0x9a, 0x7f, 0x47, 0x71, 0xdd, 0xdd, 0x81,
0x8a, 0xfd, 0x53, 0x84, 0xd5, 0xa0, 0xf4, 0xf8, 0x68, 0xd8, 0x7b, 0xd4, 0x58, 0x61, 0x55, 0x28,
0x1e, 0x0e, 0x86, 0x8f, 0x1a, 0x39, 0x1c, 0x1d, 0x0d, 0x8e, 0x7a, 0x8d, 0xfc, 0xee, 0x4d, 0x58,
0xcd, 0xfe, 0x2d, 0xc2, 0xea, 0x50, 0x19, 0x1e, 0x1c, 0x75, 0xdb, 0x83, 0x5f, 0x35, 0x56, 0xd8,
0x2a, 0x54, 0xfb, 0x47, 0xc3, 0x5e, 0xe7, 0x31, 0xef, 0x35, 0x72, 0xbb, 0xbf, 0x84, 0x5a, 0xf2,
0x72, 0x47, 0x0d, 0xed, 0xfe, 0x51, 0xb7, 0xb1, 0xc2, 0x00, 0xca, 0xc3, 0x5e, 0x87, 0xf7, 0x50,
0x6f, 0x05, 0x0a, 0xc3, 0xe1, 0x61, 0x23, 0x8f, 0xbb, 0x76, 0x0e, 0x3a, 0x87, 0xbd, 0x46, 0x01,
0x87, 0x8f, 0x1e, 0x1e, 0xdf, 0x1b, 0x36, 0x8a, 0xbb, 0x5f, 0xc2, 0x95, 0x0b, 0x2f, 0x67, 0x5a,
0x7d, 0x78, 0xc0, 0x7b, 0xa8, 0xa9, 0x0e, 0x95, 0x63, 0xde, 0x7f, 0x72, 0xf0, 0xa8, 0xd7, 0xc8,
0xa1, 0xe0, 0xc1, 0xa0, 0x73, 0xbf, 0xd7, 0x6d, 0xe4, 0xdb, 0xd7, 0xbe, 0x7b, 0xb5, 0x99, 0xfb,
0xfe, 0xd5, 0x66, 0xee, 0x87, 0x57, 0x9b, 0xb9, 0x7f, 0xbe, 0xda, 0xcc, 0x7d, 0xfb, 0x7a, 0x73,
0xe5, 0xfb, 0xd7, 0x9b, 0x2b, 0x3f, 0xbc, 0xde, 0x5c, 0x39, 0x29, 0xd3, 0x9f, 0x94, 0x5f, 0xfc,
0x3b, 0x00, 0x00, 0xff, 0xff, 0x7e, 0x60, 0x46, 0x7d, 0xe4, 0x14, 0x00, 0x00,
// 2217 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xcd, 0x6f, 0x1b, 0xc7,
0x15, 0x17, 0xbf, 0xc9, 0x47, 0x49, 0x66, 0x27, 0x4e, 0xc2, 0xa8, 0xae, 0xa4, 0x6c, 0xdc, 0x40,
0x96, 0x6d, 0x0a, 0x50, 0x80, 0x38, 0x08, 0x8a, 0xa2, 0xe2, 0x87, 0x21, 0xc6, 0xb6, 0x28, 0x0c,
0xfd, 0xd1, 0x9b, 0xb1, 0x5a, 0x0e, 0xa9, 0x85, 0xc8, 0x9d, 0xc5, 0xec, 0xd0, 0x16, 0x2f, 0x3d,
0xf8, 0x2f, 0x08, 0x50, 0xa0, 0xb7, 0x16, 0xe8, 0xa5, 0x7f, 0x41, 0xaf, 0x3d, 0x16, 0xc8, 0x31,
0x87, 0x1e, 0x82, 0x1e, 0xd2, 0xc2, 0xbe, 0xf7, 0x3f, 0x28, 0x50, 0xbc, 0x37, 0xb3, 0x1f, 0x94,
0x65, 0xd8, 0x46, 0x8b, 0x9e, 0x76, 0xe6, 0xbd, 0xdf, 0xbc, 0x79, 0xf3, 0xbe, 0xe6, 0xcd, 0x42,
0x4d, 0x86, 0x51, 0x2b, 0x54, 0x52, 0x4b, 0x96, 0x0f, 0x4f, 0x36, 0x6e, 0x4f, 0x7c, 0x7d, 0x3a,
0x3f, 0x69, 0x79, 0x72, 0xb6, 0x37, 0x91, 0x13, 0xb9, 0x47, 0xac, 0x93, 0xf9, 0x98, 0x66, 0x34,
0xa1, 0x91, 0x59, 0xe2, 0xfc, 0x31, 0x0f, 0xf9, 0x41, 0xc8, 0x3e, 0x85, 0xb2, 0x1f, 0x84, 0x73,
0x1d, 0x35, 0x73, 0xdb, 0x85, 0x9d, 0xfa, 0x7e, 0xad, 0x15, 0x9e, 0xb4, 0xfa, 0x48, 0xe1, 0x96,
0xc1, 0xb6, 0xa1, 0x28, 0xce, 0x85, 0xd7, 0xcc, 0x6f, 0xe7, 0x76, 0xea, 0xfb, 0x80, 0x80, 0xde,
0xb9, 0xf0, 0x06, 0xe1, 0xe1, 0x0a, 0x27, 0x0e, 0xfb, 0x1c, 0xca, 0x91, 0x9c, 0x2b, 0x4f, 0x34,
0x0b, 0x84, 0x59, 0x45, 0xcc, 0x90, 0x28, 0x84, 0xb2, 0x5c, 0x94, 0x34, 0xf6, 0xa7, 0xa2, 0x59,
0x4c, 0x25, 0xdd, 0xf5, 0xa7, 0x06, 0x43, 0x1c, 0xf6, 0x19, 0x94, 0x4e, 0xe6, 0xfe, 0x74, 0xd4,
0x2c, 0x11, 0xa4, 0x8e, 0x90, 0x36, 0x12, 0x08, 0x63, 0x78, 0x6c, 0x07, 0xaa, 0xe1, 0xd4, 0xd5,
0x63, 0xa9, 0x66, 0x4d, 0x48, 0x37, 0x3c, 0xb6, 0x34, 0x9e, 0x70, 0xd9, 0x1d, 0xa8, 0x7b, 0x32,
0x88, 0xb4, 0x72, 0xfd, 0x40, 0x47, 0xcd, 0x3a, 0x81, 0x3f, 0x44, 0xf0, 0x13, 0xa9, 0xce, 0x84,
0xea, 0xa4, 0x4c, 0x9e, 0x45, 0xb6, 0x8b, 0x90, 0x97, 0xa1, 0xf3, 0xbb, 0x1c, 0x54, 0x63, 0xa9,
0xcc, 0x81, 0xd5, 0x03, 0xe5, 0x9d, 0xfa, 0x5a, 0x78, 0x7a, 0xae, 0x44, 0x33, 0xb7, 0x9d, 0xdb,
0xa9, 0xf1, 0x25, 0x1a, 0x5b, 0x87, 0xfc, 0x60, 0x48, 0x86, 0xaa, 0xf1, 0xfc, 0x60, 0xc8, 0x9a,
0x50, 0x79, 0xec, 0x2a, 0xdf, 0x0d, 0x34, 0x59, 0xa6, 0xc6, 0xe3, 0x29, 0xbb, 0x06, 0xb5, 0xc1,
0xf0, 0xb1, 0x50, 0x91, 0x2f, 0x03, 0xb2, 0x47, 0x8d, 0xa7, 0x04, 0xb6, 0x09, 0x30, 0x18, 0xde,
0x15, 0x2e, 0x0a, 0x8d, 0x9a, 0xa5, 0xed, 0xc2, 0x4e, 0x8d, 0x67, 0x28, 0xce, 0x6f, 0xa0, 0x44,
0x3e, 0x62, 0xdf, 0x40, 0x79, 0xe4, 0x4f, 0x44, 0xa4, 0x8d, 0x3a, 0xed, 0xfd, 0xef, 0x7e, 0xdc,
0x5a, 0xf9, 0xfb, 0x8f, 0x5b, 0xbb, 0x99, 0x60, 0x90, 0xa1, 0x08, 0x3c, 0x19, 0x68, 0xd7, 0x0f,
0x84, 0x8a, 0xf6, 0x26, 0xf2, 0xb6, 0x59, 0xd2, 0xea, 0xd2, 0x87, 0x5b, 0x09, 0xec, 0x06, 0x94,
0xfc, 0x60, 0x24, 0xce, 0x49, 0xff, 0x42, 0xfb, 0x03, 0x2b, 0xaa, 0x3e, 0x98, 0xeb, 0x70, 0xae,
0xfb, 0xc8, 0xe2, 0x06, 0xe1, 0xfc, 0x21, 0x07, 0x65, 0x13, 0x03, 0xec, 0x1a, 0x14, 0x67, 0x42,
0xbb, 0xb4, 0x7f, 0x7d, 0xbf, 0x8a, 0xb6, 0x7d, 0x20, 0xb4, 0xcb, 0x89, 0x8a, 0xe1, 0x35, 0x93,
0x73, 0xb4, 0x7d, 0x3e, 0x0d, 0xaf, 0x07, 0x48, 0xe1, 0x96, 0xc1, 0x7e, 0x0e, 0x95, 0x40, 0xe8,
0xe7, 0x52, 0x9d, 0x91, 0x8d, 0xd6, 0x8d, 0xd3, 0x8f, 0x84, 0x7e, 0x20, 0x47, 0x82, 0xc7, 0x3c,
0x76, 0x0b, 0xaa, 0x91, 0xf0, 0xe6, 0xca, 0xd7, 0x0b, 0xb2, 0xd7, 0xfa, 0x7e, 0x83, 0xa2, 0xcc,
0xd2, 0x08, 0x9c, 0x20, 0x9c, 0xbf, 0xe6, 0xa0, 0x88, 0x6a, 0x30, 0x06, 0x45, 0x57, 0x4d, 0x4c,
0x74, 0xd7, 0x38, 0x8d, 0x59, 0x03, 0x0a, 0x22, 0x78, 0x46, 0x1a, 0xd5, 0x38, 0x0e, 0x91, 0xe2,
0x3d, 0x1f, 0x59, 0x1f, 0xe1, 0x10, 0xd7, 0xcd, 0x23, 0xa1, 0xac, 0x6b, 0x68, 0xcc, 0x6e, 0x40,
0x2d, 0x54, 0xf2, 0x7c, 0xf1, 0x14, 0x57, 0x97, 0x32, 0x81, 0x87, 0xc4, 0x5e, 0xf0, 0x8c, 0x57,
0x43, 0x3b, 0x62, 0xbb, 0x00, 0xe2, 0x5c, 0x2b, 0xf7, 0x50, 0x46, 0x3a, 0x6a, 0x96, 0xe9, 0xec,
0x14, 0xef, 0x48, 0xe8, 0x1f, 0xf3, 0x0c, 0x97, 0x6d, 0x40, 0xf5, 0x54, 0x46, 0x3a, 0x70, 0x67,
0xa2, 0x59, 0xa1, 0xed, 0x92, 0xb9, 0xf3, 0xaf, 0x3c, 0x94, 0xc8, 0x5c, 0x6c, 0x07, 0xbd, 0x13,
0xce, 0x8d, 0xa3, 0x0b, 0x6d, 0x66, 0xbd, 0x03, 0x14, 0x07, 0x89, 0x73, 0x30, 0x26, 0x36, 0xd0,
0x52, 0x53, 0xe1, 0x69, 0xa9, 0x6c, 0x28, 0x26, 0x73, 0x3c, 0xd6, 0x08, 0xa3, 0xc5, 0x9c, 0x94,
0xc6, 0xec, 0x26, 0x94, 0x25, 0xb9, 0x98, 0x0e, 0xfb, 0x06, 0xc7, 0x5b, 0x08, 0x0a, 0x57, 0xc2,
0x1d, 0xc9, 0x60, 0xba, 0x20, 0x13, 0x54, 0x79, 0x32, 0x67, 0x37, 0xa1, 0x46, 0x3e, 0x7d, 0xb8,
0x08, 0x45, 0xb3, 0x4c, 0x3e, 0x5a, 0x4b, 0xfc, 0x8d, 0x44, 0x9e, 0xf2, 0x31, 0x89, 0x3d, 0xd7,
0x3b, 0x15, 0x83, 0x50, 0x37, 0xaf, 0xa6, 0xb6, 0xec, 0x58, 0x1a, 0x4f, 0xb8, 0x28, 0x36, 0x12,
0x9e, 0x12, 0x1a, 0xa1, 0x1f, 0x12, 0x74, 0xcd, 0xba, 0xde, 0x10, 0x79, 0xca, 0x67, 0x0e, 0x94,
0x87, 0xc3, 0x43, 0x44, 0x7e, 0x94, 0x16, 0x19, 0x43, 0xe1, 0x96, 0x63, 0xce, 0x10, 0xcd, 0xa7,
0xba, 0xdf, 0x6d, 0x7e, 0x6c, 0x0c, 0x14, 0xcf, 0x9d, 0x3e, 0x54, 0x63, 0x15, 0x30, 0x9b, 0xfb,
0x5d, 0x9b, 0xe7, 0xf9, 0x7e, 0x97, 0xdd, 0x86, 0x4a, 0x74, 0xea, 0x2a, 0x3f, 0x98, 0x90, 0x5d,
0xd7, 0xf7, 0x3f, 0x48, 0x34, 0x1e, 0x1a, 0x3a, 0xee, 0x12, 0x63, 0x1c, 0x09, 0xb5, 0x44, 0xc5,
0xd7, 0x64, 0x35, 0xa0, 0x30, 0xf7, 0x47, 0x24, 0x67, 0x8d, 0xe3, 0x10, 0x29, 0x13, 0xdf, 0xc4,
0xe0, 0x1a, 0xc7, 0x21, 0x3a, 0x6b, 0x26, 0x47, 0xa6, 0x5c, 0xae, 0x71, 0x1a, 0xa3, 0xee, 0x32,
0xd4, 0xbe, 0x0c, 0xdc, 0x69, 0x6c, 0xff, 0x78, 0xee, 0x4c, 0xe3, 0xb3, 0xff, 0x5f, 0x76, 0xfb,
0x6d, 0x0e, 0xaa, 0x71, 0x8d, 0xc7, 0x82, 0xe5, 0x8f, 0x44, 0xa0, 0xfd, 0xb1, 0x2f, 0x94, 0xdd,
0x38, 0x43, 0x61, 0xb7, 0xa1, 0xe4, 0x6a, 0xad, 0xe2, 0x32, 0xf0, 0x71, 0xf6, 0x82, 0x68, 0x1d,
0x20, 0xa7, 0x17, 0x68, 0xb5, 0xe0, 0x06, 0xb5, 0xf1, 0x15, 0x40, 0x4a, 0x44, 0x5d, 0xcf, 0xc4,
0xc2, 0x4a, 0xc5, 0x21, 0xbb, 0x0a, 0xa5, 0x67, 0xee, 0x74, 0x2e, 0x6c, 0x7c, 0x9b, 0xc9, 0xd7,
0xf9, 0xaf, 0x72, 0xce, 0x5f, 0xf2, 0x50, 0xb1, 0x17, 0x06, 0xbb, 0x05, 0x15, 0xba, 0x30, 0xac,
0x46, 0x97, 0x27, 0x4d, 0x0c, 0x61, 0x7b, 0xc9, 0x4d, 0x98, 0xd1, 0xd1, 0x8a, 0x32, 0x37, 0xa2,
0xd5, 0x31, 0xbd, 0x17, 0x0b, 0x23, 0x31, 0xb6, 0x57, 0xde, 0x3a, 0xa2, 0xbb, 0x62, 0xec, 0x07,
0x3e, 0xda, 0x87, 0x23, 0x8b, 0xdd, 0x8a, 0x4f, 0x5d, 0x24, 0x89, 0x1f, 0x65, 0x25, 0xbe, 0x7e,
0xe8, 0x3e, 0xd4, 0x33, 0xdb, 0x5c, 0x72, 0xea, 0xeb, 0xd9, 0x53, 0xdb, 0x2d, 0x49, 0x9c, 0xb9,
0xaf, 0x53, 0x2b, 0xfc, 0x17, 0xf6, 0xfb, 0x12, 0x20, 0x15, 0xf9, 0xee, 0x45, 0xc7, 0x79, 0x51,
0x00, 0x18, 0x84, 0x58, 0x72, 0x47, 0x2e, 0xd5, 0xfd, 0x55, 0x7f, 0x12, 0x48, 0x25, 0x9e, 0x52,
0x1a, 0xd3, 0xfa, 0x2a, 0xaf, 0x1b, 0x1a, 0x65, 0x0c, 0x3b, 0x80, 0xfa, 0x48, 0x44, 0x9e, 0xf2,
0x29, 0xa0, 0xac, 0xd1, 0xb7, 0xf0, 0x4c, 0xa9, 0x9c, 0x56, 0x37, 0x45, 0x18, 0x5b, 0x65, 0xd7,
0xb0, 0x7d, 0x58, 0x15, 0xe7, 0xa1, 0x54, 0xda, 0xee, 0x62, 0xfa, 0x8a, 0x2b, 0xa6, 0x43, 0x41,
0x3a, 0xed, 0xc4, 0xeb, 0x22, 0x9d, 0x30, 0x17, 0x8a, 0x9e, 0x1b, 0x9a, 0x4b, 0xb5, 0xbe, 0xdf,
0xbc, 0xb0, 0x5f, 0xc7, 0x0d, 0x8d, 0xd1, 0xda, 0x5f, 0xe0, 0x59, 0x5f, 0xfc, 0x63, 0xeb, 0x66,
0xe6, 0x26, 0x9d, 0xc9, 0x93, 0xc5, 0x1e, 0xc5, 0xcb, 0x99, 0xaf, 0xf7, 0xe6, 0xda, 0x9f, 0xee,
0xb9, 0xa1, 0x8f, 0xe2, 0x70, 0x61, 0xbf, 0xcb, 0x49, 0xf4, 0xc6, 0x2f, 0xa1, 0x71, 0x51, 0xef,
0xf7, 0xf1, 0xc1, 0xc6, 0x1d, 0xa8, 0x25, 0x7a, 0xbc, 0x6d, 0x61, 0x35, 0xeb, 0xbc, 0x3f, 0xe7,
0xa0, 0x6c, 0xb2, 0x8a, 0xdd, 0x81, 0xda, 0x54, 0x7a, 0x2e, 0x2a, 0x10, 0xb7, 0x76, 0x9f, 0xa4,
0x49, 0xd7, 0xba, 0x1f, 0xf3, 0x8c, 0x55, 0x53, 0x2c, 0x06, 0x99, 0x1f, 0x8c, 0x65, 0x9c, 0x05,
0xeb, 0xe9, 0xa2, 0x7e, 0x30, 0x96, 0xdc, 0x30, 0x37, 0xee, 0xc1, 0xfa, 0xb2, 0x88, 0x4b, 0xf4,
0xfc, 0x6c, 0x39, 0x5c, 0xa9, 0x66, 0x27, 0x8b, 0xb2, 0x6a, 0xdf, 0x81, 0x5a, 0x42, 0x67, 0xbb,
0xaf, 0x2b, 0xbe, 0x9a, 0x5d, 0x99, 0xd1, 0xd5, 0x99, 0x02, 0xa4, 0xaa, 0x61, 0xb1, 0xc2, 0x1e,
0x92, 0xee, 0x51, 0xa3, 0x46, 0x32, 0xa7, 0x7b, 0xcf, 0xd5, 0x2e, 0xa9, 0xb2, 0xca, 0x69, 0xcc,
0x5a, 0x00, 0xa3, 0x24, 0x61, 0xdf, 0x90, 0xc6, 0x19, 0x84, 0x33, 0x80, 0x6a, 0xac, 0x04, 0xdb,
0x86, 0x7a, 0x64, 0x77, 0xc6, 0x8e, 0x09, 0xb7, 0x2b, 0xf1, 0x2c, 0x09, 0x3b, 0x1f, 0xe5, 0x06,
0x13, 0xb1, 0xd4, 0xf9, 0x70, 0xa4, 0x70, 0xcb, 0x70, 0x9e, 0x40, 0x89, 0x08, 0x98, 0x66, 0x91,
0x76, 0x95, 0xb6, 0x4d, 0x94, 0x69, 0x2a, 0x64, 0x44, 0xdb, 0xb6, 0x8b, 0x18, 0x88, 0xdc, 0x00,
0xd8, 0x75, 0x6c, 0x5d, 0x46, 0xd6, 0xa2, 0x97, 0xe1, 0x90, 0xed, 0xfc, 0x02, 0xaa, 0x31, 0x19,
0x4f, 0x7e, 0xdf, 0x0f, 0x84, 0x55, 0x91, 0xc6, 0xd8, 0x7c, 0x76, 0x4e, 0x5d, 0xe5, 0x7a, 0x5a,
0x98, 0x16, 0xa1, 0xc4, 0x53, 0x82, 0xf3, 0x19, 0xd4, 0x33, 0xd9, 0x83, 0xe1, 0xf6, 0x98, 0xdc,
0x68, 0x72, 0xd8, 0x4c, 0x9c, 0x17, 0xd8, 0x1a, 0xc7, 0xdd, 0xce, 0xcf, 0x00, 0x4e, 0xb5, 0x0e,
0x9f, 0x52, 0xfb, 0x63, 0x6d, 0x5f, 0x43, 0x0a, 0x21, 0xd8, 0x16, 0xd4, 0x71, 0x12, 0x59, 0xbe,
0x89, 0x77, 0x5a, 0x11, 0x19, 0xc0, 0x4f, 0xa1, 0x36, 0x4e, 0x96, 0x17, 0xac, 0xeb, 0xe2, 0xd5,
0x9f, 0x40, 0x35, 0x90, 0x96, 0x67, 0xba, 0xb1, 0x4a, 0x20, 0x89, 0xe5, 0xdc, 0x84, 0x9f, 0xbc,
0xd6, 0xc7, 0xb3, 0x8f, 0xa0, 0x3c, 0xf6, 0xa7, 0x9a, 0x8a, 0x3e, 0x36, 0x78, 0x76, 0xe6, 0xfc,
0x3b, 0x07, 0x90, 0x7a, 0x16, 0xe3, 0x15, 0xab, 0x37, 0x62, 0x56, 0x4d, 0xb5, 0x9e, 0x42, 0x75,
0x66, 0xeb, 0x80, 0xf5, 0xd9, 0xb5, 0xe5, 0x68, 0x68, 0xc5, 0x65, 0xc2, 0x54, 0x88, 0x7d, 0x5b,
0x21, 0xde, 0xa7, 0xd7, 0x4e, 0x76, 0xa0, 0x46, 0x25, 0xfb, 0x66, 0x82, 0x34, 0xd1, 0xb8, 0xe5,
0x6c, 0xdc, 0x83, 0xb5, 0xa5, 0x2d, 0xdf, 0xf1, 0x4e, 0x48, 0xeb, 0x59, 0x36, 0xcb, 0x6e, 0x41,
0xd9, 0x34, 0x9f, 0x18, 0x12, 0x38, 0xb2, 0x62, 0x68, 0x4c, 0x1d, 0xc3, 0x71, 0xfc, 0x72, 0xe9,
0x1f, 0x3b, 0xfb, 0x50, 0x36, 0x4f, 0x33, 0xb6, 0x03, 0x15, 0xd7, 0x33, 0xe9, 0x98, 0x29, 0x09,
0xc8, 0x3c, 0x20, 0x32, 0x8f, 0xd9, 0xce, 0xdf, 0xf2, 0x00, 0x29, 0xfd, 0x3d, 0x3a, 0xd6, 0xaf,
0x61, 0x3d, 0x12, 0x9e, 0x0c, 0x46, 0xae, 0x5a, 0x10, 0xd7, 0x3e, 0x41, 0x2e, 0x5b, 0x72, 0x01,
0x99, 0xe9, 0x5e, 0x0b, 0x6f, 0xef, 0x5e, 0x77, 0xa0, 0xe8, 0xc9, 0x70, 0x61, 0x2f, 0x0a, 0xb6,
0x7c, 0x90, 0x8e, 0x0c, 0x17, 0xf8, 0x10, 0x45, 0x04, 0x6b, 0x41, 0x79, 0x76, 0x46, 0x8f, 0x55,
0xd3, 0xe8, 0x5f, 0x5d, 0xc6, 0x3e, 0x38, 0xc3, 0x31, 0x3e, 0x6d, 0x0d, 0x8a, 0xdd, 0x84, 0xd2,
0xec, 0x6c, 0xe4, 0x2b, 0xea, 0x7b, 0xeb, 0xa6, 0x33, 0xcc, 0xc2, 0xbb, 0xbe, 0xc2, 0x07, 0x2c,
0x61, 0x98, 0x03, 0x79, 0x35, 0xa3, 0x5e, 0xbf, 0x6e, 0x5e, 0x31, 0x19, 0x6b, 0xce, 0x0e, 0x57,
0x78, 0x5e, 0xcd, 0xda, 0x55, 0x28, 0x1b, 0xbb, 0x3a, 0x7f, 0x2a, 0xc0, 0xfa, 0xb2, 0x96, 0x18,
0x07, 0x91, 0xf2, 0xe2, 0x38, 0x88, 0x94, 0x97, 0x34, 0xf6, 0xf9, 0x4c, 0x63, 0xef, 0x40, 0x49,
0x3e, 0x0f, 0x84, 0xca, 0xbe, 0xca, 0x3b, 0xa7, 0xf2, 0x79, 0x80, 0x6d, 0xaa, 0x61, 0x2d, 0x75,
0x7d, 0x25, 0xdb, 0xf5, 0x5d, 0x87, 0xb5, 0xb1, 0x9c, 0x4e, 0xe5, 0xf3, 0xe1, 0x62, 0x36, 0xf5,
0x83, 0x33, 0xdb, 0xfa, 0x2d, 0x13, 0xd9, 0x0e, 0x5c, 0x19, 0xf9, 0x0a, 0xd5, 0xe9, 0xc8, 0x40,
0x8b, 0x80, 0xde, 0x39, 0x88, 0xbb, 0x48, 0x66, 0xdf, 0xc0, 0xb6, 0xab, 0xb5, 0x98, 0x85, 0xfa,
0x51, 0x10, 0xba, 0xde, 0x59, 0x57, 0x7a, 0x94, 0xb3, 0xb3, 0xd0, 0xd5, 0xfe, 0x89, 0x3f, 0xc5,
0x27, 0x5d, 0x85, 0x96, 0xbe, 0x15, 0xc7, 0x3e, 0x87, 0x75, 0x4f, 0x09, 0x57, 0x8b, 0xae, 0x88,
0xf4, 0xb1, 0xab, 0x4f, 0x9b, 0x55, 0x5a, 0x79, 0x81, 0x8a, 0x67, 0x70, 0x51, 0xdb, 0x27, 0xfe,
0x74, 0xe4, 0xb9, 0x6a, 0xd4, 0xac, 0x99, 0x33, 0x2c, 0x11, 0x59, 0x0b, 0x18, 0x11, 0x7a, 0xb3,
0x50, 0x2f, 0x12, 0x28, 0x10, 0xf4, 0x12, 0x0e, 0x16, 0x4e, 0xed, 0xcf, 0x44, 0xa4, 0xdd, 0x59,
0x48, 0x7f, 0x13, 0x0a, 0x3c, 0x25, 0x38, 0xdf, 0xe6, 0xa0, 0x71, 0x31, 0x44, 0xd0, 0xc0, 0x21,
0xaa, 0x69, 0x93, 0x0d, 0xc7, 0x89, 0xd1, 0xf3, 0x19, 0xa3, 0xc7, 0x37, 0x54, 0x21, 0x73, 0x43,
0x25, 0x0e, 0x2c, 0xbe, 0xd9, 0x81, 0x4b, 0x2a, 0x95, 0x2e, 0xaa, 0xf4, 0xfb, 0x1c, 0x5c, 0xb9,
0x10, 0x86, 0xef, 0xac, 0xd1, 0x36, 0xd4, 0x67, 0xee, 0x99, 0x38, 0x76, 0x15, 0x39, 0xb7, 0x60,
0x5a, 0xb8, 0x0c, 0xe9, 0x7f, 0xa0, 0x5f, 0x00, 0xab, 0xd9, 0xd8, 0xbf, 0x54, 0xb7, 0xd8, 0x95,
0x47, 0x52, 0xdf, 0x95, 0x73, 0x7b, 0xfb, 0xc5, 0xae, 0x8c, 0x89, 0xaf, 0x3b, 0xbc, 0x70, 0x89,
0xc3, 0x9d, 0x23, 0xa8, 0xc6, 0x0a, 0xb2, 0x2d, 0xfb, 0xc4, 0xcf, 0xa5, 0xbf, 0x9a, 0x1e, 0x45,
0x42, 0xa1, 0xee, 0xe6, 0xbd, 0xff, 0x29, 0x94, 0x26, 0x4a, 0xce, 0x43, 0x5b, 0x5b, 0x97, 0x10,
0x86, 0xe3, 0x0c, 0xa1, 0x62, 0x29, 0x6c, 0x17, 0xca, 0x27, 0x8b, 0xa3, 0xb8, 0xf9, 0xb0, 0x89,
0x8d, 0xf3, 0x91, 0x45, 0x60, 0xb5, 0x30, 0x08, 0x76, 0x15, 0x8a, 0x27, 0x8b, 0x7e, 0xd7, 0x3c,
0xc8, 0xb0, 0xe6, 0xe0, 0xac, 0x5d, 0x36, 0x0a, 0x39, 0xf7, 0x61, 0x35, 0xbb, 0x0e, 0x8d, 0x92,
0x69, 0x6a, 0x68, 0x9c, 0x16, 0xd7, 0xfc, 0x5b, 0x8a, 0xeb, 0xee, 0x0e, 0x54, 0xec, 0xcf, 0x14,
0x56, 0x83, 0xd2, 0xa3, 0xa3, 0x61, 0xef, 0x61, 0x63, 0x85, 0x55, 0xa1, 0x78, 0x38, 0x18, 0x3e,
0x6c, 0xe4, 0x70, 0x74, 0x34, 0x38, 0xea, 0x35, 0xf2, 0xbb, 0x37, 0x60, 0x35, 0xfb, 0x3b, 0x85,
0xd5, 0xa1, 0x32, 0x3c, 0x38, 0xea, 0xb6, 0x07, 0xbf, 0x6e, 0xac, 0xb0, 0x55, 0xa8, 0xf6, 0x8f,
0x86, 0xbd, 0xce, 0x23, 0xde, 0x6b, 0xe4, 0x76, 0x7f, 0x05, 0xb5, 0xe4, 0x55, 0x8f, 0x12, 0xda,
0xfd, 0xa3, 0x6e, 0x63, 0x85, 0x01, 0x94, 0x87, 0xbd, 0x0e, 0xef, 0xa1, 0xdc, 0x0a, 0x14, 0x86,
0xc3, 0xc3, 0x46, 0x1e, 0x77, 0xed, 0x1c, 0x74, 0x0e, 0x7b, 0x8d, 0x02, 0x0e, 0x1f, 0x3e, 0x38,
0xbe, 0x3b, 0x6c, 0x14, 0x77, 0xbf, 0x84, 0x2b, 0x17, 0x5e, 0xce, 0xb4, 0xfa, 0xf0, 0x80, 0xf7,
0x50, 0x52, 0x1d, 0x2a, 0xc7, 0xbc, 0xff, 0xf8, 0xe0, 0x61, 0xaf, 0x91, 0x43, 0xc6, 0xfd, 0x41,
0xe7, 0x5e, 0xaf, 0xdb, 0xc8, 0xb7, 0xaf, 0x7d, 0xf7, 0x72, 0x33, 0xf7, 0xfd, 0xcb, 0xcd, 0xdc,
0x0f, 0x2f, 0x37, 0x73, 0xff, 0x7c, 0xb9, 0x99, 0xfb, 0xf6, 0xd5, 0xe6, 0xca, 0xf7, 0xaf, 0x36,
0x57, 0x7e, 0x78, 0xb5, 0xb9, 0x72, 0x52, 0xa6, 0x9f, 0x9b, 0x5f, 0xfc, 0x27, 0x00, 0x00, 0xff,
0xff, 0xa4, 0x50, 0x4f, 0x17, 0x1c, 0x15, 0x00, 0x00,
}
func (m *Op) Marshal() (dAtA []byte, err error) {
@ -2784,6 +2802,13 @@ func (m *Meta) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i
var l int
_ = l
if len(m.Hostname) > 0 {
i -= len(m.Hostname)
copy(dAtA[i:], m.Hostname)
i = encodeVarintOps(dAtA, i, uint64(len(m.Hostname)))
i--
dAtA[i] = 0x3a
}
if len(m.ExtraHosts) > 0 {
for iNdEx := len(m.ExtraHosts) - 1; iNdEx >= 0; iNdEx-- {
{
@ -2865,6 +2890,15 @@ func (m *Mount) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i
var l int
_ = l
if len(m.ResultID) > 0 {
i -= len(m.ResultID)
copy(dAtA[i:], m.ResultID)
i = encodeVarintOps(dAtA, i, uint64(len(m.ResultID)))
i--
dAtA[i] = 0x1
i--
dAtA[i] = 0xba
}
if m.SSHOpt != nil {
{
size, err := m.SSHOpt.MarshalToSizedBuffer(dAtA[:i])
@ -4663,6 +4697,10 @@ func (m *Meta) Size() (n int) {
n += 1 + l + sovOps(uint64(l))
}
}
l = len(m.Hostname)
if l > 0 {
n += 1 + l + sovOps(uint64(l))
}
return n
}
@ -4704,6 +4742,10 @@ func (m *Mount) Size() (n int) {
l = m.SSHOpt.Size()
n += 2 + l + sovOps(uint64(l))
}
l = len(m.ResultID)
if l > 0 {
n += 2 + l + sovOps(uint64(l))
}
return n
}
@ -6359,6 +6401,38 @@ func (m *Meta) Unmarshal(dAtA []byte) error {
return err
}
iNdEx = postIndex
case 7:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Hostname", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowOps
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthOps
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthOps
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Hostname = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipOps(dAtA[iNdEx:])
@ -6661,6 +6735,38 @@ func (m *Mount) Unmarshal(dAtA []byte) error {
return err
}
iNdEx = postIndex
case 23:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ResultID", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowOps
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthOps
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthOps
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.ResultID = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipOps(dAtA[iNdEx:])

View File

@ -57,6 +57,7 @@ message Meta {
string user = 4;
ProxyEnv proxy_env = 5;
repeated HostIP extraHosts = 6;
string hostname = 7;
}
enum NetMode {
@ -81,6 +82,7 @@ message Mount {
CacheOpt cacheOpt = 20;
SecretOpt secretOpt = 21;
SSHOpt SSHOpt = 22;
string resultID = 23;
}
// MountType defines a type of a mount from a supported set

View File

@ -33,8 +33,12 @@ func ToGRPC(err error) error {
st = status.New(Code(err), err.Error())
}
if st.Code() != Code(err) {
code := Code(err)
if code == codes.OK {
code = codes.Unknown
}
pb := st.Proto()
pb.Code = int32(Code(err))
pb.Code = int32(code)
st = status.FromProto(pb)
}
@ -96,9 +100,10 @@ func Code(err error) codes.Code {
Unwrap() error
})
if ok {
return Code(wrapped.Unwrap())
if err := wrapped.Unwrap(); err != nil {
return Code(err)
}
}
return status.FromContextError(err).Code()
}
@ -120,7 +125,9 @@ func AsGRPCStatus(err error) (*status.Status, bool) {
Unwrap() error
})
if ok {
return AsGRPCStatus(wrapped.Unwrap())
if err := wrapped.Unwrap(); err != nil {
return AsGRPCStatus(err)
}
}
return nil, false
@ -174,6 +181,10 @@ func FromGRPC(err error) error {
err = d.WrapError(err)
}
if err != nil {
stack.Helper()
}
return stack.Enable(err)
}
@ -182,6 +193,10 @@ type withCode struct {
error
}
func (e *withCode) Code() codes.Code {
return e.code
}
func (e *withCode) Unwrap() error {
return e.error
}

View File

@ -2,27 +2,53 @@ package grpcerrors
import (
"context"
"log"
"os"
"github.com/moby/buildkit/util/stack"
"github.com/pkg/errors"
"google.golang.org/grpc"
)
func UnaryServerInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
resp, err = handler(ctx, req)
oldErr := err
if err != nil {
stack.Helper()
err = ToGRPC(err)
}
if oldErr != nil && err == nil {
logErr := errors.Wrap(err, "invalid grpc error conversion")
if os.Getenv("BUILDKIT_DEBUG_PANIC_ON_ERROR") == "1" {
panic(logErr)
}
log.Printf("%v", logErr)
err = oldErr
}
return resp, err
}
func StreamServerInterceptor(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
return ToGRPC(handler(srv, ss))
err := ToGRPC(handler(srv, ss))
if err != nil {
stack.Helper()
}
return err
}
func UnaryClientInterceptor(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
return FromGRPC(invoker(ctx, method, req, reply, cc, opts...))
err := FromGRPC(invoker(ctx, method, req, reply, cc, opts...))
if err != nil {
stack.Helper()
}
return err
}
func StreamClientInterceptor(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) {
s, err := streamer(ctx, desc, cc, method, opts...)
if err != nil {
stack.Helper()
}
return s, ToGRPC(err)
}

View File

@ -0,0 +1,106 @@
package progresswriter
import (
"context"
"strings"
"sync"
"github.com/moby/buildkit/client"
"golang.org/x/sync/errgroup"
)
type MultiWriter struct {
w Writer
eg *errgroup.Group
once sync.Once
ready chan struct{}
}
func (mw *MultiWriter) WithPrefix(pfx string, force bool) Writer {
in := make(chan *client.SolveStatus)
out := mw.w.Status()
p := &prefixed{
main: mw.w,
in: in,
}
mw.eg.Go(func() error {
mw.once.Do(func() {
close(mw.ready)
})
for {
select {
case v, ok := <-in:
if ok {
if force {
for _, v := range v.Vertexes {
v.Name = addPrefix(pfx, v.Name)
}
}
out <- v
} else {
return nil
}
case <-mw.Done():
return mw.Err()
}
}
})
return p
}
func (mw *MultiWriter) Done() <-chan struct{} {
return mw.w.Done()
}
func (mw *MultiWriter) Err() error {
return mw.w.Err()
}
func (mw *MultiWriter) Status() chan *client.SolveStatus {
return nil
}
type prefixed struct {
main Writer
in chan *client.SolveStatus
}
func (p *prefixed) Done() <-chan struct{} {
return p.main.Done()
}
func (p *prefixed) Err() error {
return p.main.Err()
}
func (p *prefixed) Status() chan *client.SolveStatus {
return p.in
}
func NewMultiWriter(pw Writer) *MultiWriter {
if pw == nil {
return nil
}
eg, _ := errgroup.WithContext(context.TODO())
ready := make(chan struct{})
go func() {
<-ready
eg.Wait()
close(pw.Status())
}()
return &MultiWriter{
w: pw,
eg: eg,
ready: ready,
}
}
func addPrefix(pfx, name string) string {
if strings.HasPrefix(name, "[") {
return "[" + pfx + " " + name[1:]
}
return "[" + pfx + "] " + name
}

View File

@ -0,0 +1,94 @@
package progresswriter
import (
"context"
"os"
"github.com/containerd/console"
"github.com/moby/buildkit/client"
"github.com/moby/buildkit/util/progress/progressui"
"github.com/pkg/errors"
)
type printer struct {
status chan *client.SolveStatus
done <-chan struct{}
err error
}
func (p *printer) Done() <-chan struct{} {
return p.done
}
func (p *printer) Err() error {
return p.err
}
func (p *printer) Status() chan *client.SolveStatus {
if p == nil {
return nil
}
return p.status
}
type tee struct {
Writer
status chan *client.SolveStatus
}
func (t *tee) Status() chan *client.SolveStatus {
return t.status
}
func Tee(w Writer, ch chan *client.SolveStatus) Writer {
st := make(chan *client.SolveStatus)
t := &tee{
status: st,
Writer: w,
}
go func() {
for v := range st {
w.Status() <- v
ch <- v
}
close(w.Status())
close(ch)
}()
return t
}
func NewPrinter(ctx context.Context, out console.File, mode string) (Writer, error) {
statusCh := make(chan *client.SolveStatus)
doneCh := make(chan struct{})
pw := &printer{
status: statusCh,
done: doneCh,
}
if v := os.Getenv("BUILDKIT_PROGRESS"); v != "" && mode == "auto" {
mode = v
}
var c console.Console
switch mode {
case "auto", "tty", "":
if cons, err := console.ConsoleFromFile(out); err == nil {
c = cons
} else {
if mode == "tty" {
return nil, errors.Wrap(err, "failed to get console")
}
}
case "plain":
default:
return nil, errors.Errorf("invalid progress mode %s", mode)
}
go func() {
// not using shared context to not disrupt display but let is finish reporting errors
pw.err = progressui.DisplaySolveStatus(ctx, "", c, out, statusCh)
close(doneCh)
}()
return pw, nil
}

View File

@ -0,0 +1,93 @@
package progresswriter
import (
"time"
"github.com/moby/buildkit/client"
"github.com/moby/buildkit/identity"
"github.com/opencontainers/go-digest"
)
type Logger func(*client.SolveStatus)
type SubLogger interface {
Wrap(name string, fn func() error) error
Log(stream int, dt []byte)
}
func Wrap(name string, l Logger, fn func(SubLogger) error) (err error) {
if l == nil {
return nil
}
dgst := digest.FromBytes([]byte(identity.NewID()))
tm := time.Now()
l(&client.SolveStatus{
Vertexes: []*client.Vertex{{
Digest: dgst,
Name: name,
Started: &tm,
}},
})
defer func() {
tm2 := time.Now()
errMsg := ""
if err != nil {
errMsg = err.Error()
}
l(&client.SolveStatus{
Vertexes: []*client.Vertex{{
Digest: dgst,
Name: name,
Started: &tm,
Completed: &tm2,
Error: errMsg,
}},
})
}()
return fn(&subLogger{dgst, l})
}
type subLogger struct {
dgst digest.Digest
logger Logger
}
func (sl *subLogger) Wrap(name string, fn func() error) (err error) {
tm := time.Now()
sl.logger(&client.SolveStatus{
Statuses: []*client.VertexStatus{{
Vertex: sl.dgst,
ID: name,
Timestamp: time.Now(),
Started: &tm,
}},
})
defer func() {
tm2 := time.Now()
sl.logger(&client.SolveStatus{
Statuses: []*client.VertexStatus{{
Vertex: sl.dgst,
ID: name,
Timestamp: time.Now(),
Started: &tm,
Completed: &tm2,
}},
})
}()
return fn()
}
func (sl *subLogger) Log(stream int, dt []byte) {
sl.logger(&client.SolveStatus{
Logs: []*client.VertexLog{{
Vertex: sl.dgst,
Stream: stream,
Data: dt,
Timestamp: time.Now(),
}},
})
}

View File

@ -0,0 +1,71 @@
package progresswriter
import (
"time"
"github.com/moby/buildkit/client"
)
func ResetTime(in Writer) Writer {
w := &pw{Writer: in, status: make(chan *client.SolveStatus), tm: time.Now()}
go func() {
for {
select {
case <-in.Done():
return
case st, ok := <-w.status:
if !ok {
close(in.Status())
return
}
if w.diff == nil {
for _, v := range st.Vertexes {
if v.Started != nil {
d := v.Started.Sub(w.tm)
w.diff = &d
}
}
}
if w.diff != nil {
for _, v := range st.Vertexes {
if v.Started != nil {
d := v.Started.Add(-*w.diff)
v.Started = &d
}
if v.Completed != nil {
d := v.Completed.Add(-*w.diff)
v.Completed = &d
}
}
for _, v := range st.Statuses {
if v.Started != nil {
d := v.Started.Add(-*w.diff)
v.Started = &d
}
if v.Completed != nil {
d := v.Completed.Add(-*w.diff)
v.Completed = &d
}
v.Timestamp = v.Timestamp.Add(-*w.diff)
}
for _, v := range st.Logs {
v.Timestamp = v.Timestamp.Add(-*w.diff)
}
}
in.Status() <- st
}
}
}()
return w
}
type pw struct {
Writer
tm time.Time
diff *time.Duration
status chan *client.SolveStatus
}
func (p *pw) Status() chan *client.SolveStatus {
return p.status
}

View File

@ -0,0 +1,46 @@
package progresswriter
import (
"time"
"github.com/moby/buildkit/client"
"github.com/moby/buildkit/identity"
"github.com/opencontainers/go-digest"
)
type Writer interface {
Done() <-chan struct{}
Err() error
Status() chan *client.SolveStatus
}
func Write(w Writer, name string, f func() error) {
status := w.Status()
dgst := digest.FromBytes([]byte(identity.NewID()))
tm := time.Now()
vtx := client.Vertex{
Digest: dgst,
Name: name,
Started: &tm,
}
status <- &client.SolveStatus{
Vertexes: []*client.Vertex{&vtx},
}
var err error
if f != nil {
err = f()
}
tm2 := time.Now()
vtx2 := vtx
vtx2.Completed = &tm2
if err != nil {
vtx2.Error = err.Error()
}
status <- &client.SolveStatus{
Vertexes: []*client.Vertex{&vtx2},
}
}

View File

@ -0,0 +1,51 @@
package sshutil
import (
"fmt"
"net"
"strconv"
"strings"
"golang.org/x/crypto/ssh"
)
const defaultPort = 22
var errCallbackDone = fmt.Errorf("callback failed on purpose")
// addDefaultPort appends a default port if hostport doesn't contain one
func addDefaultPort(hostport string, defaultPort int) string {
_, _, err := net.SplitHostPort(hostport)
if err == nil {
return hostport
}
hostport = net.JoinHostPort(hostport, strconv.Itoa(defaultPort))
return hostport
}
// SshKeyScan scans a ssh server for the hostkey; server should be in the form hostname, or hostname:port
func SSHKeyScan(server string) (string, error) {
var key string
KeyScanCallback := func(hostport string, remote net.Addr, pubKey ssh.PublicKey) error {
hostname, _, err := net.SplitHostPort(hostport)
if err != nil {
return err
}
key = strings.TrimSpace(fmt.Sprintf("%s %s", hostname, string(ssh.MarshalAuthorizedKey(pubKey))))
return errCallbackDone
}
config := &ssh.ClientConfig{
HostKeyCallback: KeyScanCallback,
}
server = addDefaultPort(server, defaultPort)
conn, err := ssh.Dial("tcp", server, config)
if key != "" {
// as long as we get the key, the function worked
err = nil
}
if conn != nil {
conn.Close()
}
return key, err
}

View File

@ -4,15 +4,22 @@ import (
"fmt"
io "io"
"os"
"runtime"
"strconv"
"strings"
"sync"
"github.com/containerd/typeurl"
"github.com/pkg/errors"
)
var helpers map[string]struct{}
var helpersMu sync.RWMutex
func init() {
typeurl.Register((*Stack)(nil), "github.com/moby/buildkit", "stack.Stack+json")
helpers = map[string]struct{}{}
}
var version string
@ -23,6 +30,19 @@ func SetVersionInfo(v, r string) {
revision = r
}
func Helper() {
var pc [1]uintptr
n := runtime.Callers(2, pc[:])
if n == 0 {
return
}
frames := runtime.CallersFrames(pc[:n])
frame, _ := frames.Next()
helpersMu.Lock()
helpers[frame.Function] = struct{}{}
helpersMu.Unlock()
}
func Traces(err error) []*Stack {
var st []*Stack
@ -52,6 +72,7 @@ func Enable(err error) error {
if err == nil {
return nil
}
Helper()
if !hasLocalStackTrace(err) {
return errors.WithStack(err)
}
@ -112,6 +133,8 @@ func (w *formatter) Format(s fmt.State, verb rune) {
func convertStack(s errors.StackTrace) *Stack {
var out Stack
helpersMu.RLock()
defer helpersMu.RUnlock()
for _, f := range s {
dt, err := f.MarshalText()
if err != nil {
@ -121,6 +144,9 @@ func convertStack(s errors.StackTrace) *Stack {
if len(p) != 2 {
continue
}
if _, ok := helpers[p[0]]; ok {
continue
}
idx := strings.LastIndexByte(p[1], ':')
if idx == -1 {
continue

18
vendor/github.com/moby/buildkit/util/system/path.go generated vendored Normal file
View File

@ -0,0 +1,18 @@
package system
// DefaultPathEnvUnix is unix style list of directories to search for
// executables. Each directory is separated from the next by a colon
// ':' character .
const DefaultPathEnvUnix = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
// DefaultPathEnvWindows is windows style list of directories to search for
// executables. Each directory is separated from the next by a colon
// ';' character .
const DefaultPathEnvWindows = "c:\\Windows\\System32;c:\\Windows"
func DefaultPathEnv(os string) string {
if os == "windows" {
return DefaultPathEnvWindows
}
return DefaultPathEnvUnix
}

View File

@ -2,11 +2,6 @@
package system
// DefaultPathEnv is unix style list of directories to search for
// executables. Each directory is separated from the next by a colon
// ':' character .
const DefaultPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
// CheckSystemDriveAndRemoveDriveLetter verifies that a path, if it includes a drive letter,
// is the system drive. This is a no-op on Linux.
func CheckSystemDriveAndRemoveDriveLetter(path string) (string, error) {

View File

@ -8,10 +8,6 @@ import (
"strings"
)
// DefaultPathEnv is deliberately empty on Windows as the default path will be set by
// the container. Docker has no context of what the default path should be.
const DefaultPathEnv = ""
// CheckSystemDriveAndRemoveDriveLetter verifies and manipulates a Windows path.
// This is used, for example, when validating a user provided path in docker cp.
// If a drive letter is supplied, it must be the system drive. The drive letter

View File

@ -5,52 +5,10 @@ package mount
import (
"fmt"
"sort"
"strconv"
"github.com/moby/sys/mountinfo"
)
// mountError records an error from mount or unmount operation
type mountError struct {
op string
source, target string
flags uintptr
data string
err error
}
func (e *mountError) Error() string {
out := e.op + " "
if e.source != "" {
out += e.source + ":" + e.target
} else {
out += e.target
}
if e.flags != uintptr(0) {
out += ", flags: 0x" + strconv.FormatUint(uint64(e.flags), 16)
}
if e.data != "" {
out += ", data: " + e.data
}
out += ": " + e.err.Error()
return out
}
// Cause returns the underlying cause of the error.
// This is a convention used in github.com/pkg/errors
func (e *mountError) Cause() error {
return e.err
}
// Unwrap returns the underlying error.
// This is a convention used in golang 1.13+
func (e *mountError) Unwrap() error {
return e.err
}
// Mount will mount filesystem according to the specified configuration.
// Options must be specified like the mount or fstab unix commands:
// "opt1=val1,opt2=val2". See flags.go for supported option flags.
@ -59,15 +17,26 @@ func Mount(device, target, mType, options string) error {
return mount(device, target, mType, uintptr(flag), data)
}
// Unmount lazily unmounts a filesystem on supported platforms, otherwise
// does a normal unmount.
// Unmount lazily unmounts a filesystem on supported platforms, otherwise does
// a normal unmount. If target is not a mount point, no error is returned.
func Unmount(target string) error {
return unmount(target, mntDetach)
}
// RecursiveUnmount unmounts the target and all mounts underneath, starting with
// the deepsest mount first.
// RecursiveUnmount unmounts the target and all mounts underneath, starting
// with the deepest mount first. The argument does not have to be a mount
// point itself.
func RecursiveUnmount(target string) error {
// Fast path, works if target is a mount point that can be unmounted.
// On Linux, mntDetach flag ensures a recursive unmount. For other
// platforms, if there are submounts, we'll get EBUSY (and fall back
// to the slow path). NOTE we do not ignore EINVAL here as target might
// not be a mount point itself (but there can be mounts underneath).
if err := unmountBare(target, mntDetach); err == nil {
return nil
}
// Slow path: get all submounts, sort, unmount one by one.
mounts, err := mountinfo.GetMounts(mountinfo.PrefixFilter(target))
if err != nil {
return err

46
vendor/github.com/moby/sys/mount/mount_errors.go generated vendored Normal file
View File

@ -0,0 +1,46 @@
// +build !windows
package mount
import "strconv"
// mountError records an error from mount or unmount operation
type mountError struct {
op string
source, target string
flags uintptr
data string
err error
}
func (e *mountError) Error() string {
out := e.op + " "
if e.source != "" {
out += e.source + ":" + e.target
} else {
out += e.target
}
if e.flags != uintptr(0) {
out += ", flags: 0x" + strconv.FormatUint(uint64(e.flags), 16)
}
if e.data != "" {
out += ", data: " + e.data
}
out += ": " + e.err.Error()
return out
}
// Cause returns the underlying cause of the error.
// This is a convention used in github.com/pkg/errors
func (e *mountError) Cause() error {
return e.err
}
// Unwrap returns the underlying error.
// This is a convention used in golang 1.13+
func (e *mountError) Unwrap() error {
return e.err
}

View File

@ -4,8 +4,12 @@ package mount
import "golang.org/x/sys/unix"
func unmountBare(target string, flags int) error {
return unix.Unmount(target, flags)
}
func unmount(target string, flags int) error {
err := unix.Unmount(target, flags)
err := unmountBare(target, flags)
if err == nil || err == unix.EINVAL {
// Ignore "not mounted" error here. Note the same error
// can be returned if flags are invalid, so this code

View File

@ -2,6 +2,10 @@
package mount
func unmount(target string, flag int) error {
func unmountBare(_ string, _ int) error {
panic("Not implemented")
}
func unmount(_ string, _ int) error {
panic("Not implemented")
}

44
vendor/github.com/moby/sys/mountinfo/doc.go generated vendored Normal file
View File

@ -0,0 +1,44 @@
// Package mountinfo provides a set of functions to retrieve information about OS mounts.
//
// Currently it supports Linux. For historical reasons, there is also some support for FreeBSD and OpenBSD,
// and a shallow implementation for Windows, but in general this is Linux-only package, so
// the rest of the document only applies to Linux, unless explicitly specified otherwise.
//
// In Linux, information about mounts seen by the current process is available from
// /proc/self/mountinfo. Note that due to mount namespaces, different processes can
// see different mounts. A per-process mountinfo table is available from /proc/<PID>/mountinfo,
// where <PID> is a numerical process identifier.
//
// In general, /proc is not a very efficient interface, and mountinfo is not an exception.
// For example, there is no way to get information about a specific mount point (i.e. it
// is all-or-nothing). This package tries to hide the /proc ineffectiveness by using
// parse filters while reading mountinfo. A filter can skip some entries, or stop
// processing the rest of the file once the needed information is found.
//
// For mountinfo filters that accept path as an argument, the path must be absolute,
// having all symlinks resolved, and being cleaned (i.e. no extra slashes or dots).
// One way to achieve all of the above is to employ filepath.Abs followed by
// filepath.EvalSymlinks (the latter calls filepath.Clean on the result so
// there is no need to explicitly call filepath.Clean).
//
// NOTE that in many cases there is no need to consult mountinfo at all. Here are some
// of the cases where mountinfo should not be parsed:
//
// 1. Before performing a mount. Usually, this is not needed, but if required (say to
// prevent over-mounts), to check whether a directory is mounted, call os.Lstat
// on it and its parent directory, and compare their st.Sys().(*syscall.Stat_t).Dev
// fields -- if they differ, then the directory is the mount point. NOTE this does
// not work for bind mounts. Optionally, the filesystem type can also be checked
// by calling unix.Statfs and checking the Type field (i.e. filesystem type).
//
// 2. After performing a mount. If there is no error returned, the mount succeeded;
// checking the mount table for a new mount is redundant and expensive.
//
// 3. Before performing an unmount. It is more efficient to do an unmount and ignore
// a specific error (EINVAL) which tells the directory is not mounted.
//
// 4. After performing an unmount. If there is no error returned, the unmount succeeded.
//
// 5. To find the mount point root of a specific directory. You can perform os.Stat()
// on the directory and traverse up until the Dev field of a parent directory differs.
package mountinfo

View File

@ -1,3 +1,5 @@
module github.com/moby/sys/mountinfo
go 1.14
require golang.org/x/sys v0.0.0-20200909081042-eff7692f9009

2
vendor/github.com/moby/sys/mountinfo/go.sum generated vendored Normal file
View File

@ -0,0 +1,2 @@
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 h1:W0lCpv29Hv0UaM1LXb9QlBHLNP8UFfcKjblhVCWftOM=
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

58
vendor/github.com/moby/sys/mountinfo/mounted_linux.go generated vendored Normal file
View File

@ -0,0 +1,58 @@
package mountinfo
import (
"os"
"path/filepath"
"golang.org/x/sys/unix"
)
// mountedByOpenat2 is a method of detecting a mount that works for all kinds
// of mounts (incl. bind mounts), but requires a recent (v5.6+) linux kernel.
func mountedByOpenat2(path string) (bool, error) {
dir, last := filepath.Split(path)
dirfd, err := unix.Openat2(unix.AT_FDCWD, dir, &unix.OpenHow{
Flags: unix.O_PATH | unix.O_CLOEXEC,
})
if err != nil {
if err == unix.ENOENT { // not a mount
return false, nil
}
return false, &os.PathError{Op: "openat2", Path: dir, Err: err}
}
fd, err := unix.Openat2(dirfd, last, &unix.OpenHow{
Flags: unix.O_PATH | unix.O_CLOEXEC | unix.O_NOFOLLOW,
Resolve: unix.RESOLVE_NO_XDEV,
})
_ = unix.Close(dirfd)
switch err {
case nil: // definitely not a mount
_ = unix.Close(fd)
return false, nil
case unix.EXDEV: // definitely a mount
return true, nil
case unix.ENOENT: // not a mount
return false, nil
}
// not sure
return false, &os.PathError{Op: "openat2", Path: path, Err: err}
}
func mounted(path string) (bool, error) {
// Try a fast path, using openat2() with RESOLVE_NO_XDEV.
mounted, err := mountedByOpenat2(path)
if err == nil {
return mounted, nil
}
// Another fast path: compare st.st_dev fields.
mounted, err = mountedByStat(path)
// This does not work for bind mounts, so false negative
// is possible, therefore only trust if return is true.
if mounted && err == nil {
return mounted, nil
}
// Fallback to parsing mountinfo
return mountedByMountinfo(path)
}

66
vendor/github.com/moby/sys/mountinfo/mounted_unix.go generated vendored Normal file
View File

@ -0,0 +1,66 @@
// +build linux freebsd,cgo openbsd,cgo
package mountinfo
import (
"errors"
"fmt"
"os"
"path/filepath"
"golang.org/x/sys/unix"
)
func mountedByStat(path string) (bool, error) {
var st unix.Stat_t
if err := unix.Lstat(path, &st); err != nil {
if err == unix.ENOENT {
// Treat ENOENT as "not mounted".
return false, nil
}
return false, &os.PathError{Op: "stat", Path: path, Err: err}
}
dev := st.Dev
parent := filepath.Dir(path)
if err := unix.Lstat(parent, &st); err != nil {
return false, &os.PathError{Op: "stat", Path: parent, Err: err}
}
if dev != st.Dev {
// Device differs from that of parent,
// so definitely a mount point.
return true, nil
}
// NB: this does not detect bind mounts on Linux.
return false, nil
}
func normalizePath(path string) (realPath string, err error) {
if realPath, err = filepath.Abs(path); err != nil {
return "", fmt.Errorf("unable to get absolute path for %q: %w", path, err)
}
if realPath, err = filepath.EvalSymlinks(realPath); err != nil {
return "", fmt.Errorf("failed to canonicalise path for %q: %w", path, err)
}
if _, err := os.Stat(realPath); err != nil {
return "", fmt.Errorf("failed to stat target of %q: %w", path, err)
}
return realPath, nil
}
func mountedByMountinfo(path string) (bool, error) {
path, err := normalizePath(path)
if err != nil {
if errors.Is(err, unix.ENOENT) {
// treat ENOENT as "not mounted"
return false, nil
}
return false, err
}
entries, err := GetMounts(SingleEntryFilter(path))
if err != nil {
return false, err
}
return len(entries) > 0, nil
}

View File

@ -1,6 +1,8 @@
package mountinfo
import "io"
import (
"os"
)
// GetMounts retrieves a list of mounts for the current running process,
// with an optional filter applied (use nil for no filter).
@ -8,23 +10,17 @@ func GetMounts(f FilterFunc) ([]*Info, error) {
return parseMountTable(f)
}
// GetMountsFromReader retrieves a list of mounts from the
// reader provided, with an optional filter applied (use nil
// for no filter). This can be useful in tests or benchmarks
// that provide a fake mountinfo data.
func GetMountsFromReader(reader io.Reader, f FilterFunc) ([]*Info, error) {
return parseInfoFile(reader, f)
}
// Mounted determines if a specified mountpoint has been mounted.
// On Linux it looks at /proc/self/mountinfo.
func Mounted(mountpoint string) (bool, error) {
entries, err := GetMounts(SingleEntryFilter(mountpoint))
if err != nil {
return false, err
// Mounted determines if a specified path is a mount point.
//
// The argument must be an absolute path, with all symlinks resolved, and clean.
// One way to ensure it is to process the path using filepath.Abs followed by
// filepath.EvalSymlinks before calling this function.
func Mounted(path string) (bool, error) {
// root is always mounted
if path == string(os.PathSeparator) {
return true, nil
}
return len(entries) > 0, nil
return mounted(path)
}
// Info reveals information about a particular mounted filesystem. This
@ -50,18 +46,18 @@ type Info struct {
// Mountpoint indicates the mount point relative to the process's root.
Mountpoint string
// Opts represents mount-specific options.
Opts string
// Options represents mount-specific options.
Options string
// Optional represents optional fields.
Optional string
// Fstype indicates the type of filesystem, such as EXT3.
Fstype string
// FSType indicates the type of filesystem, such as EXT3.
FSType string
// Source indicates filesystem specific information or "none".
Source string
// VfsOpts represents per super block options.
VfsOpts string
// VFSOptions represents per super block options.
VFSOptions string
}

View File

@ -1,3 +1,5 @@
// +build freebsd,cgo openbsd,cgo
package mountinfo
/*
@ -33,7 +35,7 @@ func parseMountTable(filter FilterFunc) ([]*Info, error) {
var mountinfo Info
var skip, stop bool
mountinfo.Mountpoint = C.GoString(&entry.f_mntonname[0])
mountinfo.Fstype = C.GoString(&entry.f_fstypename[0])
mountinfo.FSType = C.GoString(&entry.f_fstypename[0])
mountinfo.Source = C.GoString(&entry.f_mntfromname[0])
if filter != nil {
@ -51,3 +53,15 @@ func parseMountTable(filter FilterFunc) ([]*Info, error) {
}
return out, nil
}
func mounted(path string) (bool, error) {
// Fast path: compare st.st_dev fields.
// This should always work for FreeBSD and OpenBSD.
mounted, err := mountedByStat(path)
if err == nil {
return mounted, nil
}
// Fallback to parsing mountinfo
return mountedByMountinfo(path)
}

View File

@ -6,16 +6,16 @@ import "strings"
// used to filter out mountinfo entries we're not interested in,
// and/or stop further processing if we found what we wanted.
//
// It takes a pointer to the Info struct (not fully populated,
// currently only Mountpoint, Fstype, Source, and (on Linux)
// VfsOpts are filled in), and returns two booleans:
// It takes a pointer to the Info struct (fully populated with all available
// fields on the GOOS platform), and returns two booleans:
//
// - skip: true if the entry should be skipped
// - stop: true if parsing should be stopped after the entry
// skip: true if the entry should be skipped;
//
// stop: true if parsing should be stopped after the entry.
type FilterFunc func(*Info) (skip, stop bool)
// PrefixFilter discards all entries whose mount points
// do not start with a specific prefix
// do not start with a specific prefix.
func PrefixFilter(prefix string) FilterFunc {
return func(m *Info) (bool, bool) {
skip := !strings.HasPrefix(m.Mountpoint, prefix)
@ -23,7 +23,7 @@ func PrefixFilter(prefix string) FilterFunc {
}
}
// SingleEntryFilter looks for a specific entry
// SingleEntryFilter looks for a specific entry.
func SingleEntryFilter(mp string) FilterFunc {
return func(m *Info) (bool, bool) {
if m.Mountpoint == mp {
@ -36,8 +36,8 @@ func SingleEntryFilter(mp string) FilterFunc {
// ParentsFilter returns all entries whose mount points
// can be parents of a path specified, discarding others.
//
// For example, given `/var/lib/docker/something`, entries
// like `/var/lib/docker`, `/var` and `/` are returned.
// For example, given /var/lib/docker/something, entries
// like /var/lib/docker, /var and / are returned.
func ParentsFilter(path string) FilterFunc {
return func(m *Info) (bool, bool) {
skip := !strings.HasPrefix(path, m.Mountpoint)
@ -45,12 +45,12 @@ func ParentsFilter(path string) FilterFunc {
}
}
// FstypeFilter returns all entries that match provided fstype(s).
func FstypeFilter(fstype ...string) FilterFunc {
// FSTypeFilter returns all entries that match provided fstype(s).
func FSTypeFilter(fstype ...string) FilterFunc {
return func(m *Info) (bool, bool) {
for _, t := range fstype {
if m.Fstype == t {
return false, false // don't skeep, keep going
if m.FSType == t {
return false, false // don't skip, keep going
}
}
return true, false // skip, keep going

View File

@ -1,5 +1,3 @@
// +build go1.13
package mountinfo
import (
@ -11,14 +9,18 @@ import (
"strings"
)
func parseInfoFile(r io.Reader, filter FilterFunc) ([]*Info, error) {
// GetMountsFromReader retrieves a list of mounts from the
// reader provided, with an optional filter applied (use nil
// for no filter). This can be useful in tests or benchmarks
// that provide a fake mountinfo data.
//
// This function is Linux-specific.
func GetMountsFromReader(r io.Reader, filter FilterFunc) ([]*Info, error) {
s := bufio.NewScanner(r)
out := []*Info{}
var err error
for s.Scan() {
if err = s.Err(); err != nil {
return nil, err
}
var err error
/*
See http://man7.org/linux/man-pages/man5/proc.5.html
@ -70,26 +72,19 @@ func parseInfoFile(r io.Reader, filter FilterFunc) ([]*Info, error) {
p := &Info{}
// Fill in the fields that a filter might check
p.Mountpoint, err = strconv.Unquote(`"` + fields[4] + `"`)
p.Mountpoint, err = unescape(fields[4])
if err != nil {
return nil, fmt.Errorf("Parsing '%s' failed: unable to unquote mount point field: %w", fields[4], err)
return nil, fmt.Errorf("Parsing '%s' failed: mount point: %w", fields[4], err)
}
p.Fstype = fields[sepIdx+1]
p.Source = fields[sepIdx+2]
p.VfsOpts = fields[sepIdx+3]
// Run a filter soon so we can skip parsing/adding entries
// the caller is not interested in
var skip, stop bool
if filter != nil {
skip, stop = filter(p)
if skip {
continue
}
p.FSType, err = unescape(fields[sepIdx+1])
if err != nil {
return nil, fmt.Errorf("Parsing '%s' failed: fstype: %w", fields[sepIdx+1], err)
}
// Fill in the rest of the fields
p.Source, err = unescape(fields[sepIdx+2])
if err != nil {
return nil, fmt.Errorf("Parsing '%s' failed: source: %w", fields[sepIdx+2], err)
}
p.VFSOptions = fields[sepIdx+3]
// ignore any numbers parsing errors, as there should not be any
p.ID, _ = strconv.Atoi(fields[0])
@ -101,12 +96,12 @@ func parseInfoFile(r io.Reader, filter FilterFunc) ([]*Info, error) {
p.Major, _ = strconv.Atoi(mm[0])
p.Minor, _ = strconv.Atoi(mm[1])
p.Root, err = strconv.Unquote(`"` + fields[3] + `"`)
p.Root, err = unescape(fields[3])
if err != nil {
return nil, fmt.Errorf("Parsing '%s' failed: unable to unquote root field: %w", fields[3], err)
return nil, fmt.Errorf("Parsing '%s' failed: root: %w", fields[3], err)
}
p.Opts = fields[5]
p.Options = fields[5]
// zero or more optional fields
switch {
@ -118,11 +113,23 @@ func parseInfoFile(r io.Reader, filter FilterFunc) ([]*Info, error) {
p.Optional = strings.Join(fields[6:sepIdx-1], " ")
}
// Run the filter after parsing all of the fields.
var skip, stop bool
if filter != nil {
skip, stop = filter(p)
if skip {
continue
}
}
out = append(out, p)
if stop {
break
}
}
if err := s.Err(); err != nil {
return nil, err
}
return out, nil
}
@ -135,12 +142,17 @@ func parseMountTable(filter FilterFunc) ([]*Info, error) {
}
defer f.Close()
return parseInfoFile(f, filter)
return GetMountsFromReader(f, filter)
}
// PidMountInfo collects the mounts for a specific process ID. If the process
// ID is unknown, it is better to use `GetMounts` which will inspect
// "/proc/self/mountinfo" instead.
// PidMountInfo retrieves the list of mounts from a given process' mount
// namespace. Unless there is a need to get mounts from a mount namespace
// different from that of a calling process, use GetMounts.
//
// This function is Linux-specific.
//
// Deprecated: this will be removed before v1; use GetMountsFromReader with
// opened /proc/<pid>/mountinfo as an argument instead.
func PidMountInfo(pid int) ([]*Info, error) {
f, err := os.Open(fmt.Sprintf("/proc/%d/mountinfo", pid))
if err != nil {
@ -148,5 +160,63 @@ func PidMountInfo(pid int) ([]*Info, error) {
}
defer f.Close()
return parseInfoFile(f, nil)
return GetMountsFromReader(f, nil)
}
// A few specific characters in mountinfo path entries (root and mountpoint)
// are escaped using a backslash followed by a character's ascii code in octal.
//
// space -- as \040
// tab (aka \t) -- as \011
// newline (aka \n) -- as \012
// backslash (aka \\) -- as \134
//
// This function converts path from mountinfo back, i.e. it unescapes the above sequences.
func unescape(path string) (string, error) {
// try to avoid copying
if strings.IndexByte(path, '\\') == -1 {
return path, nil
}
// The following code is UTF-8 transparent as it only looks for some
// specific characters (backslash and 0..7) with values < utf8.RuneSelf,
// and everything else is passed through as is.
buf := make([]byte, len(path))
bufLen := 0
for i := 0; i < len(path); i++ {
if path[i] != '\\' {
buf[bufLen] = path[i]
bufLen++
continue
}
s := path[i:]
if len(s) < 4 {
// too short
return "", fmt.Errorf("bad escape sequence %q: too short", s)
}
c := s[1]
switch c {
case '0', '1', '2', '3', '4', '5', '6', '7':
v := c - '0'
for j := 2; j < 4; j++ { // one digit already; two more
if s[j] < '0' || s[j] > '7' {
return "", fmt.Errorf("bad escape sequence %q: not a digit", s[:3])
}
x := s[j] - '0'
v = (v << 3) | x
}
if v > 255 {
return "", fmt.Errorf("bad escape sequence %q: out of range" + s[:3])
}
buf[bufLen] = v
bufLen++
i += 3
continue
default:
return "", fmt.Errorf("bad escape sequence %q: not a digit" + s[:3])
}
}
return string(buf[:bufLen]), nil
}

View File

@ -1,17 +1,18 @@
// +build !windows,!linux,!freebsd freebsd,!cgo
// +build !windows,!linux,!freebsd,!openbsd freebsd,!cgo openbsd,!cgo
package mountinfo
import (
"fmt"
"io"
"runtime"
)
var errNotImplemented = fmt.Errorf("not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
func parseMountTable(_ FilterFunc) ([]*Info, error) {
return nil, fmt.Errorf("mount.parseMountTable is not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
return nil, errNotImplemented
}
func parseInfoFile(_ io.Reader, f FilterFunc) ([]*Info, error) {
return parseMountTable(f)
func mounted(path string) (bool, error) {
return false, errNotImplemented
}

View File

@ -1,12 +1,10 @@
package mountinfo
import "io"
func parseMountTable(_ FilterFunc) ([]*Info, error) {
// Do NOT return an error!
return nil, nil
}
func parseInfoFile(_ io.Reader, f FilterFunc) ([]*Info, error) {
return parseMountTable(f)
func mounted(_ string) (bool, error) {
return false, nil
}

4
vendor/github.com/moby/term/tc.go generated vendored
View File

@ -11,9 +11,9 @@ func tcget(fd uintptr) (*Termios, error) {
if err != nil {
return nil, err
}
return (*Termios)(p), nil
return p, nil
}
func tcset(fd uintptr, p *Termios) error {
return unix.IoctlSetTermios(int(fd), setTermios, (*unix.Termios)(p))
return unix.IoctlSetTermios(int(fd), setTermios, p)
}

View File

@ -7,7 +7,7 @@ import (
)
// Termios is the Unix API for terminal I/O.
type Termios unix.Termios
type Termios = unix.Termios
// MakeRaw puts the terminal connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be
@ -18,8 +18,7 @@ func MakeRaw(fd uintptr) (*State, error) {
return nil, err
}
var oldState State
oldState.termios = Termios(*termios)
oldState := State{termios: *termios}
termios.Iflag &^= (unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON)
termios.Oflag &^= unix.OPOST