From 4945fe758cdbab87424eec784747fd109edb625d Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Wed, 1 Aug 2018 14:15:43 -0700 Subject: [PATCH 1/5] llbsolver: add support for extra host records Signed-off-by: Tonis Tiigi --- executor/containerdexecutor/executor.go | 6 +- executor/executor.go | 8 + executor/oci/hosts.go | 59 +++- executor/runcexecutor/executor.go | 7 +- solver/llbsolver/ops/exec.go | 32 ++ solver/pb/ops.pb.go | 416 +++++++++++++++++++----- solver/pb/ops.proto | 6 + 7 files changed, 427 insertions(+), 107 deletions(-) diff --git a/executor/containerdexecutor/executor.go b/executor/containerdexecutor/executor.go index 09538dba..f271f036 100644 --- a/executor/containerdexecutor/executor.go +++ b/executor/containerdexecutor/executor.go @@ -3,6 +3,7 @@ package containerdexecutor import ( "context" "io" + "os" "syscall" "time" @@ -39,10 +40,13 @@ func (w containerdExecutor) Exec(ctx context.Context, meta executor.Meta, root c return err } - hostsFile, err := oci.GetHostsFile(ctx, w.root) + hostsFile, err := oci.GetHostsFile(ctx, w.root, meta.ExtraHosts) if err != nil { return err } + if len(meta.ExtraHosts) > 0 { + defer os.RemoveAll(hostsFile) + } mountable, err := root.Mount(ctx, false) if err != nil { diff --git a/executor/executor.go b/executor/executor.go index 6c897926..5f79363e 100644 --- a/executor/executor.go +++ b/executor/executor.go @@ -3,6 +3,7 @@ package executor import ( "context" "io" + "net" "github.com/moby/buildkit/cache" ) @@ -15,6 +16,8 @@ type Meta struct { Tty bool ReadonlyRootFS bool // DisableNetworking bool + + ExtraHosts []HostIP } type Mount struct { @@ -28,3 +31,8 @@ type Executor interface { // TODO: add stdout/err Exec(ctx context.Context, meta Meta, rootfs cache.Mountable, mounts []Mount, stdin io.ReadCloser, stdout, stderr io.WriteCloser) error } + +type HostIP struct { + Host string + IP net.IP +} diff --git a/executor/oci/hosts.go b/executor/oci/hosts.go index b7be99cc..d01b9e6e 100644 --- a/executor/oci/hosts.go +++ b/executor/oci/hosts.go @@ -1,10 +1,15 @@ package oci import ( + "bytes" "context" + "fmt" "io/ioutil" "os" "path/filepath" + + "github.com/moby/buildkit/executor" + "github.com/moby/buildkit/identity" ) const hostsContent = ` @@ -12,26 +17,50 @@ const hostsContent = ` ::1 localhost ip6-localhost ip6-loopback ` -func GetHostsFile(ctx context.Context, stateDir string) (string, error) { - p := filepath.Join(stateDir, "hosts") - _, err := g.Do(ctx, stateDir, func(ctx context.Context) (interface{}, error) { - _, err := os.Stat(p) - if err == nil { - return "", nil - } - if !os.IsNotExist(err) { - return "", err - } - if err := ioutil.WriteFile(p+".tmp", []byte(hostsContent), 0644); err != nil { +func GetHostsFile(ctx context.Context, stateDir string, extraHosts []executor.HostIP) (string, error) { + if len(extraHosts) == 0 { + _, err := g.Do(ctx, stateDir, func(ctx context.Context) (interface{}, error) { + _, err := makeHostsFile(stateDir, nil) + return nil, err + }) + if err != nil { return "", err } + return filepath.Join(stateDir, "hosts"), nil + } + return makeHostsFile(stateDir, extraHosts) +} - if err := os.Rename(p+".tmp", p); err != nil { +func makeHostsFile(stateDir string, extraHosts []executor.HostIP) (string, error) { + p := filepath.Join(stateDir, "hosts") + if len(extraHosts) != 0 { + p += "." + identity.NewID() + } + _, err := os.Stat(p) + if err == nil { + return "", nil + } + if !os.IsNotExist(err) { + return "", err + } + + b := &bytes.Buffer{} + + if _, err := b.Write([]byte(hostsContent)); err != nil { + return "", err + } + + for _, h := range extraHosts { + if _, err := b.Write([]byte(fmt.Sprintf("%s\t%s\n", h.IP.String(), h.Host))); err != nil { return "", err } - return "", nil - }) - if err != nil { + } + + if err := ioutil.WriteFile(p+".tmp", b.Bytes(), 0644); err != nil { + return "", err + } + + if err := os.Rename(p+".tmp", p); err != nil { return "", err } return p, nil diff --git a/executor/runcexecutor/executor.go b/executor/runcexecutor/executor.go index 8dae7b2e..75bce875 100644 --- a/executor/runcexecutor/executor.go +++ b/executor/runcexecutor/executor.go @@ -23,7 +23,7 @@ import ( "github.com/moby/buildkit/identity" rootlessspecconv "github.com/moby/buildkit/util/rootless/specconv" "github.com/moby/buildkit/util/system" - "github.com/opencontainers/runtime-spec/specs-go" + specs "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -103,10 +103,13 @@ func (w *runcExecutor) Exec(ctx context.Context, meta executor.Meta, root cache. return err } - hostsFile, err := oci.GetHostsFile(ctx, w.root) + hostsFile, err := oci.GetHostsFile(ctx, w.root, meta.ExtraHosts) if err != nil { return err } + if len(meta.ExtraHosts) > 0 { + defer os.RemoveAll(hostsFile) + } mountable, err := root.Mount(ctx, false) if err != nil { diff --git a/solver/llbsolver/ops/exec.go b/solver/llbsolver/ops/exec.go index 8ac610ce..fd9d4acc 100644 --- a/solver/llbsolver/ops/exec.go +++ b/solver/llbsolver/ops/exec.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "io/ioutil" + "net" "os" "path" "path/filepath" @@ -67,6 +68,11 @@ func NewExecOp(v solver.Vertex, op *pb.Op_Exec, cm cache.Manager, sm *session.Ma func cloneExecOp(old *pb.ExecOp) pb.ExecOp { n := *old meta := *n.Meta + meta.ExtraHosts = nil + for i := range n.Meta.ExtraHosts { + h := *n.Meta.ExtraHosts[i] + meta.ExtraHosts = append(meta.ExtraHosts, &h) + } n.Meta = &meta n.Mounts = nil for i := range n.Mounts { @@ -78,6 +84,11 @@ func cloneExecOp(old *pb.ExecOp) pb.ExecOp { func (e *execOp) CacheMap(ctx context.Context, index int) (*solver.CacheMap, bool, error) { op := cloneExecOp(e.op) + for i := range op.Meta.ExtraHosts { + h := op.Meta.ExtraHosts[i] + h.IP = "" + op.Meta.ExtraHosts[i] = h + } for i := range op.Mounts { op.Mounts[i].Selector = "" } @@ -504,12 +515,18 @@ func (e *execOp) Exec(ctx context.Context, inputs []solver.Result) ([]solver.Res return mounts[i].Dest < mounts[j].Dest }) + extraHosts, err := parseExtraHosts(e.op.Meta.ExtraHosts) + if err != nil { + return nil, err + } + meta := executor.Meta{ Args: e.op.Meta.Args, Env: e.op.Meta.Env, Cwd: e.op.Meta.Cwd, User: e.op.Meta.User, ReadonlyRootFS: readonlyRootFS, + ExtraHosts: extraHosts, } if e.op.Meta.ProxyEnv != nil { @@ -657,3 +674,18 @@ func (r *cacheRef) Release(ctx context.Context) error { } return nil } + +func parseExtraHosts(ips []*pb.HostIP) ([]executor.HostIP, error) { + out := make([]executor.HostIP, len(ips)) + for i, hip := range ips { + ip := net.ParseIP(hip.IP) + if ip == nil { + return nil, errors.Errorf("failed to parse IP %s", hip.IP) + } + out[i] = executor.HostIP{ + IP: ip, + Host: hip.Host, + } + } + return out, nil +} diff --git a/solver/pb/ops.pb.go b/solver/pb/ops.pb.go index 6fa7a820..527c2d4f 100644 --- a/solver/pb/ops.pb.go +++ b/solver/pb/ops.pb.go @@ -29,6 +29,7 @@ ProxyEnv WorkerConstraints Definition + HostIP */ package pb @@ -414,11 +415,12 @@ func (m *ExecOp) GetMounts() []*Mount { // Meta is unrelated to LLB metadata. // FIXME: rename (ExecContext? ExecArgs?) type Meta struct { - Args []string `protobuf:"bytes,1,rep,name=args" json:"args,omitempty"` - Env []string `protobuf:"bytes,2,rep,name=env" json:"env,omitempty"` - Cwd string `protobuf:"bytes,3,opt,name=cwd,proto3" json:"cwd,omitempty"` - User string `protobuf:"bytes,4,opt,name=user,proto3" json:"user,omitempty"` - ProxyEnv *ProxyEnv `protobuf:"bytes,5,opt,name=proxy_env,json=proxyEnv" json:"proxy_env,omitempty"` + Args []string `protobuf:"bytes,1,rep,name=args" json:"args,omitempty"` + Env []string `protobuf:"bytes,2,rep,name=env" json:"env,omitempty"` + Cwd string `protobuf:"bytes,3,opt,name=cwd,proto3" json:"cwd,omitempty"` + User string `protobuf:"bytes,4,opt,name=user,proto3" json:"user,omitempty"` + ProxyEnv *ProxyEnv `protobuf:"bytes,5,opt,name=proxy_env,json=proxyEnv" json:"proxy_env,omitempty"` + ExtraHosts []*HostIP `protobuf:"bytes,6,rep,name=extraHosts" json:"extraHosts,omitempty"` } func (m *Meta) Reset() { *m = Meta{} } @@ -461,6 +463,13 @@ func (m *Meta) GetProxyEnv() *ProxyEnv { return nil } +func (m *Meta) GetExtraHosts() []*HostIP { + if m != nil { + return m.ExtraHosts + } + return nil +} + // 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"` @@ -864,6 +873,30 @@ func (m *Definition) GetMetadata() map[github_com_opencontainers_go_digest.Diges return nil } +type HostIP struct { + Host string `protobuf:"bytes,1,opt,name=Host,proto3" json:"Host,omitempty"` + IP string `protobuf:"bytes,2,opt,name=IP,proto3" json:"IP,omitempty"` +} + +func (m *HostIP) Reset() { *m = HostIP{} } +func (m *HostIP) String() string { return proto.CompactTextString(m) } +func (*HostIP) ProtoMessage() {} +func (*HostIP) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{18} } + +func (m *HostIP) GetHost() string { + if m != nil { + return m.Host + } + return "" +} + +func (m *HostIP) GetIP() string { + if m != nil { + return m.IP + } + return "" +} + func init() { proto.RegisterType((*Op)(nil), "pb.Op") proto.RegisterType((*Platform)(nil), "pb.Platform") @@ -883,6 +916,7 @@ func init() { proto.RegisterType((*ProxyEnv)(nil), "pb.ProxyEnv") proto.RegisterType((*WorkerConstraints)(nil), "pb.WorkerConstraints") proto.RegisterType((*Definition)(nil), "pb.Definition") + proto.RegisterType((*HostIP)(nil), "pb.HostIP") proto.RegisterEnum("pb.MountType", MountType_name, MountType_value) proto.RegisterEnum("pb.CacheSharingOpt", CacheSharingOpt_name, CacheSharingOpt_value) } @@ -1192,6 +1226,18 @@ func (m *Meta) MarshalTo(dAtA []byte) (int, error) { } i += n9 } + if len(m.ExtraHosts) > 0 { + for _, msg := range m.ExtraHosts { + dAtA[i] = 0x32 + i++ + i = encodeVarintOps(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n + } + } return i, nil } @@ -1790,6 +1836,36 @@ func (m *Definition) MarshalTo(dAtA []byte) (int, error) { return i, nil } +func (m *HostIP) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *HostIP) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.Host) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintOps(dAtA, i, uint64(len(m.Host))) + i += copy(dAtA[i:], m.Host) + } + if len(m.IP) > 0 { + dAtA[i] = 0x12 + i++ + i = encodeVarintOps(dAtA, i, uint64(len(m.IP))) + i += copy(dAtA[i:], m.IP) + } + return i, nil +} + func encodeVarintOps(dAtA []byte, offset int, v uint64) int { for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) @@ -1942,6 +2018,12 @@ func (m *Meta) Size() (n int) { l = m.ProxyEnv.Size() n += 1 + l + sovOps(uint64(l)) } + if len(m.ExtraHosts) > 0 { + for _, e := range m.ExtraHosts { + l = e.Size() + n += 1 + l + sovOps(uint64(l)) + } + } return n } @@ -2197,6 +2279,20 @@ func (m *Definition) Size() (n int) { return n } +func (m *HostIP) Size() (n int) { + var l int + _ = l + l = len(m.Host) + if l > 0 { + n += 1 + l + sovOps(uint64(l)) + } + l = len(m.IP) + if l > 0 { + n += 1 + l + sovOps(uint64(l)) + } + return n +} + func sovOps(x uint64) (n int) { for { n++ @@ -3070,6 +3166,37 @@ func (m *Meta) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ExtraHosts", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOps + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthOps + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ExtraHosts = append(m.ExtraHosts, &HostIP{}) + if err := m.ExtraHosts[len(m.ExtraHosts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipOps(dAtA[iNdEx:]) @@ -5260,6 +5387,114 @@ func (m *Definition) Unmarshal(dAtA []byte) error { } return nil } +func (m *HostIP) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOps + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: HostIP: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: HostIP: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Host", 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 > l { + return io.ErrUnexpectedEOF + } + m.Host = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field IP", 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 > l { + return io.ErrUnexpectedEOF + } + m.IP = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipOps(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthOps + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipOps(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 @@ -5368,88 +5603,91 @@ var ( func init() { proto.RegisterFile("ops.proto", fileDescriptorOps) } var fileDescriptorOps = []byte{ - // 1328 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xcb, 0x6e, 0xdb, 0x46, - 0x17, 0x36, 0xa9, 0x8b, 0xc9, 0x43, 0xdb, 0xd1, 0x3f, 0xb9, 0xfc, 0xfa, 0xfd, 0xa7, 0xb6, 0xcb, - 0x14, 0x85, 0x13, 0xc7, 0x12, 0xa0, 0x00, 0x49, 0xd0, 0x45, 0x50, 0xeb, 0x12, 0x58, 0x4d, 0x53, - 0x05, 0x23, 0xc3, 0x5d, 0x06, 0x14, 0x35, 0x92, 0x89, 0x48, 0x1c, 0x82, 0x1c, 0xa6, 0xd6, 0xa2, - 0x5d, 0xe4, 0x09, 0x0a, 0x14, 0xe8, 0xbe, 0x2f, 0xd0, 0x37, 0xe8, 0x3e, 0xcb, 0x6e, 0xdb, 0x45, - 0x5a, 0xa4, 0x2f, 0x52, 0x9c, 0x99, 0xe1, 0x25, 0x97, 0xa2, 0x09, 0xda, 0x15, 0x67, 0xce, 0xe5, - 0x9b, 0x33, 0xdf, 0x39, 0x67, 0x0e, 0xc1, 0xe6, 0x51, 0xd2, 0x8a, 0x62, 0x2e, 0x38, 0x31, 0xa3, - 0xc9, 0xf6, 0xe1, 0x3c, 0x10, 0x67, 0xe9, 0xa4, 0xe5, 0xf3, 0x65, 0x7b, 0xce, 0xe7, 0xbc, 0x2d, - 0x55, 0x93, 0x74, 0x26, 0x77, 0x72, 0x23, 0x57, 0xca, 0xc5, 0xfd, 0xc1, 0x04, 0x73, 0x14, 0x91, - 0x0f, 0xa1, 0x1e, 0x84, 0x51, 0x2a, 0x92, 0xa6, 0xb1, 0x57, 0xd9, 0x77, 0x3a, 0x76, 0x2b, 0x9a, - 0xb4, 0x86, 0x28, 0xa1, 0x5a, 0x41, 0xf6, 0xa0, 0xca, 0xce, 0x99, 0xdf, 0x34, 0xf7, 0x8c, 0x7d, - 0xa7, 0x03, 0x68, 0x30, 0x38, 0x67, 0xfe, 0x28, 0x3a, 0x5e, 0xa3, 0x52, 0x43, 0x3e, 0x86, 0x7a, - 0xc2, 0xd3, 0xd8, 0x67, 0xcd, 0x8a, 0xb4, 0xd9, 0x40, 0x9b, 0xb1, 0x94, 0x48, 0x2b, 0xad, 0x45, - 0x24, 0x9f, 0x47, 0xab, 0x66, 0xb5, 0x40, 0xea, 0xf1, 0x68, 0xa5, 0x90, 0x50, 0x43, 0xae, 0x41, - 0x6d, 0x92, 0x06, 0x8b, 0x69, 0xb3, 0x26, 0x4d, 0x1c, 0x34, 0xe9, 0xa2, 0x40, 0xda, 0x28, 0x1d, - 0xd9, 0x07, 0x2b, 0x5a, 0x78, 0x62, 0xc6, 0xe3, 0x65, 0x13, 0x8a, 0x03, 0x1f, 0x69, 0x19, 0xcd, - 0xb5, 0xe4, 0x0e, 0x38, 0x3e, 0x0f, 0x13, 0x11, 0x7b, 0x41, 0x28, 0x92, 0xa6, 0x23, 0x8d, 0x2f, - 0xa3, 0xf1, 0x97, 0x3c, 0x7e, 0xc2, 0xe2, 0x5e, 0xa1, 0xa4, 0x65, 0xcb, 0x6e, 0x15, 0x4c, 0x1e, - 0xb9, 0xdf, 0x1b, 0x60, 0x65, 0xa8, 0xc4, 0x85, 0x8d, 0xa3, 0xd8, 0x3f, 0x0b, 0x04, 0xf3, 0x45, - 0x1a, 0xb3, 0xa6, 0xb1, 0x67, 0xec, 0xdb, 0xf4, 0x15, 0x19, 0xd9, 0x02, 0x73, 0x34, 0x96, 0x44, - 0xd9, 0xd4, 0x1c, 0x8d, 0x49, 0x13, 0xd6, 0x4f, 0xbd, 0x38, 0xf0, 0x42, 0x21, 0x99, 0xb1, 0x69, - 0xb6, 0x25, 0x57, 0xc1, 0x1e, 0x8d, 0x4f, 0x59, 0x9c, 0x04, 0x3c, 0x94, 0x7c, 0xd8, 0xb4, 0x10, - 0x90, 0x1d, 0x80, 0xd1, 0xf8, 0x3e, 0xf3, 0x10, 0x34, 0x69, 0xd6, 0xf6, 0x2a, 0xfb, 0x36, 0x2d, - 0x49, 0xdc, 0x6f, 0xa0, 0x26, 0x73, 0x44, 0x3e, 0x83, 0xfa, 0x34, 0x98, 0xb3, 0x44, 0xa8, 0x70, - 0xba, 0x9d, 0xe7, 0x2f, 0x76, 0xd7, 0x7e, 0x7d, 0xb1, 0x7b, 0xa3, 0x54, 0x0c, 0x3c, 0x62, 0xa1, - 0xcf, 0x43, 0xe1, 0x05, 0x21, 0x8b, 0x93, 0xf6, 0x9c, 0x1f, 0x2a, 0x97, 0x56, 0x5f, 0x7e, 0xa8, - 0x46, 0x20, 0xd7, 0xa1, 0x16, 0x84, 0x53, 0x76, 0x2e, 0xe3, 0xaf, 0x74, 0x2f, 0x6a, 0x28, 0x67, - 0x94, 0x8a, 0x28, 0x15, 0x43, 0x54, 0x51, 0x65, 0xe1, 0x0e, 0xa1, 0xae, 0x4a, 0x80, 0x5c, 0x85, - 0xea, 0x92, 0x09, 0x4f, 0x1e, 0xef, 0x74, 0x2c, 0xa4, 0xf6, 0x21, 0x13, 0x1e, 0x95, 0x52, 0xac, - 0xae, 0x25, 0x4f, 0x91, 0x7a, 0xb3, 0xa8, 0xae, 0x87, 0x28, 0xa1, 0x5a, 0xe1, 0x7e, 0x0d, 0x55, - 0x74, 0x20, 0x04, 0xaa, 0x5e, 0x3c, 0x57, 0x65, 0x68, 0x53, 0xb9, 0x26, 0x0d, 0xa8, 0xb0, 0xf0, - 0xa9, 0xf4, 0xb5, 0x29, 0x2e, 0x51, 0xe2, 0x7f, 0x35, 0xd5, 0x64, 0xe2, 0x12, 0xfd, 0xd2, 0x84, - 0xc5, 0x9a, 0x43, 0xb9, 0x26, 0xd7, 0xc1, 0x8e, 0x62, 0x7e, 0xbe, 0x7a, 0x8c, 0xde, 0xb5, 0x52, - 0x85, 0xa0, 0x70, 0x10, 0x3e, 0xa5, 0x56, 0xa4, 0x57, 0xee, 0x8f, 0x26, 0xd4, 0x64, 0x40, 0x64, - 0x1f, 0xaf, 0x1f, 0xa5, 0x8a, 0xc9, 0x4a, 0x97, 0xe8, 0xeb, 0x83, 0x24, 0x3a, 0xbf, 0x3d, 0x92, - 0xbe, 0x0d, 0x56, 0xc2, 0x16, 0xcc, 0x17, 0x3c, 0xd6, 0xb9, 0xce, 0xf7, 0x18, 0xce, 0x14, 0xd3, - 0xa1, 0x22, 0x94, 0x6b, 0x72, 0x00, 0x75, 0x2e, 0x39, 0x94, 0x41, 0xfe, 0x05, 0xb3, 0xda, 0x04, - 0xc1, 0x63, 0xe6, 0x4d, 0x79, 0xb8, 0x58, 0xc9, 0xd0, 0x2d, 0x9a, 0xef, 0xc9, 0x01, 0xd8, 0x92, - 0xb5, 0x93, 0x55, 0xc4, 0x9a, 0xf5, 0x3d, 0x63, 0x7f, 0xab, 0xb3, 0x99, 0x33, 0x8a, 0x42, 0x5a, - 0xe8, 0xb1, 0x4b, 0x7c, 0xcf, 0x3f, 0x63, 0xa3, 0x48, 0x34, 0x2f, 0x15, 0x1c, 0xf4, 0xb4, 0x8c, - 0xe6, 0x5a, 0x84, 0x4d, 0x98, 0x1f, 0x33, 0x81, 0xa6, 0x97, 0xa5, 0xa9, 0x84, 0x1d, 0x67, 0x42, - 0x5a, 0xe8, 0xdd, 0x21, 0x58, 0x19, 0x04, 0x96, 0xfb, 0xb0, 0xaf, 0x1b, 0xc1, 0x1c, 0xf6, 0xc9, - 0x21, 0xac, 0x27, 0x67, 0x5e, 0x1c, 0x84, 0x73, 0xc9, 0xcb, 0x56, 0xe7, 0x62, 0x7e, 0xe2, 0x58, - 0xc9, 0x11, 0x2c, 0xb3, 0x71, 0x39, 0xd8, 0xf9, 0x11, 0x6f, 0x60, 0x35, 0xa0, 0x92, 0x06, 0x53, - 0x89, 0xb3, 0x49, 0x71, 0x89, 0x92, 0x79, 0xa0, 0x72, 0xbf, 0x49, 0x71, 0x89, 0x64, 0x2f, 0xf9, - 0x94, 0x49, 0x5a, 0x37, 0xa9, 0x5c, 0x23, 0x7f, 0x3c, 0x12, 0x01, 0x0f, 0xbd, 0x45, 0xc6, 0x5f, - 0xb6, 0x77, 0xef, 0x41, 0x5d, 0xbd, 0x37, 0x64, 0x0f, 0x2a, 0x49, 0xec, 0xeb, 0x37, 0x6f, 0x2b, - 0x7b, 0x88, 0xd4, 0x93, 0x45, 0x51, 0x95, 0x27, 0xd2, 0x2c, 0x12, 0xe9, 0x52, 0x80, 0xc2, 0xec, - 0xdf, 0x29, 0x18, 0xf7, 0x3b, 0x03, 0xac, 0xec, 0xa9, 0xc4, 0xbe, 0x0f, 0xa6, 0x2c, 0x14, 0xc1, - 0x2c, 0x60, 0xb1, 0x26, 0xa3, 0x24, 0x21, 0x87, 0x50, 0xf3, 0x84, 0x88, 0xb3, 0x76, 0xfa, 0x6f, - 0xf9, 0x9d, 0x6d, 0x1d, 0xa1, 0x66, 0x10, 0x8a, 0x78, 0x45, 0x95, 0xd5, 0xf6, 0x5d, 0x80, 0x42, - 0x88, 0xfc, 0x3d, 0x61, 0x2b, 0x8d, 0x8a, 0x4b, 0x72, 0x09, 0x6a, 0x4f, 0xbd, 0x45, 0xca, 0x74, - 0x50, 0x6a, 0xf3, 0x89, 0x79, 0xd7, 0x70, 0x7f, 0x32, 0x61, 0x5d, 0xbf, 0xbb, 0xe4, 0x26, 0xac, - 0xcb, 0x77, 0x57, 0x47, 0xf4, 0xf6, 0x9b, 0x66, 0x26, 0xa4, 0x9d, 0x0f, 0x94, 0x52, 0x8c, 0x1a, - 0x4a, 0x0d, 0x16, 0x1d, 0x63, 0x31, 0x5e, 0x2a, 0x53, 0x36, 0xd3, 0x93, 0x43, 0xa6, 0xa2, 0xcf, - 0x66, 0x41, 0x18, 0x60, 0xce, 0x28, 0xaa, 0xc8, 0xcd, 0xec, 0xd6, 0x55, 0x89, 0x78, 0xa5, 0x8c, - 0xf8, 0xe6, 0xa5, 0x87, 0xe0, 0x94, 0x8e, 0x79, 0xcb, 0xad, 0x3f, 0x2a, 0xdf, 0x5a, 0x1f, 0x29, - 0xe1, 0xd4, 0xd8, 0x2b, 0x58, 0xf8, 0x07, 0xfc, 0xdd, 0x06, 0x28, 0x20, 0xdf, 0xbd, 0x52, 0xdc, - 0x67, 0x15, 0x80, 0x51, 0x84, 0x0f, 0xe2, 0xd4, 0x93, 0xef, 0xe7, 0x46, 0x30, 0x0f, 0x79, 0xcc, - 0x1e, 0xcb, 0x66, 0x95, 0xfe, 0x16, 0x75, 0x94, 0x4c, 0xf6, 0x15, 0x39, 0x02, 0x67, 0xca, 0x12, - 0x3f, 0x0e, 0x64, 0x91, 0x6b, 0xd2, 0x77, 0xf1, 0x4e, 0x05, 0x4e, 0xab, 0x5f, 0x58, 0x28, 0xae, - 0xca, 0x3e, 0xa4, 0x03, 0x1b, 0xec, 0x3c, 0xe2, 0xb1, 0xd0, 0xa7, 0xa8, 0xf1, 0x7c, 0x41, 0x0d, - 0x7a, 0x94, 0xcb, 0x93, 0xa8, 0xc3, 0x8a, 0x0d, 0xf1, 0xa0, 0xea, 0x7b, 0x91, 0x9a, 0x4d, 0x4e, - 0xa7, 0xf9, 0xda, 0x79, 0x3d, 0x2f, 0x52, 0xa4, 0x75, 0x6f, 0xe1, 0x5d, 0x9f, 0xfd, 0xb6, 0x7b, - 0x50, 0x1a, 0x48, 0x4b, 0x3e, 0x59, 0xb5, 0x65, 0xbd, 0x3c, 0x09, 0x44, 0x3b, 0x15, 0xc1, 0xa2, - 0xed, 0x45, 0x01, 0xc2, 0xa1, 0xe3, 0xb0, 0x4f, 0x25, 0xf4, 0xf6, 0x3d, 0x68, 0xbc, 0x1e, 0xf7, - 0xfb, 0xe4, 0x60, 0xfb, 0x0e, 0xd8, 0x79, 0x1c, 0x7f, 0xe7, 0x68, 0x95, 0x93, 0x77, 0x0d, 0x9c, - 0xd2, 0xbd, 0xd1, 0xf0, 0x54, 0x1a, 0x2a, 0xf6, 0xd5, 0xc6, 0x7d, 0x86, 0xff, 0x06, 0x7a, 0x8a, - 0x90, 0x0f, 0x00, 0xce, 0x84, 0x88, 0x1e, 0xcb, 0xb1, 0xa2, 0x0f, 0xb1, 0x51, 0x22, 0x2d, 0xc8, - 0x2e, 0x38, 0xb8, 0x49, 0xb4, 0x5e, 0x45, 0x2a, 0x3d, 0x12, 0x65, 0xf0, 0x7f, 0xb0, 0x67, 0xb9, - 0xbb, 0x1a, 0x1d, 0xd6, 0x2c, 0xf3, 0xfe, 0x1f, 0x58, 0x21, 0xd7, 0x3a, 0x35, 0xe5, 0xd6, 0x43, - 0x2e, 0x55, 0xee, 0x01, 0xfc, 0xe7, 0x8d, 0x1f, 0x19, 0x72, 0x05, 0xea, 0xb3, 0x60, 0x21, 0x64, - 0xbb, 0xe2, 0xe0, 0xd4, 0x3b, 0xf7, 0x17, 0x03, 0xa0, 0x68, 0x2d, 0x64, 0x04, 0xfb, 0x0e, 0x6d, - 0x36, 0x54, 0x9f, 0x2d, 0xc0, 0x5a, 0xea, 0x0c, 0xea, 0x3a, 0xba, 0xfa, 0x6a, 0x3b, 0xb6, 0xb2, - 0x04, 0xab, 0xdc, 0x76, 0x74, 0x6e, 0xdf, 0xe7, 0x67, 0x23, 0x3f, 0x61, 0xfb, 0x01, 0x6c, 0xbe, - 0x02, 0xf7, 0x8e, 0x9d, 0x5a, 0x54, 0x59, 0x29, 0x65, 0x37, 0x3e, 0x05, 0x3b, 0x1f, 0x82, 0xc4, - 0x82, 0x6a, 0x77, 0xf8, 0x45, 0xbf, 0xb1, 0x46, 0x00, 0xea, 0xe3, 0x41, 0x8f, 0x0e, 0x4e, 0x1a, - 0x06, 0x59, 0x87, 0xca, 0x78, 0x7c, 0xdc, 0x30, 0x89, 0x0d, 0xb5, 0xde, 0x51, 0xef, 0x78, 0xd0, - 0xa8, 0xe0, 0xf2, 0xe4, 0xe1, 0xa3, 0xfb, 0xe3, 0x46, 0xf5, 0xc6, 0x6d, 0xb8, 0xf0, 0xda, 0xa0, - 0x92, 0xde, 0xc7, 0x47, 0x74, 0x80, 0x48, 0x0e, 0xac, 0x3f, 0xa2, 0xc3, 0xd3, 0xa3, 0x93, 0x41, - 0xc3, 0x40, 0xc5, 0xe7, 0xa3, 0xde, 0x83, 0x41, 0xbf, 0x61, 0x76, 0x1b, 0xcf, 0x5f, 0xee, 0x18, - 0x3f, 0xbf, 0xdc, 0x31, 0x7e, 0x7f, 0xb9, 0x63, 0x7c, 0xfb, 0xc7, 0xce, 0xda, 0xa4, 0x2e, 0x7f, - 0xb0, 0x6f, 0xfd, 0x19, 0x00, 0x00, 0xff, 0xff, 0xa3, 0xba, 0x5c, 0x6e, 0xa0, 0x0b, 0x00, 0x00, + // 1371 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xcb, 0x6f, 0xdb, 0x46, + 0x13, 0x37, 0xa9, 0x87, 0xc5, 0xa1, 0xed, 0xe8, 0xdb, 0x3c, 0x3e, 0x7d, 0xfe, 0x52, 0xdb, 0x65, + 0x8a, 0xc2, 0xb1, 0x63, 0x19, 0x50, 0x80, 0x24, 0xe8, 0x21, 0xa8, 0xf5, 0x08, 0xac, 0xa6, 0xa9, + 0x8c, 0x95, 0xe1, 0x1e, 0x03, 0x9a, 0x5a, 0xc9, 0x44, 0x64, 0x2e, 0x41, 0xae, 0x52, 0xeb, 0xd2, + 0x43, 0xfe, 0x82, 0x02, 0x05, 0x7a, 0xef, 0xb1, 0x97, 0xfe, 0x07, 0xbd, 0xe7, 0xd8, 0x6b, 0x7b, + 0x48, 0x8b, 0xf4, 0x1f, 0x29, 0x66, 0x76, 0x29, 0x32, 0x8f, 0xa2, 0x09, 0xda, 0x13, 0x67, 0xe7, + 0xf1, 0xdb, 0xdd, 0xdf, 0xcc, 0xce, 0x10, 0x1c, 0x19, 0xa7, 0xcd, 0x38, 0x91, 0x4a, 0x32, 0x3b, + 0x3e, 0x5d, 0xdf, 0x9b, 0x84, 0xea, 0x6c, 0x76, 0xda, 0x0c, 0xe4, 0xf9, 0xfe, 0x44, 0x4e, 0xe4, + 0x3e, 0x99, 0x4e, 0x67, 0x63, 0x5a, 0xd1, 0x82, 0x24, 0x1d, 0xe2, 0x7d, 0x6f, 0x83, 0x3d, 0x88, + 0xd9, 0x87, 0x50, 0x0d, 0xa3, 0x78, 0xa6, 0xd2, 0x86, 0xb5, 0x55, 0xda, 0x76, 0x5b, 0x4e, 0x33, + 0x3e, 0x6d, 0xf6, 0x51, 0xc3, 0x8d, 0x81, 0x6d, 0x41, 0x59, 0x5c, 0x88, 0xa0, 0x61, 0x6f, 0x59, + 0xdb, 0x6e, 0x0b, 0xd0, 0xa1, 0x77, 0x21, 0x82, 0x41, 0x7c, 0xb8, 0xc4, 0xc9, 0xc2, 0x3e, 0x86, + 0x6a, 0x2a, 0x67, 0x49, 0x20, 0x1a, 0x25, 0xf2, 0x59, 0x41, 0x9f, 0x21, 0x69, 0xc8, 0xcb, 0x58, + 0x11, 0x29, 0x90, 0xf1, 0xbc, 0x51, 0xce, 0x91, 0x3a, 0x32, 0x9e, 0x6b, 0x24, 0xb4, 0xb0, 0x1b, + 0x50, 0x39, 0x9d, 0x85, 0xd3, 0x51, 0xa3, 0x42, 0x2e, 0x2e, 0xba, 0xb4, 0x51, 0x41, 0x3e, 0xda, + 0xc6, 0xb6, 0xa1, 0x16, 0x4f, 0x7d, 0x35, 0x96, 0xc9, 0x79, 0x03, 0xf2, 0x0d, 0x8f, 0x8c, 0x8e, + 0x2f, 0xac, 0xec, 0x2e, 0xb8, 0x81, 0x8c, 0x52, 0x95, 0xf8, 0x61, 0xa4, 0xd2, 0x86, 0x4b, 0xce, + 0x57, 0xd1, 0xf9, 0x4b, 0x99, 0x3c, 0x11, 0x49, 0x27, 0x37, 0xf2, 0xa2, 0x67, 0xbb, 0x0c, 0xb6, + 0x8c, 0xbd, 0xef, 0x2c, 0xa8, 0x65, 0xa8, 0xcc, 0x83, 0x95, 0x83, 0x24, 0x38, 0x0b, 0x95, 0x08, + 0xd4, 0x2c, 0x11, 0x0d, 0x6b, 0xcb, 0xda, 0x76, 0xf8, 0x2b, 0x3a, 0xb6, 0x06, 0xf6, 0x60, 0x48, + 0x44, 0x39, 0xdc, 0x1e, 0x0c, 0x59, 0x03, 0x96, 0x4f, 0xfc, 0x24, 0xf4, 0x23, 0x45, 0xcc, 0x38, + 0x3c, 0x5b, 0xb2, 0xeb, 0xe0, 0x0c, 0x86, 0x27, 0x22, 0x49, 0x43, 0x19, 0x11, 0x1f, 0x0e, 0xcf, + 0x15, 0x6c, 0x03, 0x60, 0x30, 0x7c, 0x20, 0x7c, 0x04, 0x4d, 0x1b, 0x95, 0xad, 0xd2, 0xb6, 0xc3, + 0x0b, 0x1a, 0xef, 0x6b, 0xa8, 0x50, 0x8e, 0xd8, 0x67, 0x50, 0x1d, 0x85, 0x13, 0x91, 0x2a, 0x7d, + 0x9c, 0x76, 0xeb, 0xf9, 0x8b, 0xcd, 0xa5, 0x5f, 0x5f, 0x6c, 0xee, 0x14, 0x8a, 0x41, 0xc6, 0x22, + 0x0a, 0x64, 0xa4, 0xfc, 0x30, 0x12, 0x49, 0xba, 0x3f, 0x91, 0x7b, 0x3a, 0xa4, 0xd9, 0xa5, 0x0f, + 0x37, 0x08, 0xec, 0x26, 0x54, 0xc2, 0x68, 0x24, 0x2e, 0xe8, 0xfc, 0xa5, 0xf6, 0x65, 0x03, 0xe5, + 0x0e, 0x66, 0x2a, 0x9e, 0xa9, 0x3e, 0x9a, 0xb8, 0xf6, 0xf0, 0xfa, 0x50, 0xd5, 0x25, 0xc0, 0xae, + 0x43, 0xf9, 0x5c, 0x28, 0x9f, 0xb6, 0x77, 0x5b, 0x35, 0xa4, 0xf6, 0x91, 0x50, 0x3e, 0x27, 0x2d, + 0x56, 0xd7, 0xb9, 0x9c, 0x21, 0xf5, 0x76, 0x5e, 0x5d, 0x8f, 0x50, 0xc3, 0x8d, 0xc1, 0xfb, 0xc1, + 0x82, 0x32, 0x46, 0x30, 0x06, 0x65, 0x3f, 0x99, 0xe8, 0x3a, 0x74, 0x38, 0xc9, 0xac, 0x0e, 0x25, + 0x11, 0x3d, 0xa5, 0x60, 0x87, 0xa3, 0x88, 0x9a, 0xe0, 0xab, 0x91, 0x61, 0x13, 0x45, 0x8c, 0x9b, + 0xa5, 0x22, 0x31, 0x24, 0x92, 0xcc, 0x6e, 0x82, 0x13, 0x27, 0xf2, 0x62, 0xfe, 0x18, 0xa3, 0x2b, + 0x85, 0x12, 0x41, 0x65, 0x2f, 0x7a, 0xca, 0x6b, 0xb1, 0x91, 0xd8, 0x0e, 0x80, 0xb8, 0x50, 0x89, + 0x7f, 0x28, 0x53, 0x95, 0x36, 0xaa, 0x74, 0x4c, 0xaa, 0x4c, 0x54, 0xf4, 0x8f, 0x78, 0xc1, 0xea, + 0xfd, 0x68, 0x43, 0x85, 0x4e, 0xcf, 0xb6, 0x91, 0xab, 0x78, 0xa6, 0x69, 0x2f, 0xb5, 0x99, 0xe1, + 0x0a, 0x28, 0x2b, 0x0b, 0xaa, 0x30, 0x43, 0xeb, 0x50, 0x4b, 0xc5, 0x54, 0x04, 0x4a, 0x26, 0xa6, + 0x30, 0x16, 0x6b, 0x3c, 0xfa, 0x08, 0x73, 0xa7, 0x6f, 0x43, 0x32, 0xdb, 0x85, 0xaa, 0x24, 0xc2, + 0xe9, 0x42, 0x7f, 0x91, 0x06, 0xe3, 0x82, 0xe0, 0x89, 0xf0, 0x47, 0x32, 0x9a, 0xce, 0xe9, 0x9a, + 0x35, 0xbe, 0x58, 0xb3, 0x5d, 0x70, 0x88, 0xe2, 0xe3, 0x79, 0x2c, 0x1a, 0xd5, 0x2d, 0x6b, 0x7b, + 0xad, 0xb5, 0xba, 0xa0, 0x1f, 0x95, 0x3c, 0xb7, 0xe3, 0x93, 0x0a, 0xfc, 0xe0, 0x4c, 0x0c, 0x62, + 0xd5, 0xb8, 0x92, 0xf3, 0xd5, 0x31, 0x3a, 0xbe, 0xb0, 0x22, 0x6c, 0x2a, 0x82, 0x44, 0x28, 0x74, + 0xbd, 0x4a, 0xae, 0x04, 0x3b, 0xcc, 0x94, 0x3c, 0xb7, 0x7b, 0x7d, 0xa8, 0x65, 0x10, 0xf8, 0x36, + 0xfa, 0x5d, 0xf3, 0x6a, 0xec, 0x7e, 0x97, 0xed, 0xc1, 0x72, 0x7a, 0xe6, 0x27, 0x61, 0x34, 0x21, + 0x5e, 0xd6, 0x5a, 0x97, 0x17, 0x3b, 0x0e, 0xb5, 0x1e, 0xc1, 0x32, 0x1f, 0x4f, 0x82, 0xb3, 0xd8, + 0xe2, 0x0d, 0xac, 0x3a, 0x94, 0x66, 0xe1, 0x88, 0x70, 0x56, 0x39, 0x8a, 0xa8, 0x99, 0x84, 0xba, + 0x4e, 0x56, 0x39, 0x8a, 0x48, 0xf6, 0xb9, 0x1c, 0x09, 0xa2, 0x75, 0x95, 0x93, 0x8c, 0xfc, 0xc9, + 0x58, 0x85, 0x32, 0xf2, 0xa7, 0x19, 0x7f, 0xd9, 0xda, 0xbb, 0x0f, 0x55, 0xdd, 0x9c, 0xd8, 0x16, + 0x94, 0xd2, 0x24, 0x30, 0x0d, 0x72, 0x2d, 0xeb, 0x5a, 0xba, 0xbf, 0x71, 0x34, 0x2d, 0x12, 0x69, + 0xe7, 0x89, 0xf4, 0x38, 0x40, 0xee, 0xf6, 0xef, 0x14, 0x8c, 0xf7, 0xad, 0x05, 0xb5, 0xac, 0xaf, + 0x62, 0x93, 0x08, 0x47, 0x22, 0x52, 0xe1, 0x38, 0x14, 0x89, 0x21, 0xa3, 0xa0, 0x61, 0x7b, 0x50, + 0xf1, 0x95, 0x4a, 0xb2, 0xb7, 0xf7, 0xdf, 0x62, 0x53, 0x6e, 0x1e, 0xa0, 0xa5, 0x17, 0xa9, 0x64, + 0xce, 0xb5, 0xd7, 0xfa, 0x3d, 0x80, 0x5c, 0x89, 0xfc, 0x3d, 0x11, 0x73, 0x83, 0x8a, 0x22, 0xbb, + 0x02, 0x95, 0xa7, 0xfe, 0x74, 0x26, 0xcc, 0xa1, 0xf4, 0xe2, 0x13, 0xfb, 0x9e, 0xe5, 0xfd, 0x64, + 0xc3, 0xb2, 0x69, 0xd2, 0xec, 0x16, 0x2c, 0x53, 0x93, 0x36, 0x27, 0x7a, 0xfb, 0x4d, 0x33, 0x17, + 0xb6, 0xbf, 0x98, 0x3e, 0x85, 0x33, 0x1a, 0x28, 0x3d, 0x85, 0xcc, 0x19, 0xf3, 0x59, 0x54, 0x1a, + 0x89, 0xb1, 0x19, 0x33, 0x94, 0x8a, 0xae, 0x18, 0x87, 0x51, 0x88, 0x39, 0xe3, 0x68, 0x62, 0xb7, + 0xb2, 0x5b, 0x97, 0x09, 0xf1, 0x5a, 0x11, 0xf1, 0xcd, 0x4b, 0xf7, 0xc1, 0x2d, 0x6c, 0xf3, 0x96, + 0x5b, 0x7f, 0x54, 0xbc, 0xb5, 0xd9, 0x92, 0xe0, 0xf4, 0x8c, 0xcc, 0x59, 0xf8, 0x07, 0xfc, 0xdd, + 0x01, 0xc8, 0x21, 0xdf, 0xbd, 0x52, 0xbc, 0x67, 0x25, 0x80, 0x41, 0x8c, 0xcd, 0x73, 0xe4, 0x53, + 0xb3, 0x5d, 0x09, 0x27, 0x91, 0x4c, 0xc4, 0x63, 0x7a, 0xac, 0x14, 0x5f, 0xe3, 0xae, 0xd6, 0xd1, + 0xbb, 0x62, 0x07, 0xe0, 0x8e, 0x44, 0x1a, 0x24, 0x21, 0x15, 0xb9, 0x21, 0x7d, 0x13, 0xef, 0x94, + 0xe3, 0x34, 0xbb, 0xb9, 0x87, 0xe6, 0xaa, 0x18, 0xc3, 0x5a, 0xb0, 0x22, 0x2e, 0x62, 0x99, 0x28, + 0xb3, 0x8b, 0x9e, 0xe5, 0x97, 0xf4, 0x5f, 0x01, 0xea, 0x69, 0x27, 0xee, 0x8a, 0x7c, 0xc1, 0x7c, + 0x28, 0x07, 0x7e, 0xac, 0x07, 0x99, 0xdb, 0x6a, 0xbc, 0xb6, 0x5f, 0xc7, 0x8f, 0x35, 0x69, 0xed, + 0xdb, 0x78, 0xd7, 0x67, 0xbf, 0x6d, 0xee, 0x16, 0xa6, 0xd7, 0xb9, 0x3c, 0x9d, 0xef, 0x53, 0xbd, + 0x3c, 0x09, 0xd5, 0xfe, 0x4c, 0x85, 0xd3, 0x7d, 0x3f, 0x0e, 0x11, 0x0e, 0x03, 0xfb, 0x5d, 0x4e, + 0xd0, 0xeb, 0xf7, 0xa1, 0xfe, 0xfa, 0xb9, 0xdf, 0x27, 0x07, 0xeb, 0x77, 0xc1, 0x59, 0x9c, 0xe3, + 0xef, 0x02, 0x6b, 0xc5, 0xe4, 0xdd, 0x00, 0xb7, 0x70, 0x6f, 0x74, 0x3c, 0x21, 0x47, 0xcd, 0xbe, + 0x5e, 0x78, 0xcf, 0xf0, 0x47, 0x22, 0x9b, 0x38, 0x1f, 0x00, 0x9c, 0x29, 0x15, 0x3f, 0xa6, 0x11, + 0x64, 0x36, 0x71, 0x50, 0x43, 0x1e, 0x6c, 0x13, 0x5c, 0x5c, 0xa4, 0xc6, 0xae, 0x4f, 0x4a, 0x11, + 0xa9, 0x76, 0xf8, 0x3f, 0x38, 0xe3, 0x45, 0xb8, 0x1e, 0x1d, 0xb5, 0x71, 0x16, 0xfd, 0x3f, 0xa8, + 0x45, 0xd2, 0xd8, 0xf4, 0x44, 0x5c, 0x8e, 0x24, 0x99, 0xbc, 0x5d, 0xf8, 0xcf, 0x1b, 0x7f, 0x3d, + 0xec, 0x1a, 0x54, 0xc7, 0xe1, 0x54, 0xd1, 0x73, 0xc5, 0x21, 0x6b, 0x56, 0xde, 0x2f, 0x16, 0x40, + 0xfe, 0xb4, 0x90, 0x11, 0x7c, 0x77, 0xe8, 0xb3, 0xa2, 0xdf, 0xd9, 0x14, 0x6a, 0xe7, 0x26, 0x83, + 0xa6, 0x8e, 0xae, 0xbf, 0xfa, 0x1c, 0x9b, 0x59, 0x82, 0x75, 0x6e, 0x5b, 0x26, 0xb7, 0xef, 0xf3, + 0x67, 0xb2, 0xd8, 0x61, 0xfd, 0x21, 0xac, 0xbe, 0x02, 0xf7, 0x8e, 0x2f, 0x35, 0xaf, 0xb2, 0x62, + 0xca, 0x6e, 0x41, 0x55, 0x0f, 0x77, 0xec, 0xdb, 0x28, 0x19, 0x18, 0x92, 0x69, 0xb6, 0x1c, 0x65, + 0xff, 0x70, 0xfd, 0xa3, 0x9d, 0x4f, 0xc1, 0x59, 0x8c, 0x4c, 0x56, 0x83, 0x72, 0xbb, 0xff, 0x45, + 0xb7, 0xbe, 0xc4, 0x00, 0xaa, 0xc3, 0x5e, 0x87, 0xf7, 0x8e, 0xeb, 0x16, 0x5b, 0x86, 0xd2, 0x70, + 0x78, 0x58, 0xb7, 0x99, 0x03, 0x95, 0xce, 0x41, 0xe7, 0xb0, 0x57, 0x2f, 0xa1, 0x78, 0xfc, 0xe8, + 0xe8, 0xc1, 0xb0, 0x5e, 0xde, 0xb9, 0x03, 0x97, 0x5e, 0x1b, 0x6b, 0x14, 0x7d, 0x78, 0xc0, 0x7b, + 0x88, 0xe4, 0xc2, 0xf2, 0x11, 0xef, 0x9f, 0x1c, 0x1c, 0xf7, 0xea, 0x16, 0x1a, 0x3e, 0x1f, 0x74, + 0x1e, 0xf6, 0xba, 0x75, 0xbb, 0x5d, 0x7f, 0xfe, 0x72, 0xc3, 0xfa, 0xf9, 0xe5, 0x86, 0xf5, 0xfb, + 0xcb, 0x0d, 0xeb, 0x9b, 0x3f, 0x36, 0x96, 0x4e, 0xab, 0xf4, 0xef, 0x7e, 0xfb, 0xcf, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x5f, 0x7b, 0x2c, 0xa4, 0xfb, 0x0b, 0x00, 0x00, } diff --git a/solver/pb/ops.proto b/solver/pb/ops.proto index 50ed763b..945df067 100644 --- a/solver/pb/ops.proto +++ b/solver/pb/ops.proto @@ -52,6 +52,7 @@ message Meta { string cwd = 3; string user = 4; ProxyEnv proxy_env = 5; + repeated HostIP extraHosts = 6; } // Mount specifies how to mount an input Op as a filesystem. @@ -181,3 +182,8 @@ message Definition { // A key must be an LLB op digest string. Currently, empty string is not expected as a key, but it may change in the future. map metadata = 2 [(gogoproto.castkey) = "github.com/opencontainers/go-digest.Digest", (gogoproto.nullable) = false]; } + +message HostIP { + string Host = 1; + string IP = 2; +} \ No newline at end of file From f7359f7093545f6674b2df70169a8aeb3c90a0dc Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Wed, 1 Aug 2018 16:11:34 -0700 Subject: [PATCH 2/5] llb: add extrahost support Signed-off-by: Tonis Tiigi --- client/llb/exec.go | 39 ++++++++++++++++++++++++++++----------- client/llb/meta.go | 31 ++++++++++++++++++++++++++----- client/llb/state.go | 16 +++++++++++----- 3 files changed, 65 insertions(+), 21 deletions(-) diff --git a/client/llb/exec.go b/client/llb/exec.go index c5a66774..a0f2e41e 100644 --- a/client/llb/exec.go +++ b/client/llb/exec.go @@ -2,6 +2,7 @@ package llb import ( _ "crypto/sha256" + "net" "sort" "github.com/moby/buildkit/solver/pb" @@ -10,11 +11,12 @@ import ( ) type Meta struct { - Args []string - Env EnvList - Cwd string - User string - ProxyEnv *ProxyEnv + Args []string + Env EnvList + Cwd string + User string + ProxyEnv *ProxyEnv + ExtraHosts []HostIP } func NewExecOp(root Output, meta Meta, readOnly bool, c Constraints) *ExecOp { @@ -127,13 +129,22 @@ func (e *ExecOp) Marshal(c *Constraints) (digest.Digest, []byte, *pb.OpMetadata, return e.mounts[i].target < e.mounts[j].target }) + meta := &pb.Meta{ + Args: e.meta.Args, + Env: e.meta.Env.ToArray(), + Cwd: e.meta.Cwd, + User: e.meta.User, + } + if len(e.meta.ExtraHosts) > 0 { + hosts := make([]*pb.HostIP, len(e.meta.ExtraHosts)) + for i, h := range e.meta.ExtraHosts { + hosts[i] = &pb.HostIP{Host: h.Host, IP: h.IP.String()} + } + meta.ExtraHosts = hosts + } + peo := &pb.ExecOp{ - Meta: &pb.Meta{ - Args: e.meta.Args, - Env: e.meta.Env.ToArray(), - Cwd: e.meta.Cwd, - User: e.meta.User, - }, + Meta: meta, } if p := e.meta.ProxyEnv; p != nil { @@ -386,6 +397,12 @@ func Dirf(str string, v ...interface{}) RunOption { }) } +func AddExtraHost(host string, ip net.IP) RunOption { + return runOptionFunc(func(ei *ExecInfo) { + ei.State = ei.State.AddExtraHost(host, ip) + }) +} + func Reset(s State) RunOption { return runOptionFunc(func(ei *ExecInfo) { ei.State = ei.State.Reset(s) diff --git a/client/llb/meta.go b/client/llb/meta.go index 22aea097..f4cafd83 100644 --- a/client/llb/meta.go +++ b/client/llb/meta.go @@ -2,6 +2,7 @@ package llb import ( "fmt" + "net" "path" "github.com/containerd/containerd/platforms" @@ -12,11 +13,12 @@ import ( type contextKeyT string var ( - keyArgs = contextKeyT("llb.exec.args") - keyDir = contextKeyT("llb.exec.dir") - keyEnv = contextKeyT("llb.exec.env") - keyUser = contextKeyT("llb.exec.user") - keyPlatform = contextKeyT("llb.platform") + keyArgs = contextKeyT("llb.exec.args") + keyDir = contextKeyT("llb.exec.dir") + keyEnv = contextKeyT("llb.exec.env") + keyUser = contextKeyT("llb.exec.user") + keyExtraHost = contextKeyT("llb.exec.extrahost") + keyPlatform = contextKeyT("llb.platform") ) func addEnv(key, value string) StateOption { @@ -124,6 +126,25 @@ func getPlatform(s State) *specs.Platform { return nil } +func extraHost(host string, ip net.IP) StateOption { + return func(s State) State { + return s.WithValue(keyExtraHost, append(getExtraHosts(s), HostIP{Host: host, IP: ip})) + } +} + +func getExtraHosts(s State) []HostIP { + v := s.Value(keyExtraHost) + if v != nil { + return v.([]HostIP) + } + return nil +} + +type HostIP struct { + Host string + IP net.IP +} + type EnvList []KeyValue type KeyValue struct { diff --git a/client/llb/state.go b/client/llb/state.go index 669e6467..b0026755 100644 --- a/client/llb/state.go +++ b/client/llb/state.go @@ -3,6 +3,7 @@ package llb import ( "context" "fmt" + "net" "github.com/containerd/containerd/platforms" "github.com/moby/buildkit/identity" @@ -181,11 +182,12 @@ func (s State) Run(ro ...RunOption) ExecState { o.SetRunOption(ei) } meta := Meta{ - Args: getArgs(ei.State), - Cwd: getDir(ei.State), - Env: getEnv(ei.State), - User: getUser(ei.State), - ProxyEnv: ei.ProxyEnv, + Args: getArgs(ei.State), + Cwd: getDir(ei.State), + Env: getEnv(ei.State), + User: getUser(ei.State), + ProxyEnv: ei.ProxyEnv, + ExtraHosts: getExtraHosts(ei.State), } exec := NewExecOp(s.Output(), meta, ei.ReadonlyRootFS, ei.Constraints) @@ -254,6 +256,10 @@ func (s State) With(so ...StateOption) State { return s } +func (s State) AddExtraHost(host string, ip net.IP) State { + return extraHost(host, ip)(s) +} + type output struct { vertex Vertex getIndex func() (pb.OutputIndex, error) From bf29f5bd3bd5be5451a77b9b8f4af6604dc3ec26 Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Wed, 1 Aug 2018 16:59:32 -0700 Subject: [PATCH 3/5] client: add test for extra hosts Signed-off-by: Tonis Tiigi --- client/client_test.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/client/client_test.go b/client/client_test.go index 5f8a7031..52dae2ba 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "io/ioutil" + "net" "net/http" "os" "path/filepath" @@ -59,9 +60,27 @@ func TestClientIntegration(t *testing.T) { testDuplicateCacheMount, testParallelLocalBuilds, testSecretMounts, + testExtraHosts, }) } +func testExtraHosts(t *testing.T, sb integration.Sandbox) { + t.Parallel() + + c, err := New(context.TODO(), sb.Address()) + require.NoError(t, err) + defer c.Close() + + st := llb.Image("busybox:latest"). + Run(llb.Shlex(`sh -c 'cat /etc/hosts | grep myhost | grep 1.2.3.4'`), llb.AddExtraHost("myhost", net.ParseIP("1.2.3.4"))) + + def, err := st.Marshal() + require.NoError(t, err) + + _, err = c.Solve(context.TODO(), def, SolveOpt{}, nil) + require.NoError(t, err) +} + func testSecretMounts(t *testing.T, sb integration.Sandbox) { t.Parallel() From f8b0573edb5515ceca83be135ecb6e2f356836af Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Thu, 2 Aug 2018 12:00:27 -0700 Subject: [PATCH 4/5] dockerfile: expose add-hosts Signed-off-by: Tonis Tiigi --- frontend/dockerfile/builder/build.go | 35 +++++++++++++++++++ frontend/dockerfile/dockerfile2llb/convert.go | 6 ++++ 2 files changed, 41 insertions(+) diff --git a/frontend/dockerfile/builder/build.go b/frontend/dockerfile/builder/build.go index ab7cfe3b..de06462d 100644 --- a/frontend/dockerfile/builder/build.go +++ b/frontend/dockerfile/builder/build.go @@ -4,8 +4,10 @@ import ( "archive/tar" "bytes" "context" + "encoding/csv" "encoding/json" "fmt" + "net" "regexp" "strconv" "strings" @@ -36,6 +38,7 @@ const ( keyTargetPlatform = "platform" keyMultiPlatform = "multi-platform" keyImageResolveMode = "image-resolve-mode" + keyGlobalAddHosts = "add-hosts" ) var httpPrefix = regexp.MustCompile("^https?://") @@ -64,6 +67,11 @@ func Build(ctx context.Context, c client.Client) (*client.Result, error) { return nil, err } + extraHosts, err := parseExtraHosts(opts[keyGlobalAddHosts]) + if err != nil { + return nil, errors.Wrap(err, "failed to parse additional hosts") + } + filename := opts[keyFilename] if filename == "" { filename = defaultDockerfileName @@ -250,6 +258,7 @@ func Build(ctx context.Context, c client.Client) (*client.Result, error) { BuildPlatforms: buildPlatforms, ImageResolveMode: resolveMode, PrefixPlatform: exportMap, + ExtraHosts: extraHosts, }) if err != nil { @@ -413,3 +422,29 @@ func parseResolveMode(v string) (llb.ResolveMode, error) { return 0, errors.Errorf("invalid image-resolve-mode: %s", v) } } + +func parseExtraHosts(v string) ([]llb.HostIP, error) { + if v == "" { + return nil, nil + } + out := make([]llb.HostIP, 0) + csvReader := csv.NewReader(strings.NewReader(v)) + fields, err := csvReader.Read() + if err != nil { + return nil, err + } + for _, field := range fields { + parts := strings.SplitN(field, "=", 2) + if len(parts) != 2 { + return nil, errors.Errorf("invalid key-value pair %s", field) + } + key := strings.ToLower(parts[0]) + val := strings.ToLower(parts[1]) + ip := net.ParseIP(val) + if ip == nil { + return nil, errors.Errorf("failed to parse IP %s", val) + } + out = append(out, llb.HostIP{Host: key, IP: ip}) + } + return out, nil +} diff --git a/frontend/dockerfile/dockerfile2llb/convert.go b/frontend/dockerfile/dockerfile2llb/convert.go index 484b3e42..75be1f33 100644 --- a/frontend/dockerfile/dockerfile2llb/convert.go +++ b/frontend/dockerfile/dockerfile2llb/convert.go @@ -52,6 +52,7 @@ type ConvertOpt struct { TargetPlatform *specs.Platform BuildPlatforms []specs.Platform PrefixPlatform bool + ExtraHosts []llb.HostIP } func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State, *Image, error) { @@ -294,6 +295,7 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State, cacheIDNamespace: opt.CacheIDNamespace, buildPlatforms: platformOpt.buildPlatforms, targetPlatform: platformOpt.targetPlatform, + extraHosts: opt.ExtraHosts, } if err = dispatchOnBuild(d, d.image.Config.OnBuild, opt); err != nil { @@ -397,6 +399,7 @@ type dispatchOpt struct { cacheIDNamespace string targetPlatform specs.Platform buildPlatforms []specs.Platform + extraHosts []llb.HostIP } func dispatch(d *dispatchState, cmd command, opt dispatchOpt) error { @@ -584,6 +587,9 @@ func dispatchRun(d *dispatchState, c *instructions.RunCommand, proxy *llb.ProxyE } opt = append(opt, runMounts...) opt = append(opt, llb.WithCustomName(prefixCommand(d, uppercaseCmd(processCmdEnv(dopt.shlex, c.String(), d.state.Run(opt...).Env())), d.prefixPlatform, d.state.GetPlatform()))) + for _, h := range dopt.extraHosts { + opt = append(opt, llb.AddExtraHost(h.Host, h.IP)) + } d.state = d.state.Run(opt...).Root() return commitToHistory(&d.image, "RUN "+runCommandString(args, d.buildArgs), true, &d.state) } From 96f24ca7bb57206cf0da7370e508b91dbb582d71 Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Fri, 3 Aug 2018 14:01:54 -0700 Subject: [PATCH 5/5] executor: improve hosts cleanup Signed-off-by: Tonis Tiigi --- executor/containerdexecutor/executor.go | 7 +++---- executor/oci/hosts.go | 26 +++++++++++++------------ executor/runcexecutor/executor.go | 6 +++--- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/executor/containerdexecutor/executor.go b/executor/containerdexecutor/executor.go index f271f036..cb076686 100644 --- a/executor/containerdexecutor/executor.go +++ b/executor/containerdexecutor/executor.go @@ -3,7 +3,6 @@ package containerdexecutor import ( "context" "io" - "os" "syscall" "time" @@ -40,12 +39,12 @@ func (w containerdExecutor) Exec(ctx context.Context, meta executor.Meta, root c return err } - hostsFile, err := oci.GetHostsFile(ctx, w.root, meta.ExtraHosts) + hostsFile, clean, err := oci.GetHostsFile(ctx, w.root, meta.ExtraHosts) if err != nil { return err } - if len(meta.ExtraHosts) > 0 { - defer os.RemoveAll(hostsFile) + if clean != nil { + defer clean() } mountable, err := root.Mount(ctx, false) diff --git a/executor/oci/hosts.go b/executor/oci/hosts.go index d01b9e6e..405d758d 100644 --- a/executor/oci/hosts.go +++ b/executor/oci/hosts.go @@ -17,51 +17,53 @@ const hostsContent = ` ::1 localhost ip6-localhost ip6-loopback ` -func GetHostsFile(ctx context.Context, stateDir string, extraHosts []executor.HostIP) (string, error) { +func GetHostsFile(ctx context.Context, stateDir string, extraHosts []executor.HostIP) (string, func(), error) { if len(extraHosts) == 0 { _, err := g.Do(ctx, stateDir, func(ctx context.Context) (interface{}, error) { - _, err := makeHostsFile(stateDir, nil) + _, _, err := makeHostsFile(stateDir, nil) return nil, err }) if err != nil { - return "", err + return "", nil, err } - return filepath.Join(stateDir, "hosts"), nil + return filepath.Join(stateDir, "hosts"), func() {}, nil } return makeHostsFile(stateDir, extraHosts) } -func makeHostsFile(stateDir string, extraHosts []executor.HostIP) (string, error) { +func makeHostsFile(stateDir string, extraHosts []executor.HostIP) (string, func(), error) { p := filepath.Join(stateDir, "hosts") if len(extraHosts) != 0 { p += "." + identity.NewID() } _, err := os.Stat(p) if err == nil { - return "", nil + return "", func() {}, nil } if !os.IsNotExist(err) { - return "", err + return "", nil, err } b := &bytes.Buffer{} if _, err := b.Write([]byte(hostsContent)); err != nil { - return "", err + return "", nil, err } for _, h := range extraHosts { if _, err := b.Write([]byte(fmt.Sprintf("%s\t%s\n", h.IP.String(), h.Host))); err != nil { - return "", err + return "", nil, err } } if err := ioutil.WriteFile(p+".tmp", b.Bytes(), 0644); err != nil { - return "", err + return "", nil, err } if err := os.Rename(p+".tmp", p); err != nil { - return "", err + return "", nil, err } - return p, nil + return p, func() { + os.RemoveAll(p) + }, nil } diff --git a/executor/runcexecutor/executor.go b/executor/runcexecutor/executor.go index 75bce875..123a02dc 100644 --- a/executor/runcexecutor/executor.go +++ b/executor/runcexecutor/executor.go @@ -103,12 +103,12 @@ func (w *runcExecutor) Exec(ctx context.Context, meta executor.Meta, root cache. return err } - hostsFile, err := oci.GetHostsFile(ctx, w.root, meta.ExtraHosts) + hostsFile, clean, err := oci.GetHostsFile(ctx, w.root, meta.ExtraHosts) if err != nil { return err } - if len(meta.ExtraHosts) > 0 { - defer os.RemoveAll(hostsFile) + if clean != nil { + defer clean() } mountable, err := root.Mount(ctx, false)