Merge pull request #232 from AkihiroSuda/worker-annotations

worker: add annotation labels
docker-18.09
Tõnis Tiigi 2017-12-19 23:38:26 -08:00 committed by GitHub
commit 35bef6ee34
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 1137 additions and 176 deletions

View File

@ -1,6 +1,5 @@
// Code generated by protoc-gen-gogo. // Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: control.proto // source: control.proto
// DO NOT EDIT!
/* /*
Package moby_buildkit_v1 is a generated protocol buffer package. Package moby_buildkit_v1 is a generated protocol buffer package.
@ -21,6 +20,9 @@
VertexStatus VertexStatus
VertexLog VertexLog
BytesMessage BytesMessage
ListWorkersRequest
ListWorkersResponse
WorkerRecord
*/ */
package moby_buildkit_v1 package moby_buildkit_v1
@ -492,6 +494,62 @@ func (m *BytesMessage) GetData() []byte {
return nil return nil
} }
type ListWorkersRequest struct {
Filter []string `protobuf:"bytes,1,rep,name=filter" json:"filter,omitempty"`
}
func (m *ListWorkersRequest) Reset() { *m = ListWorkersRequest{} }
func (m *ListWorkersRequest) String() string { return proto.CompactTextString(m) }
func (*ListWorkersRequest) ProtoMessage() {}
func (*ListWorkersRequest) Descriptor() ([]byte, []int) { return fileDescriptorControl, []int{12} }
func (m *ListWorkersRequest) GetFilter() []string {
if m != nil {
return m.Filter
}
return nil
}
type ListWorkersResponse struct {
Record []*WorkerRecord `protobuf:"bytes,1,rep,name=record" json:"record,omitempty"`
}
func (m *ListWorkersResponse) Reset() { *m = ListWorkersResponse{} }
func (m *ListWorkersResponse) String() string { return proto.CompactTextString(m) }
func (*ListWorkersResponse) ProtoMessage() {}
func (*ListWorkersResponse) Descriptor() ([]byte, []int) { return fileDescriptorControl, []int{13} }
func (m *ListWorkersResponse) GetRecord() []*WorkerRecord {
if m != nil {
return m.Record
}
return nil
}
type WorkerRecord struct {
ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
Labels map[string]string `protobuf:"bytes,2,rep,name=Labels" json:"Labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
}
func (m *WorkerRecord) Reset() { *m = WorkerRecord{} }
func (m *WorkerRecord) String() string { return proto.CompactTextString(m) }
func (*WorkerRecord) ProtoMessage() {}
func (*WorkerRecord) Descriptor() ([]byte, []int) { return fileDescriptorControl, []int{14} }
func (m *WorkerRecord) GetID() string {
if m != nil {
return m.ID
}
return ""
}
func (m *WorkerRecord) GetLabels() map[string]string {
if m != nil {
return m.Labels
}
return nil
}
func init() { func init() {
proto.RegisterType((*DiskUsageRequest)(nil), "moby.buildkit.v1.DiskUsageRequest") proto.RegisterType((*DiskUsageRequest)(nil), "moby.buildkit.v1.DiskUsageRequest")
proto.RegisterType((*DiskUsageResponse)(nil), "moby.buildkit.v1.DiskUsageResponse") proto.RegisterType((*DiskUsageResponse)(nil), "moby.buildkit.v1.DiskUsageResponse")
@ -505,6 +563,9 @@ func init() {
proto.RegisterType((*VertexStatus)(nil), "moby.buildkit.v1.VertexStatus") proto.RegisterType((*VertexStatus)(nil), "moby.buildkit.v1.VertexStatus")
proto.RegisterType((*VertexLog)(nil), "moby.buildkit.v1.VertexLog") proto.RegisterType((*VertexLog)(nil), "moby.buildkit.v1.VertexLog")
proto.RegisterType((*BytesMessage)(nil), "moby.buildkit.v1.BytesMessage") proto.RegisterType((*BytesMessage)(nil), "moby.buildkit.v1.BytesMessage")
proto.RegisterType((*ListWorkersRequest)(nil), "moby.buildkit.v1.ListWorkersRequest")
proto.RegisterType((*ListWorkersResponse)(nil), "moby.buildkit.v1.ListWorkersResponse")
proto.RegisterType((*WorkerRecord)(nil), "moby.buildkit.v1.WorkerRecord")
} }
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.
@ -522,6 +583,7 @@ type ControlClient interface {
Solve(ctx context.Context, in *SolveRequest, opts ...grpc.CallOption) (*SolveResponse, error) Solve(ctx context.Context, in *SolveRequest, opts ...grpc.CallOption) (*SolveResponse, error)
Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (Control_StatusClient, error) Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (Control_StatusClient, error)
Session(ctx context.Context, opts ...grpc.CallOption) (Control_SessionClient, error) Session(ctx context.Context, opts ...grpc.CallOption) (Control_SessionClient, error)
ListWorkers(ctx context.Context, in *ListWorkersRequest, opts ...grpc.CallOption) (*ListWorkersResponse, error)
} }
type controlClient struct { type controlClient struct {
@ -613,6 +675,15 @@ func (x *controlSessionClient) Recv() (*BytesMessage, error) {
return m, nil return m, nil
} }
func (c *controlClient) ListWorkers(ctx context.Context, in *ListWorkersRequest, opts ...grpc.CallOption) (*ListWorkersResponse, error) {
out := new(ListWorkersResponse)
err := grpc.Invoke(ctx, "/moby.buildkit.v1.Control/ListWorkers", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for Control service // Server API for Control service
type ControlServer interface { type ControlServer interface {
@ -620,6 +691,7 @@ type ControlServer interface {
Solve(context.Context, *SolveRequest) (*SolveResponse, error) Solve(context.Context, *SolveRequest) (*SolveResponse, error)
Status(*StatusRequest, Control_StatusServer) error Status(*StatusRequest, Control_StatusServer) error
Session(Control_SessionServer) error Session(Control_SessionServer) error
ListWorkers(context.Context, *ListWorkersRequest) (*ListWorkersResponse, error)
} }
func RegisterControlServer(s *grpc.Server, srv ControlServer) { func RegisterControlServer(s *grpc.Server, srv ControlServer) {
@ -709,6 +781,24 @@ func (x *controlSessionServer) Recv() (*BytesMessage, error) {
return m, nil return m, nil
} }
func _Control_ListWorkers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListWorkersRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ControlServer).ListWorkers(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/moby.buildkit.v1.Control/ListWorkers",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ControlServer).ListWorkers(ctx, req.(*ListWorkersRequest))
}
return interceptor(ctx, in, info, handler)
}
var _Control_serviceDesc = grpc.ServiceDesc{ var _Control_serviceDesc = grpc.ServiceDesc{
ServiceName: "moby.buildkit.v1.Control", ServiceName: "moby.buildkit.v1.Control",
HandlerType: (*ControlServer)(nil), HandlerType: (*ControlServer)(nil),
@ -721,6 +811,10 @@ var _Control_serviceDesc = grpc.ServiceDesc{
MethodName: "Solve", MethodName: "Solve",
Handler: _Control_Solve_Handler, Handler: _Control_Solve_Handler,
}, },
{
MethodName: "ListWorkers",
Handler: _Control_ListWorkers_Handler,
},
}, },
Streams: []grpc.StreamDesc{ Streams: []grpc.StreamDesc{
{ {
@ -1330,6 +1424,110 @@ func (m *BytesMessage) MarshalTo(dAtA []byte) (int, error) {
return i, nil return i, nil
} }
func (m *ListWorkersRequest) 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 *ListWorkersRequest) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if len(m.Filter) > 0 {
for _, s := range m.Filter {
dAtA[i] = 0xa
i++
l = len(s)
for l >= 1<<7 {
dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
l >>= 7
i++
}
dAtA[i] = uint8(l)
i++
i += copy(dAtA[i:], s)
}
}
return i, nil
}
func (m *ListWorkersResponse) 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 *ListWorkersResponse) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if len(m.Record) > 0 {
for _, msg := range m.Record {
dAtA[i] = 0xa
i++
i = encodeVarintControl(dAtA, i, uint64(msg.Size()))
n, err := msg.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n
}
}
return i, nil
}
func (m *WorkerRecord) 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 *WorkerRecord) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if len(m.ID) > 0 {
dAtA[i] = 0xa
i++
i = encodeVarintControl(dAtA, i, uint64(len(m.ID)))
i += copy(dAtA[i:], m.ID)
}
if len(m.Labels) > 0 {
for k, _ := range m.Labels {
dAtA[i] = 0x12
i++
v := m.Labels[k]
mapSize := 1 + len(k) + sovControl(uint64(len(k))) + 1 + len(v) + sovControl(uint64(len(v)))
i = encodeVarintControl(dAtA, i, uint64(mapSize))
dAtA[i] = 0xa
i++
i = encodeVarintControl(dAtA, i, uint64(len(k)))
i += copy(dAtA[i:], k)
dAtA[i] = 0x12
i++
i = encodeVarintControl(dAtA, i, uint64(len(v)))
i += copy(dAtA[i:], v)
}
}
return i, nil
}
func encodeFixed64Control(dAtA []byte, offset int, v uint64) int { func encodeFixed64Control(dAtA []byte, offset int, v uint64) int {
dAtA[offset] = uint8(v) dAtA[offset] = uint8(v)
dAtA[offset+1] = uint8(v >> 8) dAtA[offset+1] = uint8(v >> 8)
@ -1617,6 +1815,48 @@ func (m *BytesMessage) Size() (n int) {
return n return n
} }
func (m *ListWorkersRequest) Size() (n int) {
var l int
_ = l
if len(m.Filter) > 0 {
for _, s := range m.Filter {
l = len(s)
n += 1 + l + sovControl(uint64(l))
}
}
return n
}
func (m *ListWorkersResponse) Size() (n int) {
var l int
_ = l
if len(m.Record) > 0 {
for _, e := range m.Record {
l = e.Size()
n += 1 + l + sovControl(uint64(l))
}
}
return n
}
func (m *WorkerRecord) Size() (n int) {
var l int
_ = l
l = len(m.ID)
if l > 0 {
n += 1 + l + sovControl(uint64(l))
}
if len(m.Labels) > 0 {
for k, v := range m.Labels {
_ = k
_ = v
mapEntrySize := 1 + len(k) + sovControl(uint64(len(k))) + 1 + len(v) + sovControl(uint64(len(v)))
n += mapEntrySize + 1 + sovControl(uint64(mapEntrySize))
}
}
return n
}
func sovControl(x uint64) (n int) { func sovControl(x uint64) (n int) {
for { for {
n++ n++
@ -3703,6 +3943,361 @@ func (m *BytesMessage) Unmarshal(dAtA []byte) error {
} }
return nil return nil
} }
func (m *ListWorkersRequest) 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 ErrIntOverflowControl
}
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: ListWorkersRequest: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: ListWorkersRequest: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Filter", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowControl
}
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 ErrInvalidLengthControl
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Filter = append(m.Filter, string(dAtA[iNdEx:postIndex]))
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipControl(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthControl
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *ListWorkersResponse) 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 ErrIntOverflowControl
}
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: ListWorkersResponse: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: ListWorkersResponse: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Record", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowControl
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthControl
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Record = append(m.Record, &WorkerRecord{})
if err := m.Record[len(m.Record)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipControl(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthControl
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *WorkerRecord) 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 ErrIntOverflowControl
}
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: WorkerRecord: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: WorkerRecord: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowControl
}
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 ErrInvalidLengthControl
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.ID = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowControl
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthControl
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
var keykey uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowControl
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
keykey |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
var stringLenmapkey uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowControl
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLenmapkey |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLenmapkey := int(stringLenmapkey)
if intStringLenmapkey < 0 {
return ErrInvalidLengthControl
}
postStringIndexmapkey := iNdEx + intStringLenmapkey
if postStringIndexmapkey > l {
return io.ErrUnexpectedEOF
}
mapkey := string(dAtA[iNdEx:postStringIndexmapkey])
iNdEx = postStringIndexmapkey
if m.Labels == nil {
m.Labels = make(map[string]string)
}
if iNdEx < postIndex {
var valuekey uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowControl
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
valuekey |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
var stringLenmapvalue uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowControl
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLenmapvalue |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLenmapvalue := int(stringLenmapvalue)
if intStringLenmapvalue < 0 {
return ErrInvalidLengthControl
}
postStringIndexmapvalue := iNdEx + intStringLenmapvalue
if postStringIndexmapvalue > l {
return io.ErrUnexpectedEOF
}
mapvalue := string(dAtA[iNdEx:postStringIndexmapvalue])
iNdEx = postStringIndexmapvalue
m.Labels[mapkey] = mapvalue
} else {
var mapvalue string
m.Labels[mapkey] = mapvalue
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipControl(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthControl
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipControl(dAtA []byte) (n int, err error) { func skipControl(dAtA []byte) (n int, err error) {
l := len(dAtA) l := len(dAtA)
iNdEx := 0 iNdEx := 0
@ -3811,70 +4406,75 @@ var (
func init() { proto.RegisterFile("control.proto", fileDescriptorControl) } func init() { proto.RegisterFile("control.proto", fileDescriptorControl) }
var fileDescriptorControl = []byte{ var fileDescriptorControl = []byte{
// 1027 bytes of a gzipped FileDescriptorProto // 1120 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xa4, 0x56, 0x5f, 0x6f, 0xe3, 0x44, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x56, 0xcd, 0x6e, 0x23, 0x45,
0x10, 0xc7, 0x4e, 0xea, 0xc4, 0xd3, 0xb4, 0x2a, 0x2b, 0x74, 0xb2, 0x02, 0xa4, 0xc1, 0xbc, 0x44, 0x10, 0x66, 0x3c, 0xce, 0xd8, 0x2e, 0x3b, 0xab, 0xd0, 0xa0, 0xd5, 0x68, 0x00, 0xc7, 0x0c, 0x20,
0x15, 0xe7, 0xdc, 0x05, 0x90, 0x50, 0x91, 0xd0, 0x5d, 0x9a, 0x43, 0xb4, 0xba, 0x0a, 0xb4, 0xbd, 0x59, 0xd1, 0xee, 0x78, 0x37, 0xfc, 0x08, 0x82, 0x84, 0x76, 0x1d, 0x2f, 0x22, 0x51, 0x22, 0x50,
0xc2, 0xb3, 0x93, 0x6c, 0x7d, 0x56, 0x1d, 0xaf, 0xd9, 0x5d, 0x47, 0x0d, 0x9f, 0x82, 0x07, 0xbe, 0x67, 0xc3, 0x4a, 0xdc, 0xc6, 0x76, 0x67, 0x76, 0x94, 0xf1, 0xf4, 0xd0, 0xdd, 0x8e, 0x12, 0x9e,
0x09, 0x9f, 0x80, 0x07, 0xc4, 0x3d, 0xf2, 0xcc, 0x43, 0x41, 0xfd, 0x00, 0x7c, 0x86, 0xd3, 0xfe, 0x82, 0x03, 0x57, 0x4e, 0x3c, 0x02, 0x4f, 0xc0, 0x01, 0x69, 0x8f, 0x9c, 0x39, 0x04, 0x94, 0x07,
0x71, 0xe2, 0x5c, 0x9a, 0xeb, 0x9f, 0x7b, 0xf2, 0xce, 0xec, 0xcc, 0x6f, 0x67, 0xe7, 0x37, 0x3b, 0xe0, 0x19, 0x50, 0xff, 0x8c, 0x3d, 0xce, 0xe4, 0x7f, 0x4f, 0xd3, 0x55, 0x5d, 0xf5, 0x75, 0x75,
0x63, 0xd8, 0x1a, 0xd1, 0x54, 0x30, 0x9a, 0x04, 0x19, 0xa3, 0x82, 0xa2, 0x9d, 0x09, 0x1d, 0xce, 0x7d, 0x35, 0x55, 0x0d, 0xcb, 0x23, 0x9a, 0x0a, 0x46, 0x93, 0x20, 0x63, 0x54, 0x50, 0xb4, 0x32,
0x82, 0x61, 0x1e, 0x27, 0xe3, 0xf3, 0x58, 0x04, 0xd3, 0xc7, 0xcd, 0x87, 0x51, 0x2c, 0x5e, 0xe6, 0xa1, 0xc3, 0x93, 0x60, 0x38, 0x8d, 0x93, 0xf1, 0x61, 0x2c, 0x82, 0xa3, 0xc7, 0xde, 0xc3, 0x28,
0xc3, 0x60, 0x44, 0x27, 0xdd, 0x88, 0x46, 0xb4, 0xab, 0x0c, 0x87, 0xf9, 0x99, 0x92, 0x94, 0xa0, 0x16, 0x2f, 0xa7, 0xc3, 0x60, 0x44, 0x27, 0xbd, 0x88, 0x46, 0xb4, 0xa7, 0x0c, 0x87, 0xd3, 0x03,
0x56, 0x1a, 0xa0, 0xb9, 0x1b, 0x51, 0x1a, 0x25, 0x64, 0x61, 0x25, 0xe2, 0x09, 0xe1, 0x22, 0x9c, 0x25, 0x29, 0x41, 0xad, 0x34, 0x80, 0xb7, 0x1a, 0x51, 0x1a, 0x25, 0x64, 0x6e, 0x25, 0xe2, 0x09,
0x64, 0xc6, 0xe0, 0xb3, 0x12, 0x9e, 0x3c, 0xac, 0x5b, 0x1c, 0xd6, 0xe5, 0x34, 0x99, 0x12, 0xd6, 0xe1, 0x22, 0x9c, 0x64, 0xc6, 0xe0, 0x41, 0x01, 0x4f, 0x1e, 0xd6, 0xcb, 0x0f, 0xeb, 0x71, 0x9a,
0xcd, 0x86, 0x5d, 0x9a, 0x71, 0x6d, 0xed, 0xef, 0xc1, 0xce, 0x20, 0xe6, 0xe7, 0xa7, 0x3c, 0x8c, 0x1c, 0x11, 0xd6, 0xcb, 0x86, 0x3d, 0x9a, 0x71, 0x6d, 0xed, 0xaf, 0xc1, 0xca, 0x20, 0xe6, 0x87,
0x08, 0x26, 0x3f, 0xe7, 0x84, 0x0b, 0xf4, 0x00, 0x9c, 0xb3, 0x38, 0x11, 0x84, 0x79, 0x56, 0xdb, 0xfb, 0x3c, 0x8c, 0x08, 0x26, 0x3f, 0x4e, 0x09, 0x17, 0xe8, 0x3e, 0x38, 0x07, 0x71, 0x22, 0x08,
0xea, 0xb8, 0xd8, 0x48, 0xfe, 0x11, 0xbc, 0x5f, 0xb2, 0xe5, 0x19, 0x4d, 0x39, 0x41, 0x5f, 0x82, 0x73, 0xad, 0x8e, 0xd5, 0x6d, 0x60, 0x23, 0xf9, 0xdb, 0xf0, 0x66, 0xc1, 0x96, 0x67, 0x34, 0xe5,
0xc3, 0xc8, 0x88, 0xb2, 0xb1, 0x67, 0xb5, 0x2b, 0x9d, 0xcd, 0xde, 0xc7, 0xc1, 0x9b, 0x37, 0x0c, 0x04, 0x7d, 0x0a, 0x0e, 0x23, 0x23, 0xca, 0xc6, 0xae, 0xd5, 0xb1, 0xbb, 0xcd, 0xf5, 0xf7, 0x82,
0x8c, 0x83, 0x34, 0xc2, 0xc6, 0xd8, 0xff, 0xc3, 0x86, 0xcd, 0x92, 0x1e, 0x6d, 0x83, 0x7d, 0x38, 0xf3, 0x37, 0x0c, 0x8c, 0x83, 0x34, 0xc2, 0xc6, 0xd8, 0xff, 0xa3, 0x02, 0xcd, 0x82, 0x1e, 0xdd,
0x30, 0xe7, 0xd9, 0x87, 0x03, 0xe4, 0x41, 0xed, 0x38, 0x17, 0xe1, 0x30, 0x21, 0x9e, 0xdd, 0xb6, 0x83, 0xca, 0xd6, 0xc0, 0x9c, 0x57, 0xd9, 0x1a, 0x20, 0x17, 0x6a, 0xbb, 0x53, 0x11, 0x0e, 0x13,
0x3a, 0x75, 0x5c, 0x88, 0xe8, 0x03, 0xd8, 0x38, 0x4c, 0x4f, 0x39, 0xf1, 0x2a, 0x4a, 0xaf, 0x05, 0xe2, 0x56, 0x3a, 0x56, 0xb7, 0x8e, 0x73, 0x11, 0xbd, 0x0d, 0x4b, 0x5b, 0xe9, 0x3e, 0x27, 0xae,
0x84, 0xa0, 0x7a, 0x12, 0xff, 0x42, 0xbc, 0x6a, 0xdb, 0xea, 0x54, 0xb0, 0x5a, 0xcb, 0x7b, 0xfc, 0xad, 0xf4, 0x5a, 0x40, 0x08, 0xaa, 0x7b, 0xf1, 0x4f, 0xc4, 0xad, 0x76, 0xac, 0xae, 0x8d, 0xd5,
0x10, 0x32, 0x92, 0x0a, 0x6f, 0x43, 0xdf, 0x43, 0x4b, 0xa8, 0x0f, 0xee, 0x01, 0x23, 0xa1, 0x20, 0x5a, 0xde, 0xe3, 0xbb, 0x90, 0x91, 0x54, 0xb8, 0x4b, 0xfa, 0x1e, 0x5a, 0x42, 0x7d, 0x68, 0x6c,
0xe3, 0xa7, 0xc2, 0x73, 0xda, 0x56, 0x67, 0xb3, 0xd7, 0x0c, 0x74, 0x5a, 0x83, 0x22, 0xad, 0xc1, 0x32, 0x12, 0x0a, 0x32, 0x7e, 0x2a, 0x5c, 0xa7, 0x63, 0x75, 0x9b, 0xeb, 0x5e, 0xa0, 0xd3, 0x1a,
0x8b, 0x22, 0xad, 0xfd, 0xfa, 0xab, 0xcb, 0xdd, 0xf7, 0x7e, 0xfd, 0x77, 0xd7, 0xc2, 0x0b, 0x37, 0xe4, 0x69, 0x0d, 0x9e, 0xe7, 0x69, 0xed, 0xd7, 0x5f, 0x9d, 0xae, 0xbe, 0xf1, 0xf3, 0x3f, 0xab,
0xf4, 0x04, 0xe0, 0x79, 0xc8, 0xc5, 0x29, 0x57, 0x20, 0xb5, 0x1b, 0x41, 0xaa, 0x0a, 0xa0, 0xe4, 0x16, 0x9e, 0xbb, 0xa1, 0x27, 0x00, 0x3b, 0x21, 0x17, 0xfb, 0x5c, 0x81, 0xd4, 0xae, 0x05, 0xa9,
0x83, 0x5a, 0x00, 0x2a, 0x01, 0x07, 0x34, 0x4f, 0x85, 0x57, 0x57, 0x71, 0x97, 0x34, 0xa8, 0x0d, 0x2a, 0x80, 0x82, 0x0f, 0x6a, 0x03, 0xa8, 0x04, 0x6c, 0xd2, 0x69, 0x2a, 0xdc, 0xba, 0x8a, 0xbb,
0x9b, 0x03, 0xc2, 0x47, 0x2c, 0xce, 0x44, 0x4c, 0x53, 0xcf, 0x55, 0x57, 0x28, 0xab, 0xfc, 0xdf, 0xa0, 0x41, 0x1d, 0x68, 0x0e, 0x08, 0x1f, 0xb1, 0x38, 0x13, 0x31, 0x4d, 0xdd, 0x86, 0xba, 0x42,
0xaa, 0xd0, 0x38, 0x91, 0x9c, 0x16, 0xc4, 0xed, 0x40, 0x05, 0x93, 0x33, 0x93, 0x45, 0xb9, 0x44, 0x51, 0xe5, 0xff, 0x52, 0x85, 0xd6, 0x9e, 0xe4, 0x34, 0x27, 0x6e, 0x05, 0x6c, 0x4c, 0x0e, 0x4c,
0x01, 0xc0, 0x80, 0x9c, 0xc5, 0x69, 0xac, 0x30, 0x6c, 0x15, 0xe6, 0x76, 0x90, 0x0d, 0x83, 0x85, 0x16, 0xe5, 0x12, 0x05, 0x00, 0x03, 0x72, 0x10, 0xa7, 0xb1, 0xc2, 0xa8, 0xa8, 0x30, 0xef, 0x05,
0x16, 0x97, 0x2c, 0x50, 0x13, 0xea, 0xcf, 0x2e, 0x32, 0xca, 0x24, 0xf9, 0x15, 0x05, 0x33, 0x97, 0xd9, 0x30, 0x98, 0x6b, 0x71, 0xc1, 0x02, 0x79, 0x50, 0x7f, 0x76, 0x9c, 0x51, 0x26, 0xc9, 0xb7,
0xd1, 0x4f, 0xb0, 0x55, 0xac, 0x9f, 0x0a, 0xc1, 0xb8, 0x57, 0x55, 0x84, 0x3f, 0x5e, 0x25, 0xbc, 0x15, 0xcc, 0x4c, 0x46, 0x2f, 0x60, 0x39, 0x5f, 0x3f, 0x15, 0x82, 0x71, 0xb7, 0xaa, 0x08, 0x7f,
0x1c, 0x54, 0xb0, 0xe4, 0xf3, 0x2c, 0x15, 0x6c, 0x86, 0x97, 0x71, 0x24, 0xd7, 0x27, 0x84, 0x73, 0x5c, 0x26, 0xbc, 0x18, 0x54, 0xb0, 0xe0, 0xf3, 0x2c, 0x15, 0xec, 0x04, 0x2f, 0xe2, 0x48, 0xae,
0x19, 0xa1, 0x26, 0xaa, 0x10, 0x65, 0x38, 0xdf, 0x32, 0x9a, 0x0a, 0x92, 0x8e, 0x15, 0x51, 0x2e, 0xf7, 0x08, 0xe7, 0x32, 0x42, 0x4d, 0x54, 0x2e, 0xca, 0x70, 0xbe, 0x66, 0x34, 0x15, 0x24, 0x1d,
0x9e, 0xcb, 0x32, 0x9c, 0x62, 0xad, 0xc3, 0xa9, 0xdd, 0x2a, 0x9c, 0x25, 0x1f, 0x13, 0xce, 0x92, 0x2b, 0xa2, 0x1a, 0x78, 0x26, 0xcb, 0x70, 0xf2, 0xb5, 0x0e, 0xa7, 0x76, 0xa3, 0x70, 0x16, 0x7c,
0x0e, 0xed, 0xc3, 0xc6, 0x41, 0x38, 0x7a, 0x49, 0x14, 0x27, 0x9b, 0xbd, 0xd6, 0x2a, 0xa0, 0xda, 0x4c, 0x38, 0x0b, 0x3a, 0xb4, 0x01, 0x4b, 0x9b, 0xe1, 0xe8, 0x25, 0x51, 0x9c, 0x34, 0xd7, 0xdb,
0xfe, 0x5e, 0x91, 0xc0, 0xfb, 0x55, 0x59, 0x1e, 0x58, 0xbb, 0x34, 0x9f, 0x00, 0x5a, 0xbd, 0xaf, 0x65, 0x40, 0xb5, 0xfd, 0xad, 0x22, 0x81, 0xf7, 0xab, 0xb2, 0x3c, 0xb0, 0x76, 0xf1, 0x9e, 0x00,
0xe4, 0xe5, 0x9c, 0xcc, 0x0a, 0x5e, 0xce, 0xc9, 0x4c, 0x16, 0xf1, 0x34, 0x4c, 0x72, 0x5d, 0xdc, 0x2a, 0xdf, 0x57, 0xf2, 0x72, 0x48, 0x4e, 0x72, 0x5e, 0x0e, 0xc9, 0x89, 0x2c, 0xe2, 0xa3, 0x30,
0x2e, 0xd6, 0xc2, 0xbe, 0xfd, 0x95, 0x25, 0x11, 0x56, 0x43, 0xbc, 0x0b, 0x82, 0x7f, 0x04, 0x8d, 0x99, 0xea, 0xe2, 0x6e, 0x60, 0x2d, 0x6c, 0x54, 0x3e, 0xb7, 0x24, 0x42, 0x39, 0xc4, 0xdb, 0x20,
0x72, 0x80, 0xe8, 0x23, 0x70, 0x75, 0x4c, 0x8b, 0xda, 0x58, 0x28, 0xe4, 0xee, 0xe1, 0xa4, 0xd8, 0xf8, 0xdb, 0xd0, 0x2a, 0x06, 0x88, 0xde, 0x85, 0x86, 0x8e, 0x69, 0x5e, 0x1b, 0x73, 0x85, 0xdc,
0xd5, 0x58, 0x0b, 0x85, 0xff, 0x35, 0x6c, 0x99, 0xec, 0x99, 0xe7, 0xbe, 0x07, 0x95, 0xa9, 0xb8, 0xdd, 0x9a, 0xe4, 0xbb, 0x1a, 0x6b, 0xae, 0xf0, 0xbf, 0x84, 0x65, 0x93, 0x3d, 0xf3, 0xbb, 0xaf,
0x30, 0x6f, 0xdd, 0x5b, 0x4d, 0xcd, 0x8f, 0x84, 0x09, 0x72, 0x81, 0xa5, 0x91, 0xff, 0x09, 0x6c, 0x81, 0x7d, 0x24, 0x8e, 0xcd, 0xbf, 0xee, 0x96, 0x53, 0xf3, 0x3d, 0x61, 0x82, 0x1c, 0x63, 0x69,
0x9d, 0x88, 0x50, 0xe4, 0x7c, 0x6d, 0x7d, 0xfa, 0xbf, 0x5b, 0xb0, 0x5d, 0xd8, 0x98, 0x13, 0xbe, 0xe4, 0xbf, 0x0f, 0xcb, 0x7b, 0x22, 0x14, 0x53, 0x7e, 0x69, 0x7d, 0xfa, 0xbf, 0x5b, 0x70, 0x2f,
0x80, 0xfa, 0x54, 0x81, 0x10, 0x7e, 0xe3, 0x31, 0x73, 0x4b, 0xb4, 0x0f, 0x75, 0xae, 0x70, 0x08, 0xb7, 0x31, 0x27, 0x7c, 0x02, 0xf5, 0x23, 0x05, 0x42, 0xf8, 0xb5, 0xc7, 0xcc, 0x2c, 0xd1, 0x06,
0xf7, 0x6c, 0xe5, 0xd5, 0x5a, 0xe7, 0x65, 0xce, 0x9b, 0xdb, 0xa3, 0x2e, 0x54, 0x13, 0x1a, 0x71, 0xd4, 0xb9, 0xc2, 0x21, 0xdc, 0xad, 0x28, 0xaf, 0xf6, 0x65, 0x5e, 0xe6, 0xbc, 0x99, 0x3d, 0xea,
0xaf, 0xa2, 0xfc, 0x3e, 0x5c, 0xe7, 0xf7, 0x9c, 0x46, 0x58, 0x19, 0xfa, 0x97, 0x36, 0x38, 0x5a, 0x41, 0x35, 0xa1, 0x11, 0x77, 0x6d, 0xe5, 0xf7, 0xce, 0x65, 0x7e, 0x3b, 0x34, 0xc2, 0xca, 0xd0,
0x87, 0x8e, 0xc0, 0x19, 0xc7, 0x11, 0xe1, 0x42, 0xdf, 0xaa, 0xdf, 0x93, 0xd5, 0xf0, 0xcf, 0xe5, 0x3f, 0xad, 0x80, 0xa3, 0x75, 0x68, 0x1b, 0x9c, 0x71, 0x1c, 0x11, 0x2e, 0xf4, 0xad, 0xfa, 0xeb,
0xee, 0x5e, 0xa9, 0x0b, 0xd3, 0x8c, 0xa4, 0x72, 0x0a, 0x84, 0x71, 0x4a, 0x18, 0xef, 0x46, 0xf4, 0xb2, 0x1a, 0xfe, 0x3e, 0x5d, 0x5d, 0x2b, 0x74, 0x61, 0x9a, 0x91, 0x54, 0x4e, 0x81, 0x30, 0x4e,
0xa1, 0x76, 0x09, 0x06, 0xea, 0x83, 0x0d, 0x82, 0xc4, 0x8a, 0xd3, 0x2c, 0x17, 0xfa, 0x06, 0xf7, 0x09, 0xe3, 0xbd, 0x88, 0x3e, 0xd4, 0x2e, 0xc1, 0x40, 0x7d, 0xb0, 0x41, 0x90, 0x58, 0x71, 0x9a,
0xc4, 0xd2, 0x08, 0xb2, 0x1f, 0xa6, 0xe1, 0x84, 0x98, 0x47, 0xac, 0xd6, 0xb2, 0x1f, 0x8e, 0x64, 0x4d, 0x85, 0xbe, 0xc1, 0x1d, 0xb1, 0x34, 0x82, 0xec, 0x87, 0x69, 0x38, 0x21, 0xe6, 0x27, 0x56,
0x61, 0x8c, 0x55, 0x97, 0xac, 0x63, 0x23, 0xa1, 0x7d, 0xa8, 0x71, 0x11, 0x32, 0x41, 0xc6, 0xea, 0x6b, 0xd9, 0x0f, 0x47, 0xb2, 0x30, 0xc6, 0xaa, 0x4b, 0xd6, 0xb1, 0x91, 0xd0, 0x06, 0xd4, 0xb8,
0xfd, 0xdd, 0xa6, 0x91, 0x15, 0x0e, 0xe8, 0x1b, 0x70, 0x47, 0x74, 0x92, 0x25, 0x44, 0x7a, 0x3b, 0x08, 0x99, 0x20, 0x63, 0xf5, 0xff, 0xdd, 0xa4, 0x91, 0xe5, 0x0e, 0xe8, 0x2b, 0x68, 0x8c, 0xe8,
0xb7, 0xf4, 0x5e, 0xb8, 0xc8, 0x32, 0x26, 0x8c, 0x51, 0xa6, 0x5a, 0xa8, 0x8b, 0xb5, 0xe0, 0xff, 0x24, 0x4b, 0x88, 0xf4, 0x76, 0x6e, 0xe8, 0x3d, 0x77, 0x91, 0x65, 0x4c, 0x18, 0xa3, 0x4c, 0xb5,
0x6f, 0x43, 0xa3, 0x4c, 0xd6, 0xca, 0x78, 0x38, 0x02, 0x47, 0x53, 0xaf, 0x4b, 0xf6, 0x7e, 0xa9, 0xd0, 0x06, 0xd6, 0x82, 0xff, 0x5f, 0x05, 0x5a, 0x45, 0xb2, 0x4a, 0xe3, 0x61, 0x1b, 0x1c, 0x4d,
0xd2, 0x08, 0xd7, 0xa6, 0xca, 0x83, 0xda, 0x28, 0x67, 0x6a, 0x76, 0xe8, 0x89, 0x52, 0x88, 0x32, 0xbd, 0x2e, 0xd9, 0xbb, 0xa5, 0x4a, 0x23, 0x5c, 0x98, 0x2a, 0x17, 0x6a, 0xa3, 0x29, 0x53, 0xb3,
0x60, 0x41, 0x45, 0x98, 0xa8, 0x54, 0x55, 0xb0, 0x16, 0xe4, 0x48, 0x99, 0xcf, 0xe1, 0xbb, 0x8d, 0x43, 0x4f, 0x94, 0x5c, 0x94, 0x01, 0x0b, 0x2a, 0xc2, 0x44, 0xa5, 0xca, 0xc6, 0x5a, 0x90, 0x23,
0x94, 0xb9, 0x5b, 0x99, 0x86, 0xda, 0x3b, 0xd1, 0x50, 0xbf, 0x33, 0x0d, 0xfe, 0x9f, 0x16, 0xb8, 0x65, 0x36, 0x87, 0x6f, 0x37, 0x52, 0x66, 0x6e, 0x45, 0x1a, 0x6a, 0xaf, 0x45, 0x43, 0xfd, 0xd6,
0xf3, 0x2a, 0x2f, 0x65, 0xd7, 0x7a, 0xe7, 0xec, 0x2e, 0x65, 0xc6, 0xbe, 0x5f, 0x66, 0x1e, 0x80, 0x34, 0xf8, 0x7f, 0x5a, 0xd0, 0x98, 0x55, 0x79, 0x21, 0xbb, 0xd6, 0x6b, 0x67, 0x77, 0x21, 0x33,
0xc3, 0x05, 0x23, 0xe1, 0x44, 0x71, 0x54, 0xc1, 0x46, 0x92, 0xfd, 0x64, 0xc2, 0x23, 0xc5, 0x50, 0x95, 0xbb, 0x65, 0xe6, 0x3e, 0x38, 0x5c, 0x30, 0x12, 0x4e, 0x14, 0x47, 0x36, 0x36, 0x92, 0xec,
0x03, 0xcb, 0xa5, 0xef, 0x43, 0xa3, 0x3f, 0x13, 0x84, 0x1f, 0x13, 0x2e, 0x27, 0xa9, 0xe4, 0x76, 0x27, 0x13, 0x1e, 0x29, 0x86, 0x5a, 0x58, 0x2e, 0x7d, 0x1f, 0x5a, 0xfd, 0x13, 0x41, 0xf8, 0x2e,
0x1c, 0x8a, 0x50, 0xdd, 0xa3, 0x81, 0xd5, 0xba, 0xf7, 0x97, 0x0d, 0xb5, 0x03, 0xfd, 0x53, 0x86, 0xe1, 0x72, 0x92, 0x4a, 0x6e, 0xc7, 0xa1, 0x08, 0xd5, 0x3d, 0x5a, 0x58, 0xad, 0xfd, 0x07, 0x80,
0x5e, 0x80, 0x3b, 0xff, 0xa5, 0x41, 0xfe, 0xea, 0xcb, 0x7f, 0xf3, 0xdf, 0xa8, 0xf9, 0xe9, 0x5b, 0x76, 0x62, 0x2e, 0x5e, 0x50, 0x76, 0x48, 0x18, 0xbf, 0xe8, 0xd1, 0x63, 0x17, 0x1e, 0x3d, 0xbb,
0x6d, 0x4c, 0x0b, 0xfb, 0x0e, 0x36, 0x54, 0xd7, 0x44, 0xad, 0xb7, 0x0f, 0xa3, 0xe6, 0xee, 0xda, 0xf0, 0xd6, 0x82, 0xb5, 0xe9, 0x52, 0x9f, 0x9d, 0x7b, 0xf6, 0x5c, 0xd0, 0x6d, 0xb4, 0xcb, 0xb9,
0x7d, 0x83, 0x74, 0x0c, 0x8e, 0x79, 0x01, 0xd7, 0x99, 0x96, 0x9b, 0x6b, 0xb3, 0xbd, 0xde, 0x40, 0x77, 0xcf, 0xaf, 0x16, 0xb4, 0x8a, 0x1b, 0xa5, 0xca, 0xee, 0x83, 0xb3, 0x13, 0x0e, 0x49, 0x92,
0x83, 0x3d, 0xb2, 0xd0, 0xf1, 0x7c, 0xd2, 0x5e, 0x17, 0x5a, 0x39, 0x73, 0xcd, 0x1b, 0xf6, 0x3b, 0xb7, 0xb1, 0xb5, 0xab, 0x81, 0x03, 0x6d, 0xac, 0x07, 0x99, 0xf1, 0xf4, 0xbe, 0x80, 0x66, 0x41,
0xd6, 0x23, 0xab, 0xdf, 0x78, 0x75, 0xd5, 0xb2, 0xfe, 0xbe, 0x6a, 0x59, 0xff, 0x5d, 0xb5, 0xac, 0x7d, 0x9b, 0xe1, 0xb1, 0xfe, 0x9b, 0x0d, 0xb5, 0x4d, 0xfd, 0x62, 0x45, 0xcf, 0xa1, 0x31, 0x7b,
0xa1, 0xa3, 0xe8, 0xfc, 0xfc, 0x75, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe9, 0xaa, 0xee, 0xfc, 0xf2, 0xef, 0x21, 0xbf, 0x1c, 0xc7, 0xf9, 0x87, 0xa3, 0xf7, 0xc1, 0x95, 0x36, 0x26, 0x73, 0xdf, 0xc0,
0x0a, 0x00, 0x00, 0x92, 0x1a, 0x29, 0xa8, 0x7d, 0xf5, 0xa4, 0xf6, 0x56, 0x2f, 0xdd, 0x37, 0x48, 0xbb, 0xe0, 0x98,
0xf6, 0x70, 0x91, 0x69, 0x71, 0xf2, 0x78, 0x9d, 0xcb, 0x0d, 0x34, 0xd8, 0x23, 0x0b, 0xed, 0xce,
0x9e, 0x21, 0x17, 0x85, 0x56, 0x2c, 0x2b, 0xef, 0x9a, 0xfd, 0xae, 0xf5, 0xc8, 0x42, 0x3f, 0x40,
0xb3, 0x50, 0x38, 0xe8, 0xc3, 0xb2, 0x4b, 0xb9, 0x0a, 0xbd, 0x8f, 0xae, 0xb1, 0xd2, 0xc1, 0xf6,
0x5b, 0xaf, 0xce, 0xda, 0xd6, 0x5f, 0x67, 0x6d, 0xeb, 0xdf, 0xb3, 0xb6, 0x35, 0x74, 0xd4, 0x7f,
0xf4, 0xf1, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0x54, 0x2e, 0xae, 0xbd, 0x6b, 0x0c, 0x00, 0x00,
} }

View File

@ -15,10 +15,11 @@ service Control {
rpc Solve(SolveRequest) returns (SolveResponse); rpc Solve(SolveRequest) returns (SolveResponse);
rpc Status(StatusRequest) returns (stream StatusResponse); rpc Status(StatusRequest) returns (stream StatusResponse);
rpc Session(stream BytesMessage) returns (stream BytesMessage); rpc Session(stream BytesMessage) returns (stream BytesMessage);
rpc ListWorkers(ListWorkersRequest) returns (ListWorkersResponse);
} }
message DiskUsageRequest { message DiskUsageRequest {
string filter = 1; string filter = 1; // FIXME: this should be containerd-compatible repeated string?
} }
message DiskUsageResponse { message DiskUsageResponse {
@ -98,4 +99,17 @@ message VertexLog {
message BytesMessage { message BytesMessage {
bytes data = 1; bytes data = 1;
} }
message ListWorkersRequest {
repeated string filter = 1; // containerd style
}
message ListWorkersResponse {
repeated WorkerRecord record = 1;
}
message WorkerRecord {
string ID = 1;
map<string, string> Labels = 2;
}

49
client/workers.go Normal file
View File

@ -0,0 +1,49 @@
package client
import (
"context"
controlapi "github.com/moby/buildkit/api/services/control"
"github.com/pkg/errors"
)
type WorkerInfo struct {
ID string
Labels map[string]string
}
func (c *Client) ListWorkers(ctx context.Context, opts ...ListWorkersOption) ([]*WorkerInfo, error) {
info := &ListWorkersInfo{}
for _, o := range opts {
o(info)
}
req := &controlapi.ListWorkersRequest{Filter: info.Filter}
resp, err := c.controlClient().ListWorkers(ctx, req)
if err != nil {
return nil, errors.Wrap(err, "failed to list workers")
}
var wi []*WorkerInfo
for _, w := range resp.Record {
wi = append(wi, &WorkerInfo{
ID: w.ID,
Labels: w.Labels,
})
}
return wi, nil
}
type ListWorkersOption func(*ListWorkersInfo)
type ListWorkersInfo struct {
Filter []string
}
func WithWorkerFilter(f []string) ListWorkersOption {
return func(wi *ListWorkersInfo) {
wi.Filter = f
}
}

View File

@ -11,5 +11,6 @@ var debugCommand = cli.Command{
Subcommands: []cli.Command{ Subcommands: []cli.Command{
debug.DumpLLBCommand, debug.DumpLLBCommand,
debug.DumpMetadataCommand, debug.DumpMetadataCommand,
debug.WorkersCommand,
}, },
} }

View File

@ -0,0 +1,88 @@
package debug
import (
"fmt"
"os"
"sort"
"text/tabwriter"
"github.com/moby/buildkit/client"
"github.com/moby/buildkit/util/appcontext"
"github.com/urfave/cli"
)
var WorkersCommand = cli.Command{
Name: "workers",
Usage: "list workers",
Action: listWorkers,
Flags: []cli.Flag{
cli.StringSliceFlag{
Name: "filter, f",
Usage: "containerd-style filter string slice",
},
cli.BoolFlag{
Name: "verbose, v",
Usage: "Verbose output",
},
},
}
func resolveClient(c *cli.Context) (*client.Client, error) {
return client.New(c.GlobalString("addr"), client.WithBlock())
}
func listWorkers(clicontext *cli.Context) error {
c, err := resolveClient(clicontext)
if err != nil {
return err
}
workers, err := c.ListWorkers(appcontext.Context(), client.WithWorkerFilter(clicontext.StringSlice("filter")))
if err != nil {
return err
}
tw := tabwriter.NewWriter(os.Stdout, 1, 8, 1, '\t', 0)
if clicontext.Bool("verbose") {
printWorkersVerbose(tw, workers)
} else {
printWorkersTable(tw, workers)
}
return nil
}
func printWorkersVerbose(tw *tabwriter.Writer, winfo []*client.WorkerInfo) {
for _, wi := range winfo {
fmt.Fprintf(tw, "ID:\t%s\n", wi.ID)
fmt.Fprintf(tw, "Labels:\n")
for _, k := range sortedKeys(wi.Labels) {
v := wi.Labels[k]
fmt.Fprintf(tw, "\t%s:\t%s\n", k, v)
}
fmt.Fprintf(tw, "\n")
}
tw.Flush()
}
func printWorkersTable(tw *tabwriter.Writer, winfo []*client.WorkerInfo) {
fmt.Fprintln(tw, "ID")
for _, wi := range winfo {
id := wi.ID
fmt.Fprintf(tw, "%s\n", id)
}
tw.Flush()
}
func sortedKeys(m map[string]string) []string {
s := make([]string, len(m))
i := 0
for k := range m {
s[i] = k
i++
}
sort.Strings(s)
return s
}

View File

@ -256,19 +256,20 @@ func newController(c *cli.Context, root string) (*control.Controller, error) {
func newWorkerController(c *cli.Context, wiOpt workerInitializerOpt) (*worker.Controller, error) { func newWorkerController(c *cli.Context, wiOpt workerInitializerOpt) (*worker.Controller, error) {
wc := &worker.Controller{} wc := &worker.Controller{}
nWorkers := 0
for _, wi := range workerInitializers { for _, wi := range workerInitializers {
ws, err := wi.fn(c, wiOpt) ws, err := wi.fn(c, wiOpt)
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, w := range ws { for _, w := range ws {
logrus.Infof("found worker %q", w.Name()) logrus.Infof("found worker %q, labels=%v", w.ID(), w.Labels())
if err = wc.Add(w); err != nil { if err = wc.Add(w); err != nil {
return nil, err return nil, err
} }
nWorkers++
} }
} }
nWorkers := len(wc.GetAll())
if nWorkers == 0 { if nWorkers == 0 {
return nil, errors.New("no worker found, rebuild the buildkit daemon?") return nil, errors.New("no worker found, rebuild the buildkit daemon?")
} }
@ -276,7 +277,19 @@ func newWorkerController(c *cli.Context, wiOpt workerInitializerOpt) (*worker.Co
if err != nil { if err != nil {
return nil, err return nil, err
} }
logrus.Infof("found %d workers, default=%q", nWorkers, defaultWorker.Name) logrus.Infof("found %d workers, default=%q", nWorkers, defaultWorker.ID())
logrus.Warn("currently, only the default worker can be used.") logrus.Warn("currently, only the default worker can be used.")
return wc, nil return wc, nil
} }
func attrMap(sl []string) (map[string]string, error) {
m := map[string]string{}
for _, v := range sl {
parts := strings.SplitN(v, "=", 2)
if len(parts) != 2 {
return nil, errors.Errorf("invalid value %s", v)
}
m[parts[0]] = parts[1]
}
return m, nil
}

View File

@ -30,7 +30,12 @@ func init() {
Name: "containerd-worker-addr", Name: "containerd-worker-addr",
Usage: "containerd socket", Usage: "containerd socket",
Value: "/run/containerd/containerd.sock", Value: "/run/containerd/containerd.sock",
}) },
cli.StringSliceFlag{
Name: "containerd-worker-labels",
Usage: "user-specific annotation labels (com.example.foo=bar)",
},
)
// TODO(AkihiroSuda): allow using multiple snapshotters. should be useful for some applications that does not work with the default overlay snapshotter. e.g. mysql (docker/for-linux#72)", // TODO(AkihiroSuda): allow using multiple snapshotters. should be useful for some applications that does not work with the default overlay snapshotter. e.g. mysql (docker/for-linux#72)",
} }
@ -43,7 +48,11 @@ func containerdWorkerInitializer(c *cli.Context, common workerInitializerOpt) ([
if (boolOrAuto == nil && !validContainerdSocket(socket)) || (boolOrAuto != nil && !*boolOrAuto) { if (boolOrAuto == nil && !validContainerdSocket(socket)) || (boolOrAuto != nil && !*boolOrAuto) {
return nil, nil return nil, nil
} }
opt, err := containerd.NewWorkerOpt(common.root, socket, ctd.DefaultSnapshotter) labels, err := attrMap(c.GlobalStringSlice("containerd-worker-labels"))
if err != nil {
return nil, err
}
opt, err := containerd.NewWorkerOpt(common.root, socket, ctd.DefaultSnapshotter, labels)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -22,7 +22,12 @@ func init() {
Name: "oci-worker", Name: "oci-worker",
Usage: "enable oci workers (true/false/auto)", Usage: "enable oci workers (true/false/auto)",
Value: "auto", Value: "auto",
}) },
cli.StringSliceFlag{
Name: "oci-worker-labels",
Usage: "user-specific annotation labels (com.example.foo=bar)",
},
)
// TODO: allow multiple oci runtimes and snapshotters // TODO: allow multiple oci runtimes and snapshotters
} }
@ -34,7 +39,11 @@ func ociWorkerInitializer(c *cli.Context, common workerInitializerOpt) ([]worker
if (boolOrAuto == nil && !validOCIBinary()) || (boolOrAuto != nil && !*boolOrAuto) { if (boolOrAuto == nil && !validOCIBinary()) || (boolOrAuto != nil && !*boolOrAuto) {
return nil, nil return nil, nil
} }
opt, err := runc.NewWorkerOpt(common.root) labels, err := attrMap(c.GlobalStringSlice("oci-worker-labels"))
if err != nil {
return nil, err
}
opt, err := runc.NewWorkerOpt(common.root, labels)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -51,7 +51,11 @@ func (c *Controller) Register(server *grpc.Server) error {
func (c *Controller) DiskUsage(ctx context.Context, r *controlapi.DiskUsageRequest) (*controlapi.DiskUsageResponse, error) { func (c *Controller) DiskUsage(ctx context.Context, r *controlapi.DiskUsageRequest) (*controlapi.DiskUsageResponse, error) {
resp := &controlapi.DiskUsageResponse{} resp := &controlapi.DiskUsageResponse{}
for _, w := range c.opt.WorkerController.GetAll() { workers, err := c.opt.WorkerController.List()
if err != nil {
return nil, err
}
for _, w := range workers {
du, err := w.DiskUsage(ctx, client.DiskUsageInfo{ du, err := w.DiskUsage(ctx, client.DiskUsageInfo{
Filter: r.Filter, Filter: r.Filter,
}) })
@ -201,3 +205,18 @@ func (c *Controller) Session(stream controlapi.Control_SessionServer) error {
logrus.Debugf("session finished: %v", err) logrus.Debugf("session finished: %v", err)
return err return err
} }
func (c *Controller) ListWorkers(ctx context.Context, r *controlapi.ListWorkersRequest) (*controlapi.ListWorkersResponse, error) {
resp := &controlapi.ListWorkersResponse{}
workers, err := c.opt.WorkerController.List(r.Filter...)
if err != nil {
return nil, err
}
for _, w := range workers {
resp.Record = append(resp.Record, &controlapi.WorkerRecord{
ID: w.ID(),
Labels: w.Labels(),
})
}
return resp, nil
}

View File

@ -459,8 +459,7 @@ func (*BuildInput) Descriptor() ([]byte, []int) { return fileDescriptorOps, []in
type OpMetadata struct { type OpMetadata struct {
IgnoreCache bool `protobuf:"varint,1,opt,name=ignore_cache,json=ignoreCache,proto3" json:"ignore_cache,omitempty"` IgnoreCache bool `protobuf:"varint,1,opt,name=ignore_cache,json=ignoreCache,proto3" json:"ignore_cache,omitempty"`
// Description can be used for keeping any text fields that builder doesn't parse // Description can be used for keeping any text fields that builder doesn't parse
Description map[string]string `protobuf:"bytes,2,rep,name=description" json:"description,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` Description map[string]string `protobuf:"bytes,2,rep,name=description" json:"description,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
// TODO: add worker constraint, etc.
WorkerConstraint *WorkerConstraint `protobuf:"bytes,3,opt,name=worker_constraint,json=workerConstraint" json:"worker_constraint,omitempty"` WorkerConstraint *WorkerConstraint `protobuf:"bytes,3,opt,name=worker_constraint,json=workerConstraint" json:"worker_constraint,omitempty"`
} }
@ -490,9 +489,9 @@ func (m *OpMetadata) GetWorkerConstraint() *WorkerConstraint {
return nil return nil
} }
// WorkerConstraint is WIP. Will be changed. // WorkerConstraint is experimental and likely to be changed.
type WorkerConstraint struct { type WorkerConstraint struct {
WorkerType string `protobuf:"bytes,1,opt,name=worker_type,json=workerType,proto3" json:"worker_type,omitempty"` Filter []string `protobuf:"bytes,1,rep,name=filter" json:"filter,omitempty"`
} }
func (m *WorkerConstraint) Reset() { *m = WorkerConstraint{} } func (m *WorkerConstraint) Reset() { *m = WorkerConstraint{} }
@ -500,11 +499,11 @@ func (m *WorkerConstraint) String() string { return proto.CompactText
func (*WorkerConstraint) ProtoMessage() {} func (*WorkerConstraint) ProtoMessage() {}
func (*WorkerConstraint) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{11} } func (*WorkerConstraint) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{11} }
func (m *WorkerConstraint) GetWorkerType() string { func (m *WorkerConstraint) GetFilter() []string {
if m != nil { if m != nil {
return m.WorkerType return m.Filter
} }
return "" return nil
} }
// Definition is the LLB definition structure with per-vertex metadata entries // Definition is the LLB definition structure with per-vertex metadata entries
@ -1097,11 +1096,20 @@ func (m *WorkerConstraint) MarshalTo(dAtA []byte) (int, error) {
_ = i _ = i
var l int var l int
_ = l _ = l
if len(m.WorkerType) > 0 { if len(m.Filter) > 0 {
dAtA[i] = 0xa for _, s := range m.Filter {
i++ dAtA[i] = 0xa
i = encodeVarintOps(dAtA, i, uint64(len(m.WorkerType))) i++
i += copy(dAtA[i:], m.WorkerType) l = len(s)
for l >= 1<<7 {
dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
l >>= 7
i++
}
dAtA[i] = uint8(l)
i++
i += copy(dAtA[i:], s)
}
} }
return i, nil return i, nil
} }
@ -1428,9 +1436,11 @@ func (m *OpMetadata) Size() (n int) {
func (m *WorkerConstraint) Size() (n int) { func (m *WorkerConstraint) Size() (n int) {
var l int var l int
_ = l _ = l
l = len(m.WorkerType) if len(m.Filter) > 0 {
if l > 0 { for _, s := range m.Filter {
n += 1 + l + sovOps(uint64(l)) l = len(s)
n += 1 + l + sovOps(uint64(l))
}
} }
return n return n
} }
@ -3283,7 +3293,7 @@ func (m *WorkerConstraint) Unmarshal(dAtA []byte) error {
switch fieldNum { switch fieldNum {
case 1: case 1:
if wireType != 2 { if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field WorkerType", wireType) return fmt.Errorf("proto: wrong wireType = %d for field Filter", wireType)
} }
var stringLen uint64 var stringLen uint64
for shift := uint(0); ; shift += 7 { for shift := uint(0); ; shift += 7 {
@ -3308,7 +3318,7 @@ func (m *WorkerConstraint) Unmarshal(dAtA []byte) error {
if postIndex > l { if postIndex > l {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
} }
m.WorkerType = string(dAtA[iNdEx:postIndex]) m.Filter = append(m.Filter, string(dAtA[iNdEx:postIndex]))
iNdEx = postIndex iNdEx = postIndex
default: default:
iNdEx = preIndex iNdEx = preIndex
@ -3639,58 +3649,58 @@ var (
func init() { proto.RegisterFile("ops.proto", fileDescriptorOps) } func init() { proto.RegisterFile("ops.proto", fileDescriptorOps) }
var fileDescriptorOps = []byte{ var fileDescriptorOps = []byte{
// 845 bytes of a gzipped FileDescriptorProto // 842 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0xcd, 0x8e, 0x1b, 0x45, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0xc1, 0x8e, 0x1b, 0x45,
0x10, 0xde, 0x19, 0xff, 0xc4, 0x53, 0xb3, 0x20, 0xd3, 0x44, 0x60, 0x59, 0x91, 0xd7, 0x0c, 0x08, 0x10, 0xdd, 0x19, 0xdb, 0x13, 0x4f, 0xcd, 0x82, 0x4c, 0x13, 0x05, 0xcb, 0x8a, 0xbc, 0x66, 0x40,
0x2d, 0x90, 0x9d, 0x95, 0x36, 0x12, 0x8a, 0x38, 0x44, 0x5a, 0xef, 0x46, 0xc2, 0xa0, 0xc8, 0x52, 0x68, 0x09, 0xd9, 0x59, 0x69, 0x91, 0x50, 0xc4, 0x21, 0xd2, 0x7a, 0x37, 0x12, 0x0b, 0x8a, 0x56,
0x83, 0xc4, 0x31, 0x1a, 0xcf, 0xb4, 0x9d, 0x51, 0xec, 0xe9, 0x56, 0x4f, 0x4f, 0x76, 0x7d, 0xe1, 0x6a, 0x0e, 0x1c, 0xa3, 0xf1, 0x4c, 0xdb, 0x69, 0xc5, 0x9e, 0x1e, 0xf5, 0xf4, 0x64, 0xd7, 0x17,
0xc0, 0x13, 0x20, 0xf1, 0x16, 0xbc, 0x03, 0x9c, 0x73, 0xe4, 0x0a, 0x87, 0x80, 0x96, 0x67, 0xe0, 0x0e, 0x7c, 0x01, 0x12, 0x7f, 0xc1, 0x3f, 0xc0, 0x39, 0x47, 0xae, 0x70, 0x08, 0x68, 0xf9, 0x06,
0x8e, 0xaa, 0xba, 0xed, 0x99, 0x2c, 0x41, 0xca, 0x0a, 0x4e, 0xae, 0xae, 0x9f, 0xaf, 0xaa, 0xbe, 0xee, 0xa8, 0xaa, 0xdb, 0x9e, 0xc9, 0x12, 0xa4, 0xac, 0xe0, 0xe4, 0xee, 0xaa, 0xd7, 0xaf, 0xaa,
0xaa, 0x1a, 0x43, 0x20, 0x55, 0x19, 0x2b, 0x2d, 0x8d, 0x64, 0xbe, 0x9a, 0x0f, 0x8f, 0x96, 0xb9, 0x5e, 0x55, 0x8d, 0x21, 0x54, 0x65, 0x95, 0x94, 0x5a, 0x19, 0xc5, 0xfc, 0x72, 0x36, 0x3a, 0x58,
0x79, 0x52, 0xcd, 0xe3, 0x54, 0xae, 0x8f, 0x97, 0x72, 0x29, 0x8f, 0xc9, 0x34, 0xaf, 0x16, 0xf4, 0x48, 0xf3, 0xb4, 0x9e, 0x25, 0x99, 0x5a, 0x1d, 0x2e, 0xd4, 0x42, 0x1d, 0x92, 0x6b, 0x56, 0xcf,
0xa2, 0x07, 0x49, 0x36, 0x24, 0xfa, 0xd9, 0x03, 0x7f, 0xa6, 0xd8, 0x7b, 0xd0, 0xcd, 0x0b, 0x55, 0xe9, 0x46, 0x17, 0x3a, 0xd9, 0x27, 0xf1, 0xcf, 0x1e, 0xf8, 0xe7, 0x25, 0x7b, 0x1f, 0x02, 0x59,
0x99, 0x72, 0xe0, 0x8d, 0x5b, 0x87, 0xe1, 0x49, 0x10, 0xab, 0x79, 0x3c, 0x45, 0x0d, 0x77, 0x06, 0x94, 0xb5, 0xa9, 0x86, 0xde, 0xa4, 0xb3, 0x1f, 0x1d, 0x85, 0x49, 0x39, 0x4b, 0xce, 0xd0, 0xc2,
0x36, 0x86, 0xb6, 0xb8, 0x14, 0xe9, 0xc0, 0x1f, 0x7b, 0x87, 0xe1, 0x09, 0xa0, 0xc3, 0xc3, 0x4b, 0x9d, 0x83, 0x4d, 0xa0, 0x2b, 0x2e, 0x45, 0x36, 0xf4, 0x27, 0xde, 0x7e, 0x74, 0x04, 0x08, 0x78,
0x91, 0xce, 0xd4, 0xe7, 0x7b, 0x9c, 0x2c, 0xec, 0x43, 0xe8, 0x96, 0xb2, 0xd2, 0xa9, 0x18, 0xb4, 0x74, 0x29, 0xb2, 0xf3, 0xf2, 0x8b, 0x1d, 0x4e, 0x1e, 0xf6, 0x11, 0x04, 0x95, 0xaa, 0x75, 0x26,
0xc8, 0x67, 0x1f, 0x7d, 0xbe, 0x22, 0x0d, 0x79, 0x39, 0x2b, 0x22, 0xa5, 0x52, 0x6d, 0x06, 0xed, 0x86, 0x1d, 0xc2, 0xec, 0x22, 0xe6, 0x6b, 0xb2, 0x10, 0xca, 0x79, 0x91, 0x29, 0x53, 0xe5, 0x7a,
0x1a, 0xe9, 0x4c, 0xaa, 0x8d, 0x45, 0x42, 0x0b, 0x7b, 0x1f, 0x3a, 0xf3, 0x2a, 0x5f, 0x65, 0x83, 0xd8, 0x6d, 0x98, 0x4e, 0x54, 0xb9, 0xb6, 0x4c, 0xe8, 0x61, 0x1f, 0x40, 0x6f, 0x56, 0xcb, 0x65,
0x0e, 0xb9, 0x84, 0xe8, 0x32, 0x41, 0x05, 0xf9, 0x58, 0xdb, 0xa4, 0x0d, 0xbe, 0x54, 0xd1, 0xb7, 0x3e, 0xec, 0x11, 0x24, 0x42, 0xc8, 0x14, 0x0d, 0x84, 0xb1, 0xbe, 0x69, 0x17, 0x7c, 0x55, 0xc6,
0xd0, 0xa1, 0x3a, 0xd9, 0x17, 0xd0, 0xcd, 0xf2, 0xa5, 0x28, 0xcd, 0xc0, 0x1b, 0x7b, 0x87, 0xc1, 0xdf, 0x42, 0x8f, 0xf2, 0x64, 0x5f, 0x42, 0x90, 0xcb, 0x85, 0xa8, 0xcc, 0xd0, 0x9b, 0x78, 0xfb,
0xe4, 0xe4, 0xf9, 0x8b, 0x83, 0xbd, 0xdf, 0x5e, 0x1c, 0x7c, 0xdc, 0x20, 0x44, 0x2a, 0x51, 0xa4, 0xe1, 0xf4, 0xe8, 0xc5, 0xcb, 0xbd, 0x9d, 0xdf, 0x5e, 0xee, 0xdd, 0x6b, 0x09, 0xa2, 0x4a, 0x51,
0xb2, 0x30, 0x49, 0x5e, 0x08, 0x5d, 0x1e, 0x2f, 0xe5, 0x91, 0x0d, 0x89, 0xcf, 0xe9, 0x87, 0x3b, 0x64, 0xaa, 0x30, 0xa9, 0x2c, 0x84, 0xae, 0x0e, 0x17, 0xea, 0xc0, 0x3e, 0x49, 0x4e, 0xe9, 0x87,
0x04, 0xf6, 0x11, 0x74, 0xf2, 0x22, 0x13, 0x97, 0xd4, 0x6c, 0x6b, 0xf2, 0xb6, 0x83, 0x0a, 0x67, 0x3b, 0x06, 0xf6, 0x31, 0xf4, 0x64, 0x91, 0x8b, 0x4b, 0x2a, 0xb6, 0x33, 0x7d, 0xd7, 0x51, 0x45,
0x95, 0x51, 0x95, 0x99, 0xa2, 0x89, 0x5b, 0x8f, 0x68, 0x0a, 0x5d, 0x4b, 0x03, 0xbb, 0x03, 0xed, 0xe7, 0xb5, 0x29, 0x6b, 0x73, 0x86, 0x2e, 0x6e, 0x11, 0xf1, 0x19, 0x04, 0x56, 0x06, 0x76, 0x17,
0xb5, 0x30, 0x09, 0xa5, 0x0f, 0x4f, 0x7a, 0x58, 0xf3, 0x23, 0x61, 0x12, 0x4e, 0x5a, 0x64, 0x78, 0xba, 0x2b, 0x61, 0x52, 0x0a, 0x1f, 0x1d, 0xf5, 0x31, 0xe7, 0xc7, 0xc2, 0xa4, 0x9c, 0xac, 0xa8,
0x2d, 0xab, 0xc2, 0x94, 0x03, 0xbf, 0x66, 0xf8, 0x11, 0x6a, 0xb8, 0x33, 0x44, 0x1c, 0xda, 0x18, 0xf0, 0x4a, 0xd5, 0x85, 0xa9, 0x86, 0x7e, 0xa3, 0xf0, 0x63, 0xb4, 0x70, 0xe7, 0x88, 0x39, 0x74,
0xc0, 0x18, 0xb4, 0x13, 0xbd, 0xb4, 0xa3, 0x08, 0x38, 0xc9, 0xac, 0x0f, 0x2d, 0x51, 0x3c, 0xa3, 0xf1, 0x01, 0x63, 0xd0, 0x4d, 0xf5, 0xc2, 0xb6, 0x22, 0xe4, 0x74, 0x66, 0x03, 0xe8, 0x88, 0xe2,
0xd8, 0x80, 0xa3, 0x88, 0x9a, 0xf4, 0x22, 0x23, 0xaa, 0x03, 0x8e, 0x22, 0xc6, 0x55, 0xa5, 0xd0, 0x39, 0xbd, 0x0d, 0x39, 0x1e, 0xd1, 0x92, 0x5d, 0xe4, 0x24, 0x75, 0xc8, 0xf1, 0x88, 0xef, 0xea,
0xc4, 0x6b, 0xc0, 0x49, 0x8e, 0x7e, 0xf4, 0xa0, 0x43, 0x59, 0xd8, 0x21, 0xf6, 0xa4, 0x2a, 0x4b, 0x4a, 0x68, 0xd2, 0x35, 0xe4, 0x74, 0x8e, 0x7f, 0xf4, 0xa0, 0x47, 0x51, 0xd8, 0x3e, 0xd6, 0x54,
0x4f, 0x6b, 0xc2, 0x5c, 0x4f, 0x40, 0xec, 0xed, 0x5a, 0x42, 0x26, 0x87, 0xd0, 0x2b, 0xc5, 0x4a, 0xd6, 0x56, 0x9e, 0xce, 0x94, 0xb9, 0x9a, 0x80, 0xd4, 0xdb, 0x96, 0x84, 0x4a, 0x8e, 0xa0, 0x5f,
0xa4, 0x46, 0x6a, 0x22, 0x20, 0xe0, 0xbb, 0x37, 0xe6, 0xc8, 0x90, 0x63, 0x9b, 0x96, 0x64, 0xf6, 0x89, 0xa5, 0xc8, 0x8c, 0xd2, 0x24, 0x40, 0xc8, 0xb7, 0x77, 0x8c, 0x91, 0xa3, 0xc6, 0x36, 0x2c,
0x09, 0x74, 0x25, 0x11, 0x43, 0x99, 0xff, 0x85, 0x2e, 0xe7, 0x82, 0xe0, 0x5a, 0x24, 0x99, 0x2c, 0x9d, 0xd9, 0x27, 0x10, 0x28, 0x12, 0x86, 0x22, 0xff, 0x8b, 0x5c, 0x0e, 0x82, 0xe4, 0x5a, 0xa4,
0x56, 0x1b, 0x9a, 0x6e, 0x8f, 0xef, 0xde, 0xd1, 0x03, 0xe8, 0xda, 0x45, 0x60, 0x63, 0x68, 0x95, 0xb9, 0x2a, 0x96, 0x6b, 0xea, 0x6e, 0x9f, 0x6f, 0xef, 0xf1, 0x43, 0x08, 0xec, 0x20, 0xb0, 0x09,
0x3a, 0x75, 0xcb, 0xf8, 0xe6, 0x76, 0x43, 0xec, 0x2e, 0x71, 0x34, 0xed, 0x0a, 0xf1, 0xeb, 0x42, 0x74, 0x2a, 0x9d, 0xb9, 0x61, 0x7c, 0x7b, 0x33, 0x21, 0x76, 0x96, 0x38, 0xba, 0xb6, 0x89, 0xf8,
0x22, 0x0e, 0x50, 0xbb, 0xfd, 0x3f, 0x0d, 0x47, 0x3f, 0x78, 0xd0, 0xdb, 0xee, 0x30, 0x1b, 0x01, 0x4d, 0x22, 0x31, 0x07, 0x68, 0x60, 0xff, 0x4f, 0xc1, 0xf1, 0x0f, 0x1e, 0xf4, 0x37, 0x33, 0xcc,
0xe4, 0x99, 0x28, 0x4c, 0xbe, 0xc8, 0x85, 0xb6, 0x7b, 0xc6, 0x1b, 0x1a, 0x76, 0x04, 0x9d, 0xc4, 0xc6, 0x00, 0x32, 0x17, 0x85, 0x91, 0x73, 0x29, 0xb4, 0x9d, 0x33, 0xde, 0xb2, 0xb0, 0x03, 0xe8,
0x18, 0xbd, 0x9d, 0xf1, 0xbb, 0xcd, 0x03, 0x88, 0x4f, 0xd1, 0xf2, 0xb0, 0x30, 0x7a, 0xc3, 0xad, 0xa5, 0xc6, 0xe8, 0x4d, 0x8f, 0xdf, 0x6b, 0x2f, 0x40, 0x72, 0x8c, 0x9e, 0x47, 0x85, 0xd1, 0x6b,
0xd7, 0xf0, 0x3e, 0x40, 0xad, 0xc4, 0x81, 0x3e, 0x15, 0x1b, 0x87, 0x8a, 0x22, 0xbb, 0x0d, 0x9d, 0x6e, 0x51, 0xa3, 0x07, 0x00, 0x8d, 0x11, 0x1b, 0xfa, 0x4c, 0xac, 0x1d, 0x2b, 0x1e, 0xd9, 0x6d,
0x67, 0xc9, 0xaa, 0x12, 0xae, 0x28, 0xfb, 0xf8, 0xcc, 0xbf, 0xef, 0x45, 0x3f, 0xf9, 0x70, 0xcb, 0xe8, 0x3d, 0x4f, 0x97, 0xb5, 0x70, 0x49, 0xd9, 0xcb, 0xe7, 0xfe, 0x03, 0x2f, 0xfe, 0xc9, 0x87,
0x1d, 0x04, 0xbb, 0x0b, 0xb7, 0xe8, 0x20, 0x5c, 0x45, 0xaf, 0xee, 0x74, 0xeb, 0xc2, 0x8e, 0x77, 0x5b, 0x6e, 0x21, 0xd8, 0x7d, 0xb8, 0x45, 0x0b, 0xe1, 0x32, 0x7a, 0x7d, 0xa5, 0x1b, 0x08, 0x3b,
0x97, 0xde, 0xa8, 0xd1, 0x41, 0xd9, 0x8b, 0x77, 0x35, 0xd6, 0x77, 0xdf, 0xca, 0xc4, 0xc2, 0x9d, 0xdc, 0x6e, 0x7a, 0x2b, 0x47, 0x47, 0x65, 0x37, 0xde, 0xe5, 0xd8, 0xec, 0x7d, 0x27, 0x17, 0x73,
0x34, 0x8d, 0xe2, 0x5c, 0x2c, 0xf2, 0x22, 0x37, 0xb9, 0x2c, 0x38, 0x9a, 0xd8, 0xdd, 0x6d, 0xd7, 0xb7, 0xd2, 0xd4, 0x8a, 0x53, 0x31, 0x97, 0x85, 0x34, 0x52, 0x15, 0x1c, 0x5d, 0xec, 0xfe, 0xa6,
0x6d, 0x42, 0x7c, 0xa7, 0x89, 0xf8, 0xcf, 0xa6, 0xa7, 0x10, 0x36, 0xd2, 0xbc, 0xa2, 0xeb, 0x0f, 0xea, 0x2e, 0x31, 0xde, 0x69, 0x33, 0xfe, 0xb3, 0xe8, 0x33, 0x88, 0x5a, 0x61, 0x5e, 0x53, 0xf5,
0x9a, 0x5d, 0xbb, 0x94, 0x04, 0x67, 0xbf, 0x47, 0x35, 0x0b, 0xff, 0x81, 0xbf, 0x4f, 0x01, 0x6a, 0x87, 0xed, 0xaa, 0x5d, 0x48, 0xa2, 0xb3, 0xdf, 0xa3, 0x46, 0x85, 0xff, 0xa0, 0xdf, 0x67, 0x00,
0xc8, 0xd7, 0xdf, 0x94, 0xe8, 0x2f, 0x0f, 0x60, 0xa6, 0xf0, 0x4a, 0xb3, 0x84, 0x8e, 0x7a, 0x3f, 0x0d, 0xe5, 0x9b, 0x4f, 0x4a, 0xfc, 0x97, 0x07, 0x70, 0x5e, 0xe2, 0x96, 0xe6, 0x29, 0x2d, 0xf5,
0x5f, 0x16, 0x52, 0x8b, 0xc7, 0x69, 0x92, 0x3e, 0x11, 0x14, 0xdf, 0xe3, 0xa1, 0xd5, 0x9d, 0xa1, 0xae, 0x5c, 0x14, 0x4a, 0x8b, 0x27, 0x59, 0x9a, 0x3d, 0x15, 0xf4, 0xbe, 0xcf, 0x23, 0x6b, 0x3b,
0x8a, 0x9d, 0x42, 0x98, 0x89, 0x32, 0xd5, 0xb9, 0x42, 0xc2, 0x1c, 0xe9, 0x07, 0xd8, 0x53, 0x8d, 0x41, 0x13, 0x3b, 0x86, 0x28, 0x17, 0x55, 0xa6, 0x65, 0x89, 0x82, 0x39, 0xd1, 0xf7, 0xb0, 0xa6,
0x13, 0x9f, 0xd7, 0x1e, 0x96, 0xab, 0x66, 0x0c, 0x3b, 0x85, 0xb7, 0x2e, 0xa4, 0x7e, 0x2a, 0xf4, 0x86, 0x27, 0x39, 0x6d, 0x10, 0x56, 0xab, 0xf6, 0x1b, 0x76, 0x0c, 0xef, 0x5c, 0x28, 0xfd, 0x4c,
0xe3, 0x54, 0x16, 0xa5, 0xd1, 0x49, 0x5e, 0x18, 0x37, 0x8f, 0xdb, 0x08, 0xf4, 0x0d, 0x19, 0xcf, 0xe8, 0x27, 0x99, 0x2a, 0x2a, 0xa3, 0x53, 0x59, 0x18, 0xd7, 0x8f, 0xdb, 0x48, 0xf4, 0x0d, 0x39,
0x76, 0x36, 0xde, 0xbf, 0xb8, 0xa6, 0x19, 0x3e, 0x80, 0xfe, 0xf5, 0x1c, 0x37, 0xe2, 0xeb, 0x1e, 0x4f, 0xb6, 0x3e, 0x3e, 0xb8, 0xb8, 0x66, 0x19, 0x3d, 0x84, 0xc1, 0xf5, 0x18, 0x37, 0xd2, 0xeb,
0xf4, 0xaf, 0x67, 0x61, 0x07, 0x10, 0xba, 0xb2, 0xcc, 0x46, 0x89, 0xed, 0x35, 0x58, 0xd5, 0xd7, 0x1e, 0x0c, 0xae, 0x47, 0x61, 0x77, 0x20, 0x98, 0xcb, 0xa5, 0xa1, 0xb1, 0xc3, 0xaf, 0x92, 0xbb,
0x1b, 0x25, 0xa2, 0x5f, 0x3d, 0x80, 0x7a, 0x57, 0x30, 0x1f, 0x2e, 0x12, 0xde, 0xf4, 0xbe, 0x5d, 0xc5, 0xbf, 0x7a, 0x00, 0xcd, 0x88, 0x60, 0x18, 0x9c, 0x1f, 0xc4, 0xec, 0xda, 0x79, 0x59, 0x42,
0x9c, 0x15, 0xf4, 0xd6, 0x8e, 0x02, 0x47, 0xcc, 0x9d, 0x97, 0xf7, 0x2b, 0xde, 0x32, 0x44, 0x15, 0x7f, 0xe5, 0x2a, 0x77, 0x7a, 0xdc, 0x7d, 0x75, 0xac, 0x92, 0x8d, 0x30, 0x94, 0xa8, 0xfd, 0x92,
0xdb, 0x4f, 0xfa, 0x77, 0xbf, 0xdf, 0xe8, 0x93, 0xbe, 0xcb, 0x30, 0xfc, 0x12, 0xde, 0x78, 0x09, 0x7f, 0xf7, 0xfb, 0x8d, 0xbe, 0xe4, 0xdb, 0x08, 0xa3, 0xaf, 0xe0, 0xad, 0x57, 0xe8, 0xde, 0x70,
0xee, 0x35, 0x57, 0xaf, 0x1e, 0x53, 0x83, 0x90, 0x49, 0xff, 0xf9, 0xd5, 0xc8, 0xfb, 0xe5, 0x6a, 0xe2, 0x9a, 0xee, 0xb4, 0x74, 0x98, 0x0e, 0x5e, 0x5c, 0x8d, 0xbd, 0x5f, 0xae, 0xc6, 0xde, 0x1f,
0xe4, 0xfd, 0x71, 0x35, 0xf2, 0xbe, 0xff, 0x73, 0xb4, 0x37, 0xef, 0xd2, 0x1f, 0xea, 0xbd, 0xbf, 0x57, 0x63, 0xef, 0xfb, 0x3f, 0xc7, 0x3b, 0xb3, 0x80, 0xfe, 0x47, 0x3f, 0xfd, 0x3b, 0x00, 0x00,
0x03, 0x00, 0x00, 0xff, 0xff, 0x26, 0xbe, 0xb0, 0x53, 0x90, 0x07, 0x00, 0x00, 0xff, 0xff, 0x99, 0xd2, 0xfe, 0xe4, 0x87, 0x07, 0x00, 0x00,
} }

View File

@ -74,14 +74,12 @@ message OpMetadata {
bool ignore_cache = 1; bool ignore_cache = 1;
// Description can be used for keeping any text fields that builder doesn't parse // Description can be used for keeping any text fields that builder doesn't parse
map<string, string> description = 2; map<string, string> description = 2;
// TODO: add worker constraint, etc.
WorkerConstraint worker_constraint = 3; WorkerConstraint worker_constraint = 3;
} }
// WorkerConstraint is WIP. Will be changed. // WorkerConstraint is experimental and likely to be changed.
message WorkerConstraint { message WorkerConstraint {
string worker_type = 1; // e.g. "runc", "containerd"...? also we will have worker_brand, arch, os, labels... repeated string filter = 1; // containerd-style filter
// TODO: distributed mode
} }
// Definition is the LLB definition structure with per-vertex metadata entries // Definition is the LLB definition structure with per-vertex metadata entries

View File

@ -2,6 +2,10 @@ package base
import ( import (
"io" "io"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"github.com/containerd/containerd/content" "github.com/containerd/containerd/content"
"github.com/containerd/containerd/diff" "github.com/containerd/containerd/diff"
@ -18,6 +22,7 @@ import (
imageexporter "github.com/moby/buildkit/exporter/containerimage" imageexporter "github.com/moby/buildkit/exporter/containerimage"
localexporter "github.com/moby/buildkit/exporter/local" localexporter "github.com/moby/buildkit/exporter/local"
ociexporter "github.com/moby/buildkit/exporter/oci" ociexporter "github.com/moby/buildkit/exporter/oci"
"github.com/moby/buildkit/identity"
"github.com/moby/buildkit/session" "github.com/moby/buildkit/session"
"github.com/moby/buildkit/snapshot/blobmapping" "github.com/moby/buildkit/snapshot/blobmapping"
"github.com/moby/buildkit/solver" "github.com/moby/buildkit/solver"
@ -39,7 +44,8 @@ import (
// WorkerOpt is specific to a worker. // WorkerOpt is specific to a worker.
// See also CommonOpt. // See also CommonOpt.
type WorkerOpt struct { type WorkerOpt struct {
Name string ID string
Labels map[string]string
SessionManager *session.Manager SessionManager *session.Manager
MetadataStore *metadata.Store MetadataStore *metadata.Store
Executor executor.Executor Executor executor.Executor
@ -47,12 +53,11 @@ type WorkerOpt struct {
ContentStore content.Store ContentStore content.Store
Applier diff.Differ Applier diff.Differ
Differ diff.Differ Differ diff.Differ
ImageStore images.Store ImageStore images.Store // optional
} }
// Worker is a local worker instance with dedicated snapshotter, cache, and so on. // Worker is a local worker instance with dedicated snapshotter, cache, and so on.
// TODO: s/Worker/OpWorker/g ? // TODO: s/Worker/OpWorker/g ?
// FIXME: Worker should be rather an interface
type Worker struct { type Worker struct {
WorkerOpt WorkerOpt
Snapshotter ctdsnapshot.Snapshotter // blobmapping snapshotter Snapshotter ctdsnapshot.Snapshotter // blobmapping snapshotter
@ -215,6 +220,14 @@ func NewWorker(opt WorkerOpt) (*Worker, error) {
}, nil }, nil
} }
func (w *Worker) ID() string {
return w.WorkerOpt.ID
}
func (w *Worker) Labels() map[string]string {
return w.WorkerOpt.Labels
}
func (w *Worker) ResolveOp(v solver.Vertex, s worker.SubBuilder) (solver.Op, error) { func (w *Worker) ResolveOp(v solver.Vertex, s worker.SubBuilder) (solver.Op, error) {
switch op := v.Sys().(type) { switch op := v.Sys().(type) {
case *pb.Op_Source: case *pb.Op_Source:
@ -232,7 +245,7 @@ func (w *Worker) ResolveImageConfig(ctx context.Context, ref string) (digest.Dig
// ImageSource is typically source/containerimage // ImageSource is typically source/containerimage
resolveImageConfig, ok := w.ImageSource.(resolveImageConfig) resolveImageConfig, ok := w.ImageSource.(resolveImageConfig)
if !ok { if !ok {
return "", nil, errors.Errorf("worker %q does not implement ResolveImageConfig", w.Name()) return "", nil, errors.Errorf("worker %q does not implement ResolveImageConfig", w.ID())
} }
return resolveImageConfig.ResolveImageConfig(ctx, ref) return resolveImageConfig.ResolveImageConfig(ctx, ref)
} }
@ -254,10 +267,6 @@ func (w *Worker) DiskUsage(ctx context.Context, opt client.DiskUsageInfo) ([]*cl
return w.CacheManager.DiskUsage(ctx, opt) return w.CacheManager.DiskUsage(ctx, opt)
} }
func (w *Worker) Name() string {
return w.WorkerOpt.Name
}
func (w *Worker) Exporter(name string) (exporter.Exporter, error) { func (w *Worker) Exporter(name string) (exporter.Exporter, error) {
exp, ok := w.Exporters[name] exp, ok := w.Exporters[name]
if !ok { if !ok {
@ -269,3 +278,36 @@ func (w *Worker) Exporter(name string) (exporter.Exporter, error) {
func (w *Worker) InstructionCache() instructioncache.InstructionCache { func (w *Worker) InstructionCache() instructioncache.InstructionCache {
return w.cache return w.cache
} }
// utility function. could be moved to the constructor logic?
func Labels(executor, snapshotter string) map[string]string {
hostname, err := os.Hostname()
if err != nil {
hostname = "unknown"
}
labels := map[string]string{
worker.LabelOS: runtime.GOOS,
worker.LabelArch: runtime.GOARCH,
worker.LabelExecutor: executor,
worker.LabelSnapshotter: snapshotter,
worker.LabelHostname: hostname,
}
return labels
}
// ID reads the worker id from the `workerid` file.
// If not exist, it creates a random one,
func ID(root string) (string, error) {
f := filepath.Join(root, "workerid")
b, err := ioutil.ReadFile(f)
if err != nil {
if os.IsNotExist(err) {
id := identity.NewID()
err := ioutil.WriteFile(f, []byte(id), 0400)
return id, err
} else {
return "", err
}
}
return string(b), nil
}

View File

@ -0,0 +1,34 @@
package base
import (
"io/ioutil"
"os"
"testing"
"github.com/stretchr/testify/require"
)
func TestID(t *testing.T) {
t.Parallel()
tmpdir, err := ioutil.TempDir("", "worker-base-test-id")
require.NoError(t, err)
id0, err := ID(tmpdir)
require.NoError(t, err)
id1, err := ID(tmpdir)
require.NoError(t, err)
require.Equal(t, id0, id1)
// reset tmpdir
require.NoError(t, os.RemoveAll(tmpdir))
require.NoError(t, os.MkdirAll(tmpdir, 0700))
id2, err := ID(tmpdir)
require.NoError(t, err)
require.NotEqual(t, id0, id2)
require.NoError(t, os.RemoveAll(tmpdir))
}

View File

@ -19,17 +19,17 @@ import (
// NewWorkerOpt creates a WorkerOpt. // NewWorkerOpt creates a WorkerOpt.
// But it does not set the following fields: // But it does not set the following fields:
// - SessionManager // - SessionManager
func NewWorkerOpt(root string, address, snapshotterName string, opts ...containerd.ClientOpt) (base.WorkerOpt, error) { func NewWorkerOpt(root string, address, snapshotterName string, labels map[string]string, opts ...containerd.ClientOpt) (base.WorkerOpt, error) {
// TODO: take lock to make sure there are no duplicates // TODO: take lock to make sure there are no duplicates
opts = append([]containerd.ClientOpt{containerd.WithDefaultNamespace("buildkit")}, opts...) opts = append([]containerd.ClientOpt{containerd.WithDefaultNamespace("buildkit")}, opts...)
client, err := containerd.New(address, opts...) client, err := containerd.New(address, opts...)
if err != nil { if err != nil {
return base.WorkerOpt{}, errors.Wrapf(err, "failed to connect client to %q . make sure containerd is running", address) return base.WorkerOpt{}, errors.Wrapf(err, "failed to connect client to %q . make sure containerd is running", address)
} }
return newContainerd(root, client, snapshotterName) return newContainerd(root, client, snapshotterName, labels)
} }
func newContainerd(root string, client *containerd.Client, snapshotterName string) (base.WorkerOpt, error) { func newContainerd(root string, client *containerd.Client, snapshotterName string, labels map[string]string) (base.WorkerOpt, error) {
if strings.Contains(snapshotterName, "/") { if strings.Contains(snapshotterName, "/") {
return base.WorkerOpt{}, errors.Errorf("bad snapshotter name: %q", snapshotterName) return base.WorkerOpt{}, errors.Errorf("bad snapshotter name: %q", snapshotterName)
} }
@ -44,8 +44,18 @@ func newContainerd(root string, client *containerd.Client, snapshotterName strin
return base.WorkerOpt{}, err return base.WorkerOpt{}, err
} }
df := client.DiffService() df := client.DiffService()
// TODO: should use containerd daemon instance ID (containerd/containerd#1862)?
id, err := base.ID(root)
if err != nil {
return base.WorkerOpt{}, err
}
xlabels := base.Labels("containerd", snapshotterName)
for k, v := range labels {
xlabels[k] = v
}
opt := base.WorkerOpt{ opt := base.WorkerOpt{
Name: name, ID: id,
Labels: xlabels,
MetadataStore: md, MetadataStore: md,
Executor: containerdexecutor.New(client, root), Executor: containerdexecutor.New(client, root),
BaseSnapshotter: client.SnapshotService(snapshotterName), BaseSnapshotter: client.SnapshotService(snapshotterName),

33
worker/filter.go Normal file
View File

@ -0,0 +1,33 @@
package worker
import (
"strings"
"github.com/containerd/containerd/filters"
)
func adaptWorker(w Worker) filters.Adaptor {
return filters.AdapterFunc(func(fieldpath []string) (string, bool) {
if len(fieldpath) == 0 {
return "", false
}
switch fieldpath[0] {
case "id":
return w.ID(), len(w.ID()) > 0
case "labels":
return checkMap(fieldpath[1:], w.Labels())
}
return "", false
})
}
func checkMap(fieldpath []string, m map[string]string) (string, bool) {
if len(m) == 0 {
return "", false
}
value, ok := m[strings.Join(fieldpath, ".")]
return value, ok
}

View File

@ -23,9 +23,9 @@ import (
// NewWorkerOpt creates a WorkerOpt. // NewWorkerOpt creates a WorkerOpt.
// But it does not set the following fields: // But it does not set the following fields:
// - SessionManager // - SessionManager
func NewWorkerOpt(root string) (base.WorkerOpt, error) { func NewWorkerOpt(root string, labels map[string]string) (base.WorkerOpt, error) {
var opt base.WorkerOpt var opt base.WorkerOpt
name := "runc-overlay" name := "runc-overlayfs"
root = filepath.Join(root, name) root = filepath.Join(root, name)
if err := os.MkdirAll(root, 0700); err != nil { if err := os.MkdirAll(root, 0700); err != nil {
return opt, err return opt, err
@ -54,7 +54,7 @@ func NewWorkerOpt(root string) (base.WorkerOpt, error) {
} }
mdb := ctdmetadata.NewDB(db, c, map[string]ctdsnapshot.Snapshotter{ mdb := ctdmetadata.NewDB(db, c, map[string]ctdsnapshot.Snapshotter{
"overlay": s, "overlayfs": s,
}) })
if err := mdb.Init(context.TODO()); err != nil { if err := mdb.Init(context.TODO()); err != nil {
return opt, err return opt, err
@ -68,11 +68,20 @@ func NewWorkerOpt(root string) (base.WorkerOpt, error) {
// TODO: call mdb.GarbageCollect . maybe just inject it into nsSnapshotter.Remove and csContent.Delete // TODO: call mdb.GarbageCollect . maybe just inject it into nsSnapshotter.Remove and csContent.Delete
id, err := base.ID(root)
if err != nil {
return opt, err
}
xlabels := base.Labels("oci", "overlayfs")
for k, v := range labels {
xlabels[k] = v
}
opt = base.WorkerOpt{ opt = base.WorkerOpt{
Name: name, ID: id,
Labels: xlabels,
MetadataStore: md, MetadataStore: md,
Executor: exe, Executor: exe,
BaseSnapshotter: &nsSnapshotter{mdb.Snapshotter("overlay")}, BaseSnapshotter: &nsSnapshotter{mdb.Snapshotter("overlayfs")},
ContentStore: c, ContentStore: c,
Applier: df, Applier: df,
Differ: df, Differ: df,

View File

@ -38,7 +38,7 @@ func TestRuncWorker(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
defer os.RemoveAll(tmpdir) defer os.RemoveAll(tmpdir)
workerOpt, err := NewWorkerOpt(tmpdir) workerOpt, err := NewWorkerOpt(tmpdir, nil)
require.NoError(t, err) require.NoError(t, err)
workerOpt.SessionManager, err = session.NewManager() workerOpt.SessionManager, err = session.NewManager()

View File

@ -18,6 +18,9 @@ type SubBuilder interface {
} }
type Worker interface { type Worker interface {
// ID needs to be unique in the cluster
ID() string
Labels() map[string]string
InstructionCache() instructioncache.InstructionCache InstructionCache() instructioncache.InstructionCache
// ResolveOp resolves Vertex.Sys() to Op implementation. SubBuilder is needed for pb.Op_Build. // ResolveOp resolves Vertex.Sys() to Op implementation. SubBuilder is needed for pb.Op_Build.
ResolveOp(v types.Vertex, s SubBuilder) (types.Op, error) ResolveOp(v types.Vertex, s SubBuilder) (types.Op, error)
@ -25,6 +28,15 @@ type Worker interface {
// Exec is similar to executor.Exec but without []mount.Mount // Exec is similar to executor.Exec but without []mount.Mount
Exec(ctx context.Context, meta executor.Meta, rootFS cache.ImmutableRef, stdin io.ReadCloser, stdout, stderr io.WriteCloser) error Exec(ctx context.Context, meta executor.Meta, rootFS cache.ImmutableRef, stdin io.ReadCloser, stdout, stderr io.WriteCloser) error
DiskUsage(ctx context.Context, opt client.DiskUsageInfo) ([]*client.UsageInfo, error) DiskUsage(ctx context.Context, opt client.DiskUsageInfo) ([]*client.UsageInfo, error)
Name() string
Exporter(name string) (exporter.Exporter, error) Exporter(name string) (exporter.Exporter, error)
} }
// Pre-defined label keys
const (
labelPrefix = "org.mobyproject.buildkit.worker."
LabelOS = labelPrefix + "os" // GOOS
LabelArch = labelPrefix + "arch" // GOARCH
LabelExecutor = labelPrefix + "executor" // "oci" or "containerd"
LabelSnapshotter = labelPrefix + "snapshotter" // containerd snapshotter name ("overlay", "naive", ...)
LabelHostname = labelPrefix + "hostname"
)

View File

@ -3,6 +3,7 @@ package worker
import ( import (
"sync" "sync"
"github.com/containerd/containerd/filters"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
@ -22,12 +23,22 @@ func (c *Controller) Add(w Worker) error {
return nil return nil
} }
// GetAll returns all local workers // List lists workers
func (c *Controller) GetAll() []Worker { func (c *Controller) List(filterStrings ...string) ([]Worker, error) {
filter, err := filters.ParseAll(filterStrings...)
if err != nil {
return nil, err
}
c.mu.Lock() c.mu.Lock()
workers := c.workers allWorkers := c.workers
c.mu.Unlock() c.mu.Unlock()
return workers var workers []Worker
for _, w := range allWorkers {
if filter.Match(adaptWorker(w)) {
workers = append(workers, w)
}
}
return workers, nil
} }
// GetDefault returns the default local worker // GetDefault returns the default local worker