Browse code

vendor: update buildkit to 46f9075a

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
Signed-off-by: Tibor Vass <tibor@docker.com>

Tonis Tiigi authored on 2018/08/10 05:45:33
Showing 38 changed files
... ...
@@ -26,7 +26,7 @@ github.com/imdario/mergo v0.3.6
26 26
 golang.org/x/sync 1d60e4601c6fd243af51cc01ddf169918a5407ca
27 27
 
28 28
 # buildkit
29
-github.com/moby/buildkit e57eed420c7573ae44875be98fa877175b4677a1
29
+github.com/moby/buildkit 46f9075ab68a07df2c40ae6e240ce4f9392b3a66 git://github.com/tiborvass/buildkit.git
30 30
 github.com/tonistiigi/fsutil b19464cd1b6a00773b4f2eb7acf9c30426f9df42
31 31
 github.com/grpc-ecosystem/grpc-opentracing 8e809c8a86450a29b90dcc9efbf062d0fe6d9746
32 32
 github.com/opentracing/opentracing-go 1361b9cd60be79c4c3a7fa9841b3c132e40066a7
... ...
@@ -35,6 +35,7 @@ import pb "github.com/moby/buildkit/solver/pb"
35 35
 import moby_buildkit_v1_types "github.com/moby/buildkit/api/types"
36 36
 
37 37
 import time "time"
38
+import github_com_moby_buildkit_util_entitlements "github.com/moby/buildkit/util/entitlements"
38 39
 import github_com_opencontainers_go_digest "github.com/opencontainers/go-digest"
39 40
 
40 41
 import context "golang.org/x/net/context"
... ...
@@ -57,8 +58,10 @@ var _ = time.Kitchen
57 57
 const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
58 58
 
59 59
 type PruneRequest struct {
60
-	Filter []string `protobuf:"bytes,1,rep,name=filter" json:"filter,omitempty"`
61
-	All    bool     `protobuf:"varint,2,opt,name=all,proto3" json:"all,omitempty"`
60
+	Filter       []string `protobuf:"bytes,1,rep,name=filter" json:"filter,omitempty"`
61
+	All          bool     `protobuf:"varint,2,opt,name=all,proto3" json:"all,omitempty"`
62
+	KeepDuration int64    `protobuf:"varint,3,opt,name=keepDuration,proto3" json:"keepDuration,omitempty"`
63
+	KeepBytes    int64    `protobuf:"varint,4,opt,name=keepBytes,proto3" json:"keepBytes,omitempty"`
62 64
 }
63 65
 
64 66
 func (m *PruneRequest) Reset()                    { *m = PruneRequest{} }
... ...
@@ -80,6 +83,20 @@ func (m *PruneRequest) GetAll() bool {
80 80
 	return false
81 81
 }
82 82
 
83
+func (m *PruneRequest) GetKeepDuration() int64 {
84
+	if m != nil {
85
+		return m.KeepDuration
86
+	}
87
+	return 0
88
+}
89
+
90
+func (m *PruneRequest) GetKeepBytes() int64 {
91
+	if m != nil {
92
+		return m.KeepBytes
93
+	}
94
+	return 0
95
+}
96
+
83 97
 type DiskUsageRequest struct {
84 98
 	Filter []string `protobuf:"bytes,1,rep,name=filter" json:"filter,omitempty"`
85 99
 }
... ...
@@ -209,14 +226,15 @@ func (m *UsageRecord) GetShared() bool {
209 209
 }
210 210
 
211 211
 type SolveRequest struct {
212
-	Ref           string            `protobuf:"bytes,1,opt,name=Ref,proto3" json:"Ref,omitempty"`
213
-	Definition    *pb.Definition    `protobuf:"bytes,2,opt,name=Definition" json:"Definition,omitempty"`
214
-	Exporter      string            `protobuf:"bytes,3,opt,name=Exporter,proto3" json:"Exporter,omitempty"`
215
-	ExporterAttrs map[string]string `protobuf:"bytes,4,rep,name=ExporterAttrs" json:"ExporterAttrs,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
216
-	Session       string            `protobuf:"bytes,5,opt,name=Session,proto3" json:"Session,omitempty"`
217
-	Frontend      string            `protobuf:"bytes,6,opt,name=Frontend,proto3" json:"Frontend,omitempty"`
218
-	FrontendAttrs map[string]string `protobuf:"bytes,7,rep,name=FrontendAttrs" json:"FrontendAttrs,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
219
-	Cache         CacheOptions      `protobuf:"bytes,8,opt,name=Cache" json:"Cache"`
212
+	Ref           string                                                   `protobuf:"bytes,1,opt,name=Ref,proto3" json:"Ref,omitempty"`
213
+	Definition    *pb.Definition                                           `protobuf:"bytes,2,opt,name=Definition" json:"Definition,omitempty"`
214
+	Exporter      string                                                   `protobuf:"bytes,3,opt,name=Exporter,proto3" json:"Exporter,omitempty"`
215
+	ExporterAttrs map[string]string                                        `protobuf:"bytes,4,rep,name=ExporterAttrs" json:"ExporterAttrs,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
216
+	Session       string                                                   `protobuf:"bytes,5,opt,name=Session,proto3" json:"Session,omitempty"`
217
+	Frontend      string                                                   `protobuf:"bytes,6,opt,name=Frontend,proto3" json:"Frontend,omitempty"`
218
+	FrontendAttrs map[string]string                                        `protobuf:"bytes,7,rep,name=FrontendAttrs" json:"FrontendAttrs,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
219
+	Cache         CacheOptions                                             `protobuf:"bytes,8,opt,name=Cache" json:"Cache"`
220
+	Entitlements  []github_com_moby_buildkit_util_entitlements.Entitlement `protobuf:"bytes,9,rep,name=Entitlements,customtype=github.com/moby/buildkit/util/entitlements.Entitlement" json:"Entitlements,omitempty"`
220 221
 }
221 222
 
222 223
 func (m *SolveRequest) Reset()                    { *m = SolveRequest{} }
... ...
@@ -955,6 +973,16 @@ func (m *PruneRequest) MarshalTo(dAtA []byte) (int, error) {
955 955
 		}
956 956
 		i++
957 957
 	}
958
+	if m.KeepDuration != 0 {
959
+		dAtA[i] = 0x18
960
+		i++
961
+		i = encodeVarintControl(dAtA, i, uint64(m.KeepDuration))
962
+	}
963
+	if m.KeepBytes != 0 {
964
+		dAtA[i] = 0x20
965
+		i++
966
+		i = encodeVarintControl(dAtA, i, uint64(m.KeepBytes))
967
+	}
958 968
 	return i, nil
959 969
 }
960 970
 
... ...
@@ -1212,6 +1240,21 @@ func (m *SolveRequest) MarshalTo(dAtA []byte) (int, error) {
1212 1212
 		return 0, err
1213 1213
 	}
1214 1214
 	i += n4
1215
+	if len(m.Entitlements) > 0 {
1216
+		for _, s := range m.Entitlements {
1217
+			dAtA[i] = 0x4a
1218
+			i++
1219
+			l = len(s)
1220
+			for l >= 1<<7 {
1221
+				dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
1222
+				l >>= 7
1223
+				i++
1224
+			}
1225
+			dAtA[i] = uint8(l)
1226
+			i++
1227
+			i += copy(dAtA[i:], s)
1228
+		}
1229
+	}
1215 1230
 	return i, nil
1216 1231
 }
1217 1232
 
... ...
@@ -1690,6 +1733,12 @@ func (m *PruneRequest) Size() (n int) {
1690 1690
 	if m.All {
1691 1691
 		n += 2
1692 1692
 	}
1693
+	if m.KeepDuration != 0 {
1694
+		n += 1 + sovControl(uint64(m.KeepDuration))
1695
+	}
1696
+	if m.KeepBytes != 0 {
1697
+		n += 1 + sovControl(uint64(m.KeepBytes))
1698
+	}
1693 1699
 	return n
1694 1700
 }
1695 1701
 
... ...
@@ -1801,6 +1850,12 @@ func (m *SolveRequest) Size() (n int) {
1801 1801
 	}
1802 1802
 	l = m.Cache.Size()
1803 1803
 	n += 1 + l + sovControl(uint64(l))
1804
+	if len(m.Entitlements) > 0 {
1805
+		for _, s := range m.Entitlements {
1806
+			l = len(s)
1807
+			n += 1 + l + sovControl(uint64(l))
1808
+		}
1809
+	}
1804 1810
 	return n
1805 1811
 }
1806 1812
 
... ...
@@ -2089,6 +2144,44 @@ func (m *PruneRequest) Unmarshal(dAtA []byte) error {
2089 2089
 				}
2090 2090
 			}
2091 2091
 			m.All = bool(v != 0)
2092
+		case 3:
2093
+			if wireType != 0 {
2094
+				return fmt.Errorf("proto: wrong wireType = %d for field KeepDuration", wireType)
2095
+			}
2096
+			m.KeepDuration = 0
2097
+			for shift := uint(0); ; shift += 7 {
2098
+				if shift >= 64 {
2099
+					return ErrIntOverflowControl
2100
+				}
2101
+				if iNdEx >= l {
2102
+					return io.ErrUnexpectedEOF
2103
+				}
2104
+				b := dAtA[iNdEx]
2105
+				iNdEx++
2106
+				m.KeepDuration |= (int64(b) & 0x7F) << shift
2107
+				if b < 0x80 {
2108
+					break
2109
+				}
2110
+			}
2111
+		case 4:
2112
+			if wireType != 0 {
2113
+				return fmt.Errorf("proto: wrong wireType = %d for field KeepBytes", wireType)
2114
+			}
2115
+			m.KeepBytes = 0
2116
+			for shift := uint(0); ; shift += 7 {
2117
+				if shift >= 64 {
2118
+					return ErrIntOverflowControl
2119
+				}
2120
+				if iNdEx >= l {
2121
+					return io.ErrUnexpectedEOF
2122
+				}
2123
+				b := dAtA[iNdEx]
2124
+				iNdEx++
2125
+				m.KeepBytes |= (int64(b) & 0x7F) << shift
2126
+				if b < 0x80 {
2127
+					break
2128
+				}
2129
+			}
2092 2130
 		default:
2093 2131
 			iNdEx = preIndex
2094 2132
 			skippy, err := skipControl(dAtA[iNdEx:])
... ...
@@ -3041,6 +3134,35 @@ func (m *SolveRequest) Unmarshal(dAtA []byte) error {
3041 3041
 				return err
3042 3042
 			}
3043 3043
 			iNdEx = postIndex
3044
+		case 9:
3045
+			if wireType != 2 {
3046
+				return fmt.Errorf("proto: wrong wireType = %d for field Entitlements", wireType)
3047
+			}
3048
+			var stringLen uint64
3049
+			for shift := uint(0); ; shift += 7 {
3050
+				if shift >= 64 {
3051
+					return ErrIntOverflowControl
3052
+				}
3053
+				if iNdEx >= l {
3054
+					return io.ErrUnexpectedEOF
3055
+				}
3056
+				b := dAtA[iNdEx]
3057
+				iNdEx++
3058
+				stringLen |= (uint64(b) & 0x7F) << shift
3059
+				if b < 0x80 {
3060
+					break
3061
+				}
3062
+			}
3063
+			intStringLen := int(stringLen)
3064
+			if intStringLen < 0 {
3065
+				return ErrInvalidLengthControl
3066
+			}
3067
+			postIndex := iNdEx + intStringLen
3068
+			if postIndex > l {
3069
+				return io.ErrUnexpectedEOF
3070
+			}
3071
+			m.Entitlements = append(m.Entitlements, github_com_moby_buildkit_util_entitlements.Entitlement(dAtA[iNdEx:postIndex]))
3072
+			iNdEx = postIndex
3044 3073
 		default:
3045 3074
 			iNdEx = preIndex
3046 3075
 			skippy, err := skipControl(dAtA[iNdEx:])
... ...
@@ -4709,81 +4831,85 @@ var (
4709 4709
 func init() { proto.RegisterFile("control.proto", fileDescriptorControl) }
4710 4710
 
4711 4711
 var fileDescriptorControl = []byte{
4712
-	// 1206 bytes of a gzipped FileDescriptorProto
4713
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x56, 0x4f, 0x6f, 0x1b, 0x45,
4714
-	0x14, 0x67, 0x6d, 0xc7, 0x7f, 0x9e, 0x9d, 0x2a, 0x0c, 0x50, 0xad, 0x16, 0x48, 0xcc, 0x02, 0x92,
4715
-	0x55, 0xb5, 0xbb, 0x6d, 0xa0, 0x52, 0x15, 0xa1, 0xaa, 0x75, 0x5c, 0x44, 0xaa, 0x44, 0x94, 0x75,
4716
-	0x42, 0x25, 0x6e, 0x6b, 0x7b, 0xe2, 0xac, 0xb2, 0xde, 0x59, 0x66, 0x66, 0x43, 0xcd, 0xa7, 0xe0,
4717
-	0xc0, 0x37, 0xe1, 0xc0, 0x27, 0x40, 0xea, 0x91, 0x33, 0x87, 0x14, 0xe5, 0x0e, 0x77, 0x6e, 0x68,
4718
-	0xfe, 0xac, 0x3d, 0x8e, 0x9d, 0x38, 0x49, 0x4f, 0x99, 0x37, 0xf9, 0xbd, 0x9f, 0xdf, 0x7b, 0xbf,
4719
-	0xb7, 0xf3, 0x1e, 0xac, 0xf6, 0x49, 0xc2, 0x29, 0x89, 0xbd, 0x94, 0x12, 0x4e, 0xd0, 0xda, 0x88,
4720
-	0xf4, 0xc6, 0x5e, 0x2f, 0x8b, 0xe2, 0xc1, 0x71, 0xc4, 0xbd, 0x93, 0x07, 0xce, 0xbd, 0x61, 0xc4,
4721
-	0x8f, 0xb2, 0x9e, 0xd7, 0x27, 0x23, 0x7f, 0x48, 0x86, 0xc4, 0x97, 0xc0, 0x5e, 0x76, 0x28, 0x2d,
4722
-	0x69, 0xc8, 0x93, 0x22, 0x70, 0x36, 0x86, 0x84, 0x0c, 0x63, 0x3c, 0x45, 0xf1, 0x68, 0x84, 0x19,
4723
-	0x0f, 0x47, 0xa9, 0x06, 0xdc, 0x35, 0xf8, 0xc4, 0x8f, 0xf9, 0xf9, 0x8f, 0xf9, 0x8c, 0xc4, 0x27,
4724
-	0x98, 0xfa, 0x69, 0xcf, 0x27, 0x29, 0xd3, 0x68, 0xff, 0x42, 0x74, 0x98, 0x46, 0x3e, 0x1f, 0xa7,
4725
-	0x98, 0xf9, 0x3f, 0x11, 0x7a, 0x8c, 0xa9, 0x72, 0x70, 0x1f, 0x41, 0xe3, 0x05, 0xcd, 0x12, 0x1c,
4726
-	0xe0, 0x1f, 0x33, 0xcc, 0x38, 0xba, 0x0d, 0xe5, 0xc3, 0x28, 0xe6, 0x98, 0xda, 0x56, 0xb3, 0xd8,
4727
-	0xaa, 0x05, 0xda, 0x42, 0x6b, 0x50, 0x0c, 0xe3, 0xd8, 0x2e, 0x34, 0xad, 0x56, 0x35, 0x10, 0x47,
4728
-	0xf7, 0x0e, 0xac, 0x75, 0x22, 0x76, 0x7c, 0xc0, 0xc2, 0xe1, 0x32, 0x6f, 0xf7, 0x39, 0xbc, 0x6b,
4729
-	0x60, 0x59, 0x4a, 0x12, 0x86, 0xd1, 0x43, 0x28, 0x53, 0xdc, 0x27, 0x74, 0x20, 0xc1, 0xf5, 0xcd,
4730
-	0x8f, 0xbd, 0xf3, 0xc5, 0xf4, 0xb4, 0x83, 0x00, 0x05, 0x1a, 0xec, 0xfe, 0x57, 0x80, 0xba, 0x71,
4731
-	0x8f, 0x6e, 0x41, 0x61, 0xa7, 0x63, 0x5b, 0x4d, 0xab, 0x55, 0x0b, 0x0a, 0x3b, 0x1d, 0x64, 0x43,
4732
-	0x65, 0x2f, 0xe3, 0x61, 0x2f, 0xc6, 0x3a, 0xda, 0xdc, 0x44, 0xef, 0xc3, 0xca, 0x4e, 0x72, 0xc0,
4733
-	0xb0, 0x5d, 0x94, 0xf7, 0xca, 0x40, 0x08, 0x4a, 0xdd, 0xe8, 0x67, 0x6c, 0x97, 0x9a, 0x56, 0xab,
4734
-	0x18, 0xc8, 0xb3, 0xc8, 0xe3, 0x45, 0x48, 0x71, 0xc2, 0xed, 0x15, 0xc9, 0xab, 0x2d, 0xd4, 0x86,
4735
-	0xda, 0x36, 0xc5, 0x21, 0xc7, 0x83, 0xa7, 0xdc, 0x2e, 0x37, 0xad, 0x56, 0x7d, 0xd3, 0xf1, 0x94,
4736
-	0x82, 0x5e, 0xae, 0xa0, 0xb7, 0x9f, 0x2b, 0xd8, 0xae, 0xbe, 0x3e, 0xdd, 0x78, 0xe7, 0x97, 0x37,
4737
-	0x1b, 0x56, 0x30, 0x75, 0x43, 0x4f, 0x00, 0x76, 0x43, 0xc6, 0x0f, 0x98, 0x24, 0xa9, 0x2c, 0x25,
4738
-	0x29, 0x49, 0x02, 0xc3, 0x07, 0xad, 0x03, 0xc8, 0x02, 0x6c, 0x93, 0x2c, 0xe1, 0x76, 0x55, 0xc6,
4739
-	0x6d, 0xdc, 0xa0, 0x26, 0xd4, 0x3b, 0x98, 0xf5, 0x69, 0x94, 0xf2, 0x88, 0x24, 0x76, 0x4d, 0xa6,
4740
-	0x60, 0x5e, 0x09, 0x06, 0x55, 0xbd, 0xfd, 0x71, 0x8a, 0x6d, 0x90, 0x00, 0xe3, 0x46, 0xe4, 0xdf,
4741
-	0x3d, 0x0a, 0x29, 0x1e, 0xd8, 0x75, 0x59, 0x2a, 0x6d, 0xb9, 0xbf, 0x96, 0xa0, 0xd1, 0x15, 0x6d,
4742
-	0x97, 0x0b, 0xbe, 0x06, 0xc5, 0x00, 0x1f, 0xea, 0xea, 0x8b, 0x23, 0xf2, 0x00, 0x3a, 0xf8, 0x30,
4743
-	0x4a, 0x22, 0xf9, 0xdb, 0x05, 0x99, 0xde, 0x2d, 0x2f, 0xed, 0x79, 0xd3, 0xdb, 0xc0, 0x40, 0x20,
4744
-	0x07, 0xaa, 0xcf, 0x5e, 0xa5, 0x84, 0x8a, 0xa6, 0x29, 0x4a, 0x9a, 0x89, 0x8d, 0x5e, 0xc2, 0x6a,
4745
-	0x7e, 0x7e, 0xca, 0x39, 0x65, 0x76, 0x49, 0x36, 0xca, 0x83, 0xf9, 0x46, 0x31, 0x83, 0xf2, 0x66,
4746
-	0x7c, 0x9e, 0x25, 0x9c, 0x8e, 0x83, 0x59, 0x1e, 0xd1, 0x23, 0x5d, 0xcc, 0x98, 0x88, 0x50, 0x09,
4747
-	0x9c, 0x9b, 0x22, 0x9c, 0xaf, 0x29, 0x49, 0x38, 0x4e, 0x06, 0x52, 0xe0, 0x5a, 0x30, 0xb1, 0x45,
4748
-	0x38, 0xf9, 0x59, 0x85, 0x53, 0xb9, 0x52, 0x38, 0x33, 0x3e, 0x3a, 0x9c, 0x99, 0x3b, 0xb4, 0x05,
4749
-	0x2b, 0xdb, 0x61, 0xff, 0x08, 0x4b, 0x2d, 0xeb, 0x9b, 0xeb, 0xf3, 0x84, 0xf2, 0xdf, 0xdf, 0x4a,
4750
-	0xf1, 0x58, 0xbb, 0x24, 0xda, 0x2a, 0x50, 0x2e, 0xce, 0x13, 0x40, 0xf3, 0xf9, 0x0a, 0x5d, 0x8e,
4751
-	0xf1, 0x38, 0xd7, 0xe5, 0x18, 0x8f, 0x45, 0xf3, 0x9f, 0x84, 0x71, 0xa6, 0x3e, 0x8a, 0x5a, 0xa0,
4752
-	0x8c, 0xad, 0xc2, 0x23, 0x4b, 0x30, 0xcc, 0x87, 0x78, 0x1d, 0x06, 0xf7, 0x8d, 0x05, 0x0d, 0x33,
4753
-	0x42, 0xf4, 0x11, 0xd4, 0x54, 0x50, 0xd3, 0xe6, 0x98, 0x5e, 0x88, 0xee, 0xdb, 0x19, 0x69, 0x83,
4754
-	0xd9, 0x05, 0xf9, 0x52, 0x18, 0x37, 0xe8, 0x3b, 0xa8, 0x2b, 0xb0, 0xaa, 0x72, 0x51, 0x56, 0xd9,
4755
-	0xbf, 0xbc, 0x28, 0x9e, 0xe1, 0xa1, 0x6a, 0x6c, 0x72, 0x38, 0x8f, 0x61, 0xed, 0x3c, 0xe0, 0x5a,
4756
-	0x19, 0xfe, 0x6e, 0xc1, 0xaa, 0x16, 0x55, 0xbf, 0x5e, 0x61, 0xce, 0x88, 0x69, 0x7e, 0xa7, 0xdf,
4757
-	0xb1, 0x87, 0x17, 0xf6, 0x83, 0x82, 0x79, 0xe7, 0xfd, 0x54, 0xbc, 0x73, 0x74, 0xce, 0x36, 0x7c,
4758
-	0xb0, 0x10, 0x7a, 0xad, 0xc8, 0x3f, 0x81, 0xd5, 0x2e, 0x0f, 0x79, 0xc6, 0x2e, 0xfc, 0x64, 0xdd,
4759
-	0xdf, 0x2c, 0xb8, 0x95, 0x63, 0x74, 0x76, 0x5f, 0x42, 0xf5, 0x04, 0x53, 0x8e, 0x5f, 0x61, 0xa6,
4760
-	0xb3, 0xb2, 0xe7, 0xb3, 0xfa, 0x5e, 0x22, 0x82, 0x09, 0x12, 0x6d, 0x41, 0x95, 0x49, 0x1e, 0xac,
4761
-	0x64, 0x5d, 0xd8, 0xca, 0xca, 0x4b, 0xff, 0xde, 0x04, 0x8f, 0x7c, 0x28, 0xc5, 0x64, 0x98, 0xab,
4762
-	0xfd, 0xe1, 0x45, 0x7e, 0xbb, 0x64, 0x18, 0x48, 0xa0, 0x7b, 0x5a, 0x80, 0xb2, 0xba, 0x43, 0xcf,
4763
-	0xa1, 0x3c, 0x88, 0x86, 0x98, 0x71, 0x95, 0x55, 0x7b, 0x53, 0x7c, 0x20, 0x7f, 0x9d, 0x6e, 0xdc,
4764
-	0x31, 0xa6, 0x21, 0x49, 0x71, 0x22, 0x66, 0x77, 0x18, 0x25, 0x98, 0x32, 0x7f, 0x48, 0xee, 0x29,
4765
-	0x17, 0xaf, 0x23, 0xff, 0x04, 0x9a, 0x41, 0x70, 0x45, 0x49, 0x9a, 0x71, 0xdd, 0x98, 0x37, 0xe3,
4766
-	0x52, 0x0c, 0x62, 0xb4, 0x24, 0xe1, 0x08, 0xeb, 0x77, 0x4d, 0x9e, 0xc5, 0xd3, 0xda, 0x17, 0x7d,
4767
-	0x3b, 0x90, 0x03, 0xa7, 0x1a, 0x68, 0x0b, 0x6d, 0x41, 0x85, 0xf1, 0x90, 0x72, 0x3c, 0x90, 0x4f,
4768
-	0xd2, 0x55, 0x66, 0x42, 0xee, 0x80, 0x1e, 0x43, 0xad, 0x4f, 0x46, 0x69, 0x8c, 0x85, 0x77, 0xf9,
4769
-	0x8a, 0xde, 0x53, 0x17, 0xd1, 0x3d, 0x98, 0x52, 0x42, 0xe5, 0x34, 0xaa, 0x05, 0xca, 0x70, 0xff,
4770
-	0x2d, 0x40, 0xc3, 0x14, 0x6b, 0x6e, 0xd2, 0x3e, 0x87, 0xb2, 0x92, 0x5e, 0x75, 0xdd, 0xcd, 0x4a,
4771
-	0xa5, 0x18, 0x16, 0x96, 0xca, 0x86, 0x4a, 0x3f, 0xa3, 0x72, 0x0c, 0xab, 0xe1, 0x9c, 0x9b, 0x22,
4772
-	0x60, 0x4e, 0x78, 0x18, 0xcb, 0x52, 0x15, 0x03, 0x65, 0x88, 0xe9, 0x3c, 0xd9, 0x9e, 0xae, 0x37,
4773
-	0x9d, 0x27, 0x6e, 0xa6, 0x0c, 0x95, 0xb7, 0x92, 0xa1, 0x7a, 0x6d, 0x19, 0xdc, 0x3f, 0x2c, 0xa8,
4774
-	0x4d, 0xba, 0xdc, 0xa8, 0xae, 0xf5, 0xd6, 0xd5, 0x9d, 0xa9, 0x4c, 0xe1, 0x66, 0x95, 0xb9, 0x0d,
4775
-	0x65, 0xc6, 0x29, 0x0e, 0x47, 0x52, 0xa3, 0x62, 0xa0, 0x2d, 0xf1, 0x9e, 0x8c, 0xd8, 0x50, 0x2a,
4776
-	0xd4, 0x08, 0xc4, 0xd1, 0x75, 0xa1, 0xd1, 0x1e, 0x73, 0xcc, 0xf6, 0x30, 0x13, 0x4b, 0x89, 0xd0,
4777
-	0x76, 0x10, 0xf2, 0x50, 0xe6, 0xd1, 0x08, 0xe4, 0xd9, 0xbd, 0x0b, 0x68, 0x37, 0x62, 0xfc, 0xa5,
4778
-	0xdc, 0x45, 0xd9, 0xb2, 0xfd, 0xb1, 0x0b, 0xef, 0xcd, 0xa0, 0xf5, 0x2b, 0xf5, 0xd5, 0xb9, 0x0d,
4779
-	0xf2, 0xb3, 0xf9, 0x57, 0x43, 0xae, 0xbc, 0x9e, 0x72, 0x9c, 0x5d, 0x24, 0x37, 0xff, 0x29, 0x42,
4780
-	0x65, 0x5b, 0x6d, 0xf3, 0x68, 0x1f, 0x6a, 0x93, 0x05, 0x15, 0xb9, 0xf3, 0x34, 0xe7, 0x37, 0x5d,
4781
-	0xe7, 0xd3, 0x4b, 0x31, 0x3a, 0xbe, 0x6f, 0x60, 0x45, 0x2e, 0xd7, 0x68, 0xc1, 0x33, 0x68, 0x6e,
4782
-	0xdd, 0xce, 0xe5, 0xab, 0xef, 0x7d, 0x4b, 0x30, 0xc9, 0x19, 0xb2, 0x88, 0xc9, 0x5c, 0x36, 0x9c,
4783
-	0x8d, 0x25, 0xc3, 0x07, 0xed, 0x41, 0x59, 0x7f, 0xce, 0x8b, 0xa0, 0xe6, 0xa4, 0x70, 0x9a, 0x17,
4784
-	0x03, 0x14, 0xd9, 0x7d, 0x0b, 0xed, 0x4d, 0x36, 0xa9, 0x45, 0xa1, 0x99, 0x6d, 0xe0, 0x2c, 0xf9,
4785
-	0x7f, 0xcb, 0xba, 0x6f, 0xa1, 0x1f, 0xa0, 0x6e, 0x08, 0x8d, 0x16, 0x08, 0x3a, 0xdf, 0x35, 0xce,
4786
-	0xe7, 0x4b, 0x50, 0x2a, 0xd8, 0x76, 0xe3, 0xf5, 0xd9, 0xba, 0xf5, 0xe7, 0xd9, 0xba, 0xf5, 0xf7,
4787
-	0xd9, 0xba, 0xd5, 0x2b, 0xcb, 0xbe, 0xff, 0xe2, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x10, 0x8f,
4788
-	0x03, 0xa4, 0xd1, 0x0d, 0x00, 0x00,
4712
+	// 1279 bytes of a gzipped FileDescriptorProto
4713
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x57, 0x4f, 0x6f, 0x1b, 0x45,
4714
+	0x14, 0xef, 0xda, 0x89, 0xed, 0x7d, 0x76, 0xaa, 0x30, 0x40, 0xb5, 0x5a, 0x20, 0x31, 0x0b, 0x48,
4715
+	0x56, 0xd5, 0xee, 0xb6, 0x81, 0x22, 0x14, 0xa1, 0xaa, 0x75, 0x5c, 0x44, 0xaa, 0x46, 0x94, 0x49,
4716
+	0x4b, 0x25, 0x0e, 0x48, 0x6b, 0x7b, 0xe2, 0xae, 0xb2, 0xde, 0x59, 0x66, 0x66, 0x43, 0xcd, 0x07,
4717
+	0xe0, 0xcc, 0x77, 0xe1, 0xc0, 0x27, 0x40, 0xea, 0x91, 0x73, 0x0f, 0x29, 0xea, 0x1d, 0x4e, 0x5c,
4718
+	0xb8, 0xa1, 0xf9, 0xb3, 0xce, 0x38, 0x76, 0xea, 0xa6, 0x3d, 0x65, 0xde, 0xe4, 0xf7, 0x7e, 0xfb,
4719
+	0xfe, 0xcd, 0x7b, 0xcf, 0xb0, 0x36, 0xa0, 0x99, 0x60, 0x34, 0x0d, 0x73, 0x46, 0x05, 0x45, 0xeb,
4720
+	0x63, 0xda, 0x9f, 0x84, 0xfd, 0x22, 0x49, 0x87, 0x87, 0x89, 0x08, 0x8f, 0xae, 0xfb, 0x57, 0x47,
4721
+	0x89, 0x78, 0x5c, 0xf4, 0xc3, 0x01, 0x1d, 0x47, 0x23, 0x3a, 0xa2, 0x91, 0x02, 0xf6, 0x8b, 0x03,
4722
+	0x25, 0x29, 0x41, 0x9d, 0x34, 0x81, 0xbf, 0x39, 0xa2, 0x74, 0x94, 0x92, 0x13, 0x94, 0x48, 0xc6,
4723
+	0x84, 0x8b, 0x78, 0x9c, 0x1b, 0xc0, 0x15, 0x8b, 0x4f, 0x7e, 0x2c, 0x2a, 0x3f, 0x16, 0x71, 0x9a,
4724
+	0x1e, 0x11, 0x16, 0xe5, 0xfd, 0x88, 0xe6, 0xdc, 0xa0, 0xa3, 0x33, 0xd1, 0x71, 0x9e, 0x44, 0x62,
4725
+	0x92, 0x13, 0x1e, 0xfd, 0x44, 0xd9, 0x21, 0x61, 0x5a, 0x21, 0xf8, 0xc5, 0x81, 0xd6, 0x7d, 0x56,
4726
+	0x64, 0x04, 0x93, 0x1f, 0x0b, 0xc2, 0x05, 0xba, 0x04, 0xb5, 0x83, 0x24, 0x15, 0x84, 0x79, 0x4e,
4727
+	0xbb, 0xda, 0x71, 0xb1, 0x91, 0xd0, 0x3a, 0x54, 0xe3, 0x34, 0xf5, 0x2a, 0x6d, 0xa7, 0xd3, 0xc0,
4728
+	0xf2, 0x88, 0x3a, 0xd0, 0x3a, 0x24, 0x24, 0xef, 0x15, 0x2c, 0x16, 0x09, 0xcd, 0xbc, 0x6a, 0xdb,
4729
+	0xe9, 0x54, 0xbb, 0x2b, 0x4f, 0x8f, 0x37, 0x1d, 0x3c, 0xf3, 0x1f, 0x14, 0x80, 0x2b, 0xe5, 0xee,
4730
+	0x44, 0x10, 0xee, 0xad, 0x58, 0xb0, 0x93, 0xeb, 0xe0, 0x32, 0xac, 0xf7, 0x12, 0x7e, 0xf8, 0x90,
4731
+	0xc7, 0xa3, 0x65, 0xb6, 0x04, 0x77, 0xe1, 0x2d, 0x0b, 0xcb, 0x73, 0x9a, 0x71, 0x82, 0x6e, 0x40,
4732
+	0x8d, 0x91, 0x01, 0x65, 0x43, 0x05, 0x6e, 0x6e, 0x7d, 0x10, 0x9e, 0xce, 0x4d, 0x68, 0x14, 0x24,
4733
+	0x08, 0x1b, 0x70, 0xf0, 0x5f, 0x05, 0x9a, 0xd6, 0x3d, 0xba, 0x08, 0x95, 0xdd, 0x9e, 0xe7, 0xb4,
4734
+	0x9d, 0x8e, 0x8b, 0x2b, 0xbb, 0x3d, 0xe4, 0x41, 0x7d, 0xaf, 0x10, 0x71, 0x3f, 0x25, 0xc6, 0xf7,
4735
+	0x52, 0x44, 0xef, 0xc0, 0xea, 0x6e, 0xf6, 0x90, 0x13, 0xe5, 0x78, 0x03, 0x6b, 0x01, 0x21, 0x58,
4736
+	0xd9, 0x4f, 0x7e, 0x26, 0xda, 0x4d, 0xac, 0xce, 0xd2, 0x8f, 0xfb, 0x31, 0x23, 0x99, 0xf0, 0x56,
4737
+	0x15, 0xaf, 0x91, 0x50, 0x17, 0xdc, 0x1d, 0x46, 0x62, 0x41, 0x86, 0xb7, 0x85, 0x57, 0x6b, 0x3b,
4738
+	0x9d, 0xe6, 0x96, 0x1f, 0xea, 0x82, 0x08, 0xcb, 0x82, 0x08, 0x1f, 0x94, 0x05, 0xd1, 0x6d, 0x3c,
4739
+	0x3d, 0xde, 0xbc, 0xf0, 0xeb, 0x73, 0x19, 0xb7, 0xa9, 0x1a, 0xba, 0x05, 0x70, 0x2f, 0xe6, 0xe2,
4740
+	0x21, 0x57, 0x24, 0xf5, 0xa5, 0x24, 0x2b, 0x8a, 0xc0, 0xd2, 0x41, 0x1b, 0x00, 0x2a, 0x00, 0x3b,
4741
+	0xb4, 0xc8, 0x84, 0xd7, 0x50, 0x76, 0x5b, 0x37, 0xa8, 0x0d, 0xcd, 0x1e, 0xe1, 0x03, 0x96, 0xe4,
4742
+	0x2a, 0xcd, 0xae, 0x72, 0xc1, 0xbe, 0x92, 0x0c, 0x3a, 0x7a, 0x0f, 0x26, 0x39, 0xf1, 0x40, 0x01,
4743
+	0xac, 0x1b, 0xe9, 0xff, 0xfe, 0xe3, 0x98, 0x91, 0xa1, 0xd7, 0x54, 0xa1, 0x32, 0x52, 0xf0, 0xef,
4744
+	0x0a, 0xb4, 0xf6, 0x65, 0x15, 0x97, 0x09, 0x5f, 0x87, 0x2a, 0x26, 0x07, 0x26, 0xfa, 0xf2, 0x88,
4745
+	0x42, 0x80, 0x1e, 0x39, 0x48, 0xb2, 0x44, 0x7d, 0xbb, 0xa2, 0xdc, 0xbb, 0x18, 0xe6, 0xfd, 0xf0,
4746
+	0xe4, 0x16, 0x5b, 0x08, 0xe4, 0x43, 0xe3, 0xce, 0x93, 0x9c, 0x32, 0x59, 0x34, 0x55, 0x45, 0x33,
4747
+	0x95, 0xd1, 0x23, 0x58, 0x2b, 0xcf, 0xb7, 0x85, 0x60, 0xb2, 0x14, 0x65, 0xa1, 0x5c, 0x9f, 0x2f,
4748
+	0x14, 0xdb, 0xa8, 0x70, 0x46, 0xe7, 0x4e, 0x26, 0xd8, 0x04, 0xcf, 0xf2, 0xc8, 0x1a, 0xd9, 0x27,
4749
+	0x9c, 0x4b, 0x0b, 0x75, 0x82, 0x4b, 0x51, 0x9a, 0xf3, 0x15, 0xa3, 0x99, 0x20, 0xd9, 0x50, 0x25,
4750
+	0xd8, 0xc5, 0x53, 0x59, 0x9a, 0x53, 0x9e, 0xb5, 0x39, 0xf5, 0x57, 0x32, 0x67, 0x46, 0xc7, 0x98,
4751
+	0x33, 0x73, 0x87, 0xb6, 0x61, 0x75, 0x27, 0x1e, 0x3c, 0x26, 0x2a, 0x97, 0xcd, 0xad, 0x8d, 0x79,
4752
+	0x42, 0xf5, 0xef, 0x6f, 0x54, 0xf2, 0xb8, 0x7a, 0x8a, 0x17, 0xb0, 0x56, 0x41, 0x3f, 0x40, 0xeb,
4753
+	0x4e, 0x26, 0x12, 0x91, 0x92, 0x31, 0xc9, 0x04, 0xf7, 0x5c, 0xf9, 0xf0, 0xba, 0xdb, 0xcf, 0x8e,
4754
+	0x37, 0x3f, 0x3f, 0xb3, 0xb5, 0x14, 0x22, 0x49, 0x23, 0x62, 0x69, 0x85, 0x16, 0x05, 0x9e, 0xe1,
4755
+	0xf3, 0x6f, 0x01, 0x9a, 0x8f, 0xa7, 0xcc, 0xfb, 0x21, 0x99, 0x94, 0x79, 0x3f, 0x24, 0x13, 0xf9,
4756
+	0xb8, 0x8e, 0xe2, 0xb4, 0xd0, 0x8f, 0xce, 0xc5, 0x5a, 0xd8, 0xae, 0x7c, 0xe1, 0x48, 0x86, 0xf9,
4757
+	0x10, 0x9c, 0x87, 0x21, 0x78, 0xee, 0x40, 0xcb, 0x8e, 0x00, 0x7a, 0x1f, 0x5c, 0x6d, 0xd4, 0x49,
4758
+	0xf1, 0x9d, 0x5c, 0xc8, 0xea, 0xde, 0x1d, 0x1b, 0x81, 0x7b, 0x15, 0xd5, 0x89, 0xac, 0x1b, 0xf4,
4759
+	0x2d, 0x34, 0x35, 0x58, 0x67, 0xb1, 0xaa, 0xb2, 0x18, 0xbd, 0x3c, 0xe8, 0xa1, 0xa5, 0xa1, 0x73,
4760
+	0x68, 0x73, 0xf8, 0x37, 0x61, 0xfd, 0x34, 0xe0, 0x5c, 0x1e, 0xfe, 0xee, 0xc0, 0x9a, 0x29, 0x1a,
4761
+	0xd3, 0x1d, 0xe3, 0x92, 0x91, 0xb0, 0xf2, 0xce, 0xf4, 0xc9, 0x1b, 0x67, 0xd6, 0x9b, 0x86, 0x85,
4762
+	0xa7, 0xf5, 0xb4, 0xbd, 0x73, 0x74, 0xfe, 0x0e, 0xbc, 0xbb, 0x10, 0x7a, 0x2e, 0xcb, 0x3f, 0x84,
4763
+	0xb5, 0x7d, 0x11, 0x8b, 0x82, 0x9f, 0xd9, 0x12, 0x82, 0xdf, 0x1c, 0xb8, 0x58, 0x62, 0x8c, 0x77,
4764
+	0x9f, 0x41, 0xe3, 0x88, 0x30, 0x41, 0x9e, 0x10, 0x6e, 0xbc, 0xf2, 0xe6, 0xbd, 0xfa, 0x4e, 0x21,
4765
+	0xf0, 0x14, 0x89, 0xb6, 0xa1, 0xc1, 0x15, 0x0f, 0xd1, 0x69, 0x5d, 0xf8, 0x54, 0xb4, 0x96, 0xf9,
4766
+	0xde, 0x14, 0x8f, 0x22, 0x58, 0x49, 0xe9, 0xa8, 0xcc, 0xf6, 0x7b, 0x67, 0xe9, 0xdd, 0xa3, 0x23,
4767
+	0xac, 0x80, 0xc1, 0x71, 0x05, 0x6a, 0xfa, 0x0e, 0xdd, 0x85, 0xda, 0x30, 0x19, 0x11, 0x2e, 0xb4,
4768
+	0x57, 0xdd, 0x2d, 0xf9, 0x00, 0x9f, 0x1d, 0x6f, 0x5e, 0xb6, 0x5e, 0x18, 0xcd, 0x49, 0x26, 0x57,
4769
+	0x8d, 0x38, 0xc9, 0x08, 0xe3, 0xd1, 0x88, 0x5e, 0xd5, 0x2a, 0x61, 0x4f, 0xfd, 0xc1, 0x86, 0x41,
4770
+	0x72, 0x25, 0x59, 0x5e, 0x08, 0x53, 0x98, 0xaf, 0xc7, 0xa5, 0x19, 0xe4, 0xe8, 0xca, 0xe2, 0x31,
4771
+	0x31, 0x7d, 0x53, 0x9d, 0x65, 0xeb, 0x1e, 0xc8, 0xba, 0x1d, 0xaa, 0x81, 0xd6, 0xc0, 0x46, 0x42,
4772
+	0xdb, 0x50, 0xe7, 0x22, 0x66, 0x82, 0x0c, 0x55, 0xcb, 0x7b, 0x95, 0x99, 0x53, 0x2a, 0xa0, 0x9b,
4773
+	0xe0, 0x0e, 0xe8, 0x38, 0x4f, 0x89, 0xd4, 0xae, 0xbd, 0xa2, 0xf6, 0x89, 0x8a, 0xac, 0x1e, 0xc2,
4774
+	0x18, 0x65, 0x6a, 0xda, 0xb9, 0x58, 0x0b, 0xc1, 0x3f, 0x15, 0x68, 0xd9, 0xc9, 0x9a, 0x9b, 0xe4,
4775
+	0x77, 0xa1, 0xa6, 0x53, 0xaf, 0xab, 0xee, 0xf5, 0x42, 0xa5, 0x19, 0x16, 0x86, 0xca, 0x83, 0xfa,
4776
+	0xa0, 0x60, 0x6a, 0xcc, 0xeb, 0xe1, 0x5f, 0x8a, 0xd2, 0x60, 0x41, 0x45, 0x9c, 0xaa, 0x50, 0x55,
4777
+	0xb1, 0x16, 0xe4, 0xf4, 0x9f, 0x2e, 0x7b, 0xe7, 0x9b, 0xfe, 0x53, 0x35, 0x3b, 0x0d, 0xf5, 0x37,
4778
+	0x4a, 0x43, 0xe3, 0xdc, 0x69, 0x08, 0xfe, 0x70, 0xc0, 0x9d, 0x56, 0xb9, 0x15, 0x5d, 0xe7, 0x8d,
4779
+	0xa3, 0x3b, 0x13, 0x99, 0xca, 0xeb, 0x45, 0xe6, 0x12, 0xd4, 0xb8, 0x60, 0x24, 0x1e, 0xeb, 0xbd,
4780
+	0x14, 0x1b, 0x49, 0xf6, 0x93, 0x31, 0x1f, 0xa9, 0x0c, 0xb5, 0xb0, 0x3c, 0x06, 0x01, 0xb4, 0xd4,
4781
+	0x0a, 0xba, 0x47, 0xb8, 0x5c, 0x7a, 0x64, 0x6e, 0x87, 0xb1, 0x88, 0x95, 0x1f, 0x2d, 0xac, 0xce,
4782
+	0xc1, 0x15, 0x40, 0xf7, 0x12, 0x2e, 0x1e, 0xa9, 0xd5, 0x99, 0x2f, 0xdb, 0x4f, 0xf7, 0xe1, 0xed,
4783
+	0x19, 0xb4, 0xe9, 0x52, 0x5f, 0x9e, 0xda, 0x50, 0x3f, 0x9e, 0xef, 0x1a, 0x6a, 0x43, 0x0f, 0xb5,
4784
+	0xe2, 0xec, 0xa2, 0xba, 0xf5, 0x77, 0x15, 0xea, 0x3b, 0xfa, 0xc7, 0x07, 0x7a, 0x00, 0xee, 0x74,
4785
+	0x01, 0x46, 0xc1, 0x3c, 0xcd, 0xe9, 0x4d, 0xda, 0xff, 0xe8, 0xa5, 0x18, 0x63, 0xdf, 0xd7, 0xb0,
4786
+	0xaa, 0x7e, 0x0a, 0xa0, 0x05, 0x6d, 0xd0, 0xfe, 0x8d, 0xe0, 0xbf, 0x7c, 0xb5, 0xbe, 0xe6, 0x48,
4787
+	0x26, 0x35, 0x43, 0x16, 0x31, 0xd9, 0xcb, 0x8c, 0xbf, 0xb9, 0x64, 0xf8, 0xa0, 0x3d, 0xa8, 0x99,
4788
+	0xe7, 0xbc, 0x08, 0x6a, 0x4f, 0x0a, 0xbf, 0x7d, 0x36, 0x40, 0x93, 0x5d, 0x73, 0xd0, 0xde, 0x74,
4789
+	0x53, 0x5b, 0x64, 0x9a, 0x5d, 0x06, 0xfe, 0x92, 0xff, 0x77, 0x9c, 0x6b, 0x0e, 0xfa, 0x1e, 0x9a,
4790
+	0x56, 0xa2, 0xd1, 0x82, 0x84, 0xce, 0x57, 0x8d, 0xff, 0xc9, 0x12, 0x94, 0x36, 0xb6, 0xdb, 0x7a,
4791
+	0xfa, 0x62, 0xc3, 0xf9, 0xf3, 0xc5, 0x86, 0xf3, 0xd7, 0x8b, 0x0d, 0xa7, 0x5f, 0x53, 0x75, 0xff,
4792
+	0xe9, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0xfe, 0x98, 0x98, 0x82, 0x80, 0x0e, 0x00, 0x00,
4789 4793
 }
... ...
@@ -25,8 +25,10 @@ service Control {
25 25
 }
26 26
 
27 27
 message PruneRequest {
28
-	repeated string filter = 1; // FIXME: not implemented
28
+	repeated string filter = 1;
29 29
 	bool all = 2;
30
+	int64 keepDuration = 3 [(gogoproto.nullable) = true];
31
+	int64 keepBytes = 4 [(gogoproto.nullable) = true];
30 32
 }
31 33
 
32 34
 message DiskUsageRequest {
... ...
@@ -60,6 +62,7 @@ message SolveRequest {
60 60
 	string Frontend = 6;
61 61
 	map<string, string> FrontendAttrs = 7;
62 62
 	CacheOptions Cache = 8 [(gogoproto.nullable) = false];
63
+	repeated string Entitlements = 9 [(gogoproto.customtype) = "github.com/moby/buildkit/util/entitlements.Entitlement" ];
63 64
 }
64 65
 
65 66
 message CacheOptions {
... ...
@@ -2,6 +2,7 @@ package cache
2 2
 
3 3
 import (
4 4
 	"context"
5
+	"sort"
5 6
 	"sync"
6 7
 	"time"
7 8
 
... ...
@@ -321,14 +322,50 @@ func (cm *cacheManager) Prune(ctx context.Context, ch chan client.UsageInfo, opt
321 321
 		check = c
322 322
 	}
323 323
 
324
-	return cm.prune(ctx, ch, filter, opt.All, check)
324
+	totalSize := int64(0)
325
+	if opt.KeepBytes != 0 {
326
+		du, err := cm.DiskUsage(ctx, client.DiskUsageInfo{})
327
+		if err != nil {
328
+			return err
329
+		}
330
+		for _, ui := range du {
331
+			if check != nil {
332
+				if check.Exists(ui.ID) {
333
+					continue
334
+				}
335
+			}
336
+			totalSize += ui.Size
337
+		}
338
+	}
339
+
340
+	return cm.prune(ctx, ch, pruneOpt{
341
+		filter:       filter,
342
+		all:          opt.All,
343
+		checkShared:  check,
344
+		keepDuration: opt.KeepDuration,
345
+		keepBytes:    opt.KeepBytes,
346
+		totalSize:    totalSize,
347
+	})
325 348
 }
326 349
 
327
-func (cm *cacheManager) prune(ctx context.Context, ch chan client.UsageInfo, filter filters.Filter, all bool, checkShared ExternalRefChecker) error {
328
-	var toDelete []*cacheRecord
350
+func (cm *cacheManager) prune(ctx context.Context, ch chan client.UsageInfo, opt pruneOpt) error {
351
+	var toDelete []*deleteRecord
352
+
353
+	if opt.keepBytes != 0 && opt.totalSize < opt.keepBytes {
354
+		return nil
355
+	}
356
+
329 357
 	cm.mu.Lock()
330 358
 
359
+	gcMode := opt.keepBytes != 0
360
+	cutOff := time.Now().Add(-opt.keepDuration)
361
+
362
+	locked := map[*cacheRecord]struct{}{}
363
+
331 364
 	for _, cr := range cm.records {
365
+		if _, ok := locked[cr]; ok {
366
+			continue
367
+		}
332 368
 		cr.mu.Lock()
333 369
 
334 370
 		// ignore duplicates that share data
... ...
@@ -349,11 +386,11 @@ func (cm *cacheManager) prune(ctx context.Context, ch chan client.UsageInfo, fil
349 349
 			}
350 350
 
351 351
 			shared := false
352
-			if checkShared != nil {
353
-				shared = checkShared.Exists(cr.ID())
352
+			if opt.checkShared != nil {
353
+				shared = opt.checkShared.Exists(cr.ID())
354 354
 			}
355 355
 
356
-			if !all {
356
+			if !opt.all {
357 357
 				if recordType == client.UsageRecordTypeInternal || recordType == client.UsageRecordTypeFrontend || shared {
358 358
 					cr.mu.Unlock()
359 359
 					continue
... ...
@@ -367,23 +404,59 @@ func (cm *cacheManager) prune(ctx context.Context, ch chan client.UsageInfo, fil
367 367
 				Shared:     shared,
368 368
 			}
369 369
 
370
-			if filter.Match(adaptUsageInfo(c)) {
371
-				cr.dead = true
370
+			usageCount, lastUsedAt := getLastUsed(cr.md)
371
+			c.LastUsedAt = lastUsedAt
372
+			c.UsageCount = usageCount
372 373
 
373
-				toDelete = append(toDelete, cr)
374
-
375
-				// mark metadata as deleted in case we crash before cleanup finished
376
-				if err := setDeleted(cr.md); err != nil {
374
+			if opt.keepDuration != 0 {
375
+				if lastUsedAt != nil && lastUsedAt.After(cutOff) {
377 376
 					cr.mu.Unlock()
378
-					cm.mu.Unlock()
379
-					return err
377
+					continue
380 378
 				}
381 379
 			}
382
-		}
383 380
 
381
+			if opt.filter.Match(adaptUsageInfo(c)) {
382
+				toDelete = append(toDelete, &deleteRecord{
383
+					cacheRecord: cr,
384
+					lastUsedAt:  c.LastUsedAt,
385
+					usageCount:  c.UsageCount,
386
+				})
387
+				if !gcMode {
388
+					cr.dead = true
389
+
390
+					// mark metadata as deleted in case we crash before cleanup finished
391
+					if err := setDeleted(cr.md); err != nil {
392
+						cr.mu.Unlock()
393
+						cm.mu.Unlock()
394
+						return err
395
+					}
396
+				} else {
397
+					locked[cr] = struct{}{}
398
+					continue // leave the record locked
399
+				}
400
+			}
401
+		}
384 402
 		cr.mu.Unlock()
385 403
 	}
386 404
 
405
+	if gcMode && len(toDelete) > 0 {
406
+		sortDeleteRecords(toDelete)
407
+		var err error
408
+		for i, cr := range toDelete {
409
+			// only remove single record at a time
410
+			if i == 0 {
411
+				cr.dead = true
412
+				err = setDeleted(cr.md)
413
+			}
414
+			cr.mu.Unlock()
415
+		}
416
+		if err != nil {
417
+			return err
418
+		}
419
+		toDelete = toDelete[:1]
420
+		opt.totalSize -= getSize(toDelete[0].md)
421
+	}
422
+
387 423
 	cm.mu.Unlock()
388 424
 
389 425
 	if len(toDelete) == 0 {
... ...
@@ -443,7 +516,7 @@ func (cm *cacheManager) prune(ctx context.Context, ch chan client.UsageInfo, fil
443 443
 	case <-ctx.Done():
444 444
 		return ctx.Err()
445 445
 	default:
446
-		return cm.prune(ctx, ch, filter, all, checkShared)
446
+		return cm.prune(ctx, ch, opt)
447 447
 	}
448 448
 }
449 449
 
... ...
@@ -705,3 +778,63 @@ func adaptUsageInfo(info *client.UsageInfo) filters.Adaptor {
705 705
 		return "", false
706 706
 	})
707 707
 }
708
+
709
+type pruneOpt struct {
710
+	filter       filters.Filter
711
+	all          bool
712
+	checkShared  ExternalRefChecker
713
+	keepDuration time.Duration
714
+	keepBytes    int64
715
+	totalSize    int64
716
+}
717
+
718
+type deleteRecord struct {
719
+	*cacheRecord
720
+	lastUsedAt      *time.Time
721
+	usageCount      int
722
+	lastUsedAtIndex int
723
+	usageCountIndex int
724
+}
725
+
726
+func sortDeleteRecords(toDelete []*deleteRecord) {
727
+	sort.Slice(toDelete, func(i, j int) bool {
728
+		if toDelete[i].lastUsedAt == nil {
729
+			return true
730
+		}
731
+		if toDelete[j].lastUsedAt == nil {
732
+			return false
733
+		}
734
+		return toDelete[i].lastUsedAt.Before(*toDelete[j].lastUsedAt)
735
+	})
736
+
737
+	maxLastUsedIndex := 0
738
+	var val time.Time
739
+	for _, v := range toDelete {
740
+		if v.lastUsedAt != nil && v.lastUsedAt.After(val) {
741
+			val = *v.lastUsedAt
742
+			maxLastUsedIndex++
743
+		}
744
+		v.lastUsedAtIndex = maxLastUsedIndex
745
+	}
746
+
747
+	sort.Slice(toDelete, func(i, j int) bool {
748
+		return toDelete[i].usageCount < toDelete[j].usageCount
749
+	})
750
+
751
+	maxUsageCountIndex := 0
752
+	var count int
753
+	for _, v := range toDelete {
754
+		if v.usageCount != count {
755
+			count = v.usageCount
756
+			maxUsageCountIndex++
757
+		}
758
+		v.usageCountIndex = maxUsageCountIndex
759
+	}
760
+
761
+	sort.Slice(toDelete, func(i, j int) bool {
762
+		return float64(toDelete[i].lastUsedAtIndex)/float64(maxLastUsedIndex)+
763
+			float64(toDelete[i].usageCountIndex)/float64(maxUsageCountIndex) <
764
+			float64(toDelete[j].lastUsedAtIndex)/float64(maxLastUsedIndex)+
765
+				float64(toDelete[j].usageCountIndex)/float64(maxUsageCountIndex)
766
+	})
767
+}
708 768
new file mode 100644
... ...
@@ -0,0 +1,95 @@
0
+package client
1
+
2
+import (
3
+	"context"
4
+
5
+	"github.com/moby/buildkit/client/buildid"
6
+	gateway "github.com/moby/buildkit/frontend/gateway/client"
7
+	"github.com/moby/buildkit/frontend/gateway/grpcclient"
8
+	gatewayapi "github.com/moby/buildkit/frontend/gateway/pb"
9
+	"github.com/moby/buildkit/session"
10
+	"github.com/moby/buildkit/util/apicaps"
11
+	"github.com/pkg/errors"
12
+	"google.golang.org/grpc"
13
+)
14
+
15
+func (c *Client) Build(ctx context.Context, opt SolveOpt, product string, buildFunc gateway.BuildFunc, statusChan chan *SolveStatus) (*SolveResponse, error) {
16
+	defer func() {
17
+		if statusChan != nil {
18
+			close(statusChan)
19
+		}
20
+	}()
21
+
22
+	if opt.Frontend != "" {
23
+		return nil, errors.New("invalid SolveOpt, Build interface cannot use Frontend")
24
+	}
25
+
26
+	if product == "" {
27
+		product = apicaps.ExportedProduct
28
+	}
29
+
30
+	feOpts := opt.FrontendAttrs
31
+	opt.FrontendAttrs = nil
32
+
33
+	workers, err := c.ListWorkers(ctx)
34
+	if err != nil {
35
+		return nil, errors.Wrap(err, "listing workers for Build")
36
+	}
37
+	var gworkers []gateway.WorkerInfo
38
+	for _, w := range workers {
39
+		gworkers = append(gworkers, gateway.WorkerInfo{
40
+			ID:        w.ID,
41
+			Labels:    w.Labels,
42
+			Platforms: w.Platforms,
43
+		})
44
+	}
45
+
46
+	cb := func(ref string, s *session.Session) error {
47
+		g, err := grpcclient.New(ctx, feOpts, s.ID(), product, c.gatewayClientForBuild(ref), gworkers)
48
+		if err != nil {
49
+			return err
50
+		}
51
+
52
+		if err := g.Run(ctx, buildFunc); err != nil {
53
+			return errors.Wrap(err, "failed to run Build function")
54
+		}
55
+		return nil
56
+	}
57
+
58
+	return c.solve(ctx, nil, cb, opt, statusChan)
59
+}
60
+
61
+func (c *Client) gatewayClientForBuild(buildid string) gatewayapi.LLBBridgeClient {
62
+	g := gatewayapi.NewLLBBridgeClient(c.conn)
63
+	return &gatewayClientForBuild{g, buildid}
64
+}
65
+
66
+type gatewayClientForBuild struct {
67
+	gateway gatewayapi.LLBBridgeClient
68
+	buildID string
69
+}
70
+
71
+func (g *gatewayClientForBuild) ResolveImageConfig(ctx context.Context, in *gatewayapi.ResolveImageConfigRequest, opts ...grpc.CallOption) (*gatewayapi.ResolveImageConfigResponse, error) {
72
+	ctx = buildid.AppendToOutgoingContext(ctx, g.buildID)
73
+	return g.gateway.ResolveImageConfig(ctx, in, opts...)
74
+}
75
+
76
+func (g *gatewayClientForBuild) Solve(ctx context.Context, in *gatewayapi.SolveRequest, opts ...grpc.CallOption) (*gatewayapi.SolveResponse, error) {
77
+	ctx = buildid.AppendToOutgoingContext(ctx, g.buildID)
78
+	return g.gateway.Solve(ctx, in, opts...)
79
+}
80
+
81
+func (g *gatewayClientForBuild) ReadFile(ctx context.Context, in *gatewayapi.ReadFileRequest, opts ...grpc.CallOption) (*gatewayapi.ReadFileResponse, error) {
82
+	ctx = buildid.AppendToOutgoingContext(ctx, g.buildID)
83
+	return g.gateway.ReadFile(ctx, in, opts...)
84
+}
85
+
86
+func (g *gatewayClientForBuild) Ping(ctx context.Context, in *gatewayapi.PingRequest, opts ...grpc.CallOption) (*gatewayapi.PongResponse, error) {
87
+	ctx = buildid.AppendToOutgoingContext(ctx, g.buildID)
88
+	return g.gateway.Ping(ctx, in, opts...)
89
+}
90
+
91
+func (g *gatewayClientForBuild) Return(ctx context.Context, in *gatewayapi.ReturnRequest, opts ...grpc.CallOption) (*gatewayapi.ReturnResponse, error) {
92
+	ctx = buildid.AppendToOutgoingContext(ctx, g.buildID)
93
+	return g.gateway.Return(ctx, in, opts...)
94
+}
0 95
new file mode 100644
... ...
@@ -0,0 +1,29 @@
0
+package buildid
1
+
2
+import (
3
+	"context"
4
+
5
+	"google.golang.org/grpc/metadata"
6
+)
7
+
8
+var metadataKey = "buildkit-controlapi-buildid"
9
+
10
+func AppendToOutgoingContext(ctx context.Context, id string) context.Context {
11
+	if id != "" {
12
+		return metadata.AppendToOutgoingContext(ctx, metadataKey, id)
13
+	}
14
+	return ctx
15
+}
16
+
17
+func FromIncomingContext(ctx context.Context) string {
18
+	md, ok := metadata.FromIncomingContext(ctx)
19
+	if !ok {
20
+		return ""
21
+	}
22
+
23
+	if ids := md.Get(metadataKey); len(ids) == 1 {
24
+		return ids[0]
25
+	}
26
+
27
+	return ""
28
+}
... ...
@@ -2,6 +2,7 @@ package llb
2 2
 
3 3
 import (
4 4
 	_ "crypto/sha256"
5
+	"net"
5 6
 	"sort"
6 7
 
7 8
 	"github.com/moby/buildkit/solver/pb"
... ...
@@ -10,11 +11,13 @@ import (
10 10
 )
11 11
 
12 12
 type Meta struct {
13
-	Args     []string
14
-	Env      EnvList
15
-	Cwd      string
16
-	User     string
17
-	ProxyEnv *ProxyEnv
13
+	Args       []string
14
+	Env        EnvList
15
+	Cwd        string
16
+	User       string
17
+	ProxyEnv   *ProxyEnv
18
+	ExtraHosts []HostIP
19
+	Network    pb.NetMode
18 20
 }
19 21
 
20 22
 func NewExecOp(root Output, meta Meta, readOnly bool, c Constraints) *ExecOp {
... ...
@@ -127,13 +130,26 @@ func (e *ExecOp) Marshal(c *Constraints) (digest.Digest, []byte, *pb.OpMetadata,
127 127
 		return e.mounts[i].target < e.mounts[j].target
128 128
 	})
129 129
 
130
+	meta := &pb.Meta{
131
+		Args: e.meta.Args,
132
+		Env:  e.meta.Env.ToArray(),
133
+		Cwd:  e.meta.Cwd,
134
+		User: e.meta.User,
135
+	}
136
+	if len(e.meta.ExtraHosts) > 0 {
137
+		hosts := make([]*pb.HostIP, len(e.meta.ExtraHosts))
138
+		for i, h := range e.meta.ExtraHosts {
139
+			hosts[i] = &pb.HostIP{Host: h.Host, IP: h.IP.String()}
140
+		}
141
+		meta.ExtraHosts = hosts
142
+	}
143
+
130 144
 	peo := &pb.ExecOp{
131
-		Meta: &pb.Meta{
132
-			Args: e.meta.Args,
133
-			Env:  e.meta.Env.ToArray(),
134
-			Cwd:  e.meta.Cwd,
135
-			User: e.meta.User,
136
-		},
145
+		Meta:    meta,
146
+		Network: e.meta.Network,
147
+	}
148
+	if e.meta.Network != NetModeSandbox {
149
+		addCap(&e.constraints, pb.CapExecMetaNetwork)
137 150
 	}
138 151
 
139 152
 	if p := e.meta.ProxyEnv; p != nil {
... ...
@@ -346,6 +362,12 @@ func (fn runOptionFunc) SetRunOption(ei *ExecInfo) {
346 346
 	fn(ei)
347 347
 }
348 348
 
349
+func Network(n pb.NetMode) RunOption {
350
+	return runOptionFunc(func(ei *ExecInfo) {
351
+		ei.State = network(n)(ei.State)
352
+	})
353
+}
354
+
349 355
 func Shlex(str string) RunOption {
350 356
 	return Shlexf(str)
351 357
 }
... ...
@@ -386,6 +408,12 @@ func Dirf(str string, v ...interface{}) RunOption {
386 386
 	})
387 387
 }
388 388
 
389
+func AddExtraHost(host string, ip net.IP) RunOption {
390
+	return runOptionFunc(func(ei *ExecInfo) {
391
+		ei.State = ei.State.AddExtraHost(host, ip)
392
+	})
393
+}
394
+
389 395
 func Reset(s State) RunOption {
390 396
 	return runOptionFunc(func(ei *ExecInfo) {
391 397
 		ei.State = ei.State.Reset(s)
... ...
@@ -492,3 +520,9 @@ const (
492 492
 	CacheMountPrivate
493 493
 	CacheMountLocked
494 494
 )
495
+
496
+const (
497
+	NetModeSandbox = pb.NetMode_UNSET
498
+	NetModeHost    = pb.NetMode_HOST
499
+	NetModeNone    = pb.NetMode_NONE
500
+)
... ...
@@ -2,21 +2,25 @@ package llb
2 2
 
3 3
 import (
4 4
 	"fmt"
5
+	"net"
5 6
 	"path"
6 7
 
7 8
 	"github.com/containerd/containerd/platforms"
8 9
 	"github.com/google/shlex"
10
+	"github.com/moby/buildkit/solver/pb"
9 11
 	specs "github.com/opencontainers/image-spec/specs-go/v1"
10 12
 )
11 13
 
12 14
 type contextKeyT string
13 15
 
14 16
 var (
15
-	keyArgs     = contextKeyT("llb.exec.args")
16
-	keyDir      = contextKeyT("llb.exec.dir")
17
-	keyEnv      = contextKeyT("llb.exec.env")
18
-	keyUser     = contextKeyT("llb.exec.user")
19
-	keyPlatform = contextKeyT("llb.platform")
17
+	keyArgs      = contextKeyT("llb.exec.args")
18
+	keyDir       = contextKeyT("llb.exec.dir")
19
+	keyEnv       = contextKeyT("llb.exec.env")
20
+	keyUser      = contextKeyT("llb.exec.user")
21
+	keyExtraHost = contextKeyT("llb.exec.extrahost")
22
+	keyPlatform  = contextKeyT("llb.platform")
23
+	keyNetwork   = contextKeyT("llb.network")
20 24
 )
21 25
 
22 26
 func addEnv(key, value string) StateOption {
... ...
@@ -124,6 +128,40 @@ func getPlatform(s State) *specs.Platform {
124 124
 	return nil
125 125
 }
126 126
 
127
+func extraHost(host string, ip net.IP) StateOption {
128
+	return func(s State) State {
129
+		return s.WithValue(keyExtraHost, append(getExtraHosts(s), HostIP{Host: host, IP: ip}))
130
+	}
131
+}
132
+
133
+func getExtraHosts(s State) []HostIP {
134
+	v := s.Value(keyExtraHost)
135
+	if v != nil {
136
+		return v.([]HostIP)
137
+	}
138
+	return nil
139
+}
140
+
141
+type HostIP struct {
142
+	Host string
143
+	IP   net.IP
144
+}
145
+
146
+func network(v pb.NetMode) StateOption {
147
+	return func(s State) State {
148
+		return s.WithValue(keyNetwork, v)
149
+	}
150
+}
151
+
152
+func getNetwork(s State) pb.NetMode {
153
+	v := s.Value(keyNetwork)
154
+	if v != nil {
155
+		n := v.(pb.NetMode)
156
+		return n
157
+	}
158
+	return NetModeSandbox
159
+}
160
+
127 161
 type EnvList []KeyValue
128 162
 
129 163
 type KeyValue struct {
... ...
@@ -3,6 +3,7 @@ package llb
3 3
 import (
4 4
 	"context"
5 5
 	"fmt"
6
+	"net"
6 7
 
7 8
 	"github.com/containerd/containerd/platforms"
8 9
 	"github.com/moby/buildkit/identity"
... ...
@@ -181,11 +182,13 @@ func (s State) Run(ro ...RunOption) ExecState {
181 181
 		o.SetRunOption(ei)
182 182
 	}
183 183
 	meta := Meta{
184
-		Args:     getArgs(ei.State),
185
-		Cwd:      getDir(ei.State),
186
-		Env:      getEnv(ei.State),
187
-		User:     getUser(ei.State),
188
-		ProxyEnv: ei.ProxyEnv,
184
+		Args:       getArgs(ei.State),
185
+		Cwd:        getDir(ei.State),
186
+		Env:        getEnv(ei.State),
187
+		User:       getUser(ei.State),
188
+		ProxyEnv:   ei.ProxyEnv,
189
+		ExtraHosts: getExtraHosts(ei.State),
190
+		Network:    getNetwork(ei.State),
189 191
 	}
190 192
 
191 193
 	exec := NewExecOp(s.Output(), meta, ei.ReadonlyRootFS, ei.Constraints)
... ...
@@ -247,6 +250,14 @@ func (s State) GetPlatform() *specs.Platform {
247 247
 	return getPlatform(s)
248 248
 }
249 249
 
250
+func (s State) Network(n pb.NetMode) State {
251
+	return network(n)(s)
252
+}
253
+
254
+func (s State) GetNetwork() pb.NetMode {
255
+	return getNetwork(s)
256
+}
257
+
250 258
 func (s State) With(so ...StateOption) State {
251 259
 	for _, o := range so {
252 260
 		s = o(s)
... ...
@@ -254,6 +265,10 @@ func (s State) With(so ...StateOption) State {
254 254
 	return s
255 255
 }
256 256
 
257
+func (s State) AddExtraHost(host string, ip net.IP) State {
258
+	return extraHost(host, ip)(s)
259
+}
260
+
257 261
 type output struct {
258 262
 	vertex   Vertex
259 263
 	getIndex func() (pb.OutputIndex, error)
... ...
@@ -3,6 +3,7 @@ package client
3 3
 import (
4 4
 	"context"
5 5
 	"io"
6
+	"time"
6 7
 
7 8
 	controlapi "github.com/moby/buildkit/api/services/control"
8 9
 	"github.com/pkg/errors"
... ...
@@ -14,7 +15,11 @@ func (c *Client) Prune(ctx context.Context, ch chan UsageInfo, opts ...PruneOpti
14 14
 		o.SetPruneOption(info)
15 15
 	}
16 16
 
17
-	req := &controlapi.PruneRequest{Filter: info.Filter}
17
+	req := &controlapi.PruneRequest{
18
+		Filter:       info.Filter,
19
+		KeepDuration: int64(info.KeepDuration),
20
+		KeepBytes:    int64(info.KeepBytes),
21
+	}
18 22
 	if info.All {
19 23
 		req.All = true
20 24
 	}
... ...
@@ -54,8 +59,10 @@ type PruneOption interface {
54 54
 }
55 55
 
56 56
 type PruneInfo struct {
57
-	Filter []string
58
-	All    bool
57
+	Filter       []string
58
+	All          bool
59
+	KeepDuration time.Duration
60
+	KeepBytes    int64
59 61
 }
60 62
 
61 63
 type pruneOptionFunc func(*PruneInfo)
... ...
@@ -67,3 +74,10 @@ func (f pruneOptionFunc) SetPruneOption(pi *PruneInfo) {
67 67
 var PruneAll = pruneOptionFunc(func(pi *PruneInfo) {
68 68
 	pi.All = true
69 69
 })
70
+
71
+func WithKeepOpt(duration time.Duration, bytes int64) PruneOption {
72
+	return pruneOptionFunc(func(pi *PruneInfo) {
73
+		pi.KeepDuration = duration
74
+		pi.KeepBytes = bytes
75
+	})
76
+}
... ...
@@ -15,6 +15,7 @@ import (
15 15
 	"github.com/moby/buildkit/session/filesync"
16 16
 	"github.com/moby/buildkit/session/grpchijack"
17 17
 	"github.com/moby/buildkit/solver/pb"
18
+	"github.com/moby/buildkit/util/entitlements"
18 19
 	opentracing "github.com/opentracing/opentracing-go"
19 20
 	"github.com/pkg/errors"
20 21
 	"github.com/sirupsen/logrus"
... ...
@@ -22,18 +23,19 @@ import (
22 22
 )
23 23
 
24 24
 type SolveOpt struct {
25
-	Exporter          string
26
-	ExporterAttrs     map[string]string
27
-	ExporterOutput    io.WriteCloser // for ExporterOCI and ExporterDocker
28
-	ExporterOutputDir string         // for ExporterLocal
29
-	LocalDirs         map[string]string
30
-	SharedKey         string
31
-	Frontend          string
32
-	FrontendAttrs     map[string]string
33
-	ExportCache       string
34
-	ExportCacheAttrs  map[string]string
35
-	ImportCache       []string
36
-	Session           []session.Attachable
25
+	Exporter            string
26
+	ExporterAttrs       map[string]string
27
+	ExporterOutput      io.WriteCloser // for ExporterOCI and ExporterDocker
28
+	ExporterOutputDir   string         // for ExporterLocal
29
+	LocalDirs           map[string]string
30
+	SharedKey           string
31
+	Frontend            string
32
+	FrontendAttrs       map[string]string
33
+	ExportCache         string
34
+	ExportCacheAttrs    map[string]string
35
+	ImportCache         []string
36
+	Session             []session.Attachable
37
+	AllowedEntitlements []entitlements.Entitlement
37 38
 }
38 39
 
39 40
 // Solve calls Solve on the controller.
... ...
@@ -52,6 +54,16 @@ func (c *Client) Solve(ctx context.Context, def *llb.Definition, opt SolveOpt, s
52 52
 		return nil, errors.Errorf("invalid definition for frontend %s", opt.Frontend)
53 53
 	}
54 54
 
55
+	return c.solve(ctx, def, nil, opt, statusChan)
56
+}
57
+
58
+type runGatewayCB func(ref string, s *session.Session) error
59
+
60
+func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runGatewayCB, opt SolveOpt, statusChan chan *SolveStatus) (*SolveResponse, error) {
61
+	if def != nil && runGateway != nil {
62
+		return nil, errors.New("invalid with def and cb")
63
+	}
64
+
55 65
 	syncedDirs, err := prepareSyncedDirs(def, opt.LocalDirs)
56 66
 	if err != nil {
57 67
 		return nil, err
... ...
@@ -110,8 +122,12 @@ func (c *Client) Solve(ctx context.Context, def *llb.Definition, opt SolveOpt, s
110 110
 		return s.Run(statusContext, grpchijack.Dialer(c.controlClient()))
111 111
 	})
112 112
 
113
+	solveCtx, cancelSolve := context.WithCancel(ctx)
113 114
 	var res *SolveResponse
114 115
 	eg.Go(func() error {
116
+		ctx := solveCtx
117
+		defer cancelSolve()
118
+
115 119
 		defer func() { // make sure the Status ends cleanly on build errors
116 120
 			go func() {
117 121
 				<-time.After(3 * time.Second)
... ...
@@ -137,6 +153,7 @@ func (c *Client) Solve(ctx context.Context, def *llb.Definition, opt SolveOpt, s
137 137
 				ImportRefs:  opt.ImportCache,
138 138
 				ExportAttrs: opt.ExportCacheAttrs,
139 139
 			},
140
+			Entitlements: opt.AllowedEntitlements,
140 141
 		})
141 142
 		if err != nil {
142 143
 			return errors.Wrap(err, "failed to solve")
... ...
@@ -147,6 +164,28 @@ func (c *Client) Solve(ctx context.Context, def *llb.Definition, opt SolveOpt, s
147 147
 		return nil
148 148
 	})
149 149
 
150
+	if runGateway != nil {
151
+		eg.Go(func() error {
152
+			err := runGateway(ref, s)
153
+			if err == nil {
154
+				return nil
155
+			}
156
+
157
+			// If the callback failed then the main
158
+			// `Solve` (called above) should error as
159
+			// well. However as a fallback we wait up to
160
+			// 5s for that to happen before failing this
161
+			// goroutine.
162
+			select {
163
+			case <-solveCtx.Done():
164
+			case <-time.After(5 * time.Second):
165
+				cancelSolve()
166
+			}
167
+
168
+			return err
169
+		})
170
+	}
171
+
150 172
 	eg.Go(func() error {
151 173
 		stream, err := c.controlClient().Status(statusContext, &controlapi.StatusRequest{
152 174
 			Ref: ref,
... ...
@@ -2,12 +2,14 @@ package control
2 2
 
3 3
 import (
4 4
 	"context"
5
+	"time"
5 6
 
6 7
 	"github.com/docker/distribution/reference"
7 8
 	controlapi "github.com/moby/buildkit/api/services/control"
8 9
 	apitypes "github.com/moby/buildkit/api/types"
9 10
 	"github.com/moby/buildkit/cache/remotecache"
10 11
 	"github.com/moby/buildkit/client"
12
+	controlgateway "github.com/moby/buildkit/control/gateway"
11 13
 	"github.com/moby/buildkit/exporter"
12 14
 	"github.com/moby/buildkit/frontend"
13 15
 	"github.com/moby/buildkit/session"
... ...
@@ -34,29 +36,34 @@ type Opt struct {
34 34
 }
35 35
 
36 36
 type Controller struct { // TODO: ControlService
37
-	opt    Opt
38
-	solver *llbsolver.Solver
39
-	cache  solver.CacheManager
37
+	opt              Opt
38
+	solver           *llbsolver.Solver
39
+	cache            solver.CacheManager
40
+	gatewayForwarder *controlgateway.GatewayForwarder
40 41
 }
41 42
 
42 43
 func NewController(opt Opt) (*Controller, error) {
43 44
 	cache := solver.NewCacheManager("local", opt.CacheKeyStorage, worker.NewCacheResultStorage(opt.WorkerController))
44 45
 
45
-	solver, err := llbsolver.New(opt.WorkerController, opt.Frontends, cache, opt.ResolveCacheImporterFunc)
46
+	gatewayForwarder := controlgateway.NewGatewayForwarder()
47
+
48
+	solver, err := llbsolver.New(opt.WorkerController, opt.Frontends, cache, opt.ResolveCacheImporterFunc, gatewayForwarder)
46 49
 	if err != nil {
47 50
 		return nil, errors.Wrap(err, "failed to create solver")
48 51
 	}
49 52
 
50 53
 	c := &Controller{
51
-		opt:    opt,
52
-		solver: solver,
53
-		cache:  cache,
54
+		opt:              opt,
55
+		solver:           solver,
56
+		cache:            cache,
57
+		gatewayForwarder: gatewayForwarder,
54 58
 	}
55 59
 	return c, nil
56 60
 }
57 61
 
58 62
 func (c *Controller) Register(server *grpc.Server) error {
59 63
 	controlapi.RegisterControlServer(server, c)
64
+	c.gatewayForwarder.Register(server)
60 65
 	return nil
61 66
 }
62 67
 
... ...
@@ -120,8 +127,10 @@ func (c *Controller) Prune(req *controlapi.PruneRequest, stream controlapi.Contr
120 120
 		func(w worker.Worker) {
121 121
 			eg.Go(func() error {
122 122
 				return w.Prune(ctx, ch, client.PruneInfo{
123
-					Filter: req.Filter,
124
-					All:    req.All,
123
+					Filter:       req.Filter,
124
+					All:          req.All,
125
+					KeepDuration: time.Duration(req.KeepDuration),
126
+					KeepBytes:    req.KeepBytes,
125 127
 				})
126 128
 			})
127 129
 		}(w)
... ...
@@ -213,7 +222,7 @@ func (c *Controller) Solve(ctx context.Context, req *controlapi.SolveRequest) (*
213 213
 		Exporter:        expi,
214 214
 		CacheExporter:   cacheExporter,
215 215
 		CacheExportMode: parseCacheExporterOpt(req.Cache.ExportAttrs),
216
-	})
216
+	}, req.Entitlements)
217 217
 	if err != nil {
218 218
 		return nil, err
219 219
 	}
220 220
new file mode 100644
... ...
@@ -0,0 +1,127 @@
0
+package gateway
1
+
2
+import (
3
+	"context"
4
+	"sync"
5
+	"time"
6
+
7
+	"github.com/moby/buildkit/client/buildid"
8
+	"github.com/moby/buildkit/frontend/gateway"
9
+	gwapi "github.com/moby/buildkit/frontend/gateway/pb"
10
+	"github.com/pkg/errors"
11
+	"google.golang.org/grpc"
12
+)
13
+
14
+type GatewayForwarder struct {
15
+	mu         sync.RWMutex
16
+	updateCond *sync.Cond
17
+	builds     map[string]gateway.LLBBridgeForwarder
18
+}
19
+
20
+func NewGatewayForwarder() *GatewayForwarder {
21
+	gwf := &GatewayForwarder{
22
+		builds: map[string]gateway.LLBBridgeForwarder{},
23
+	}
24
+	gwf.updateCond = sync.NewCond(gwf.mu.RLocker())
25
+	return gwf
26
+}
27
+
28
+func (gwf *GatewayForwarder) Register(server *grpc.Server) {
29
+	gwapi.RegisterLLBBridgeServer(server, gwf)
30
+}
31
+
32
+func (gwf *GatewayForwarder) RegisterBuild(ctx context.Context, id string, bridge gateway.LLBBridgeForwarder) error {
33
+	gwf.mu.Lock()
34
+	defer gwf.mu.Unlock()
35
+
36
+	if _, ok := gwf.builds[id]; ok {
37
+		return errors.Errorf("build ID %s exists", id)
38
+	}
39
+
40
+	gwf.builds[id] = bridge
41
+	gwf.updateCond.Broadcast()
42
+
43
+	return nil
44
+}
45
+
46
+func (gwf *GatewayForwarder) UnregisterBuild(ctx context.Context, id string) {
47
+	gwf.mu.Lock()
48
+	defer gwf.mu.Unlock()
49
+
50
+	delete(gwf.builds, id)
51
+	gwf.updateCond.Broadcast()
52
+}
53
+
54
+func (gwf *GatewayForwarder) lookupForwarder(ctx context.Context) (gateway.LLBBridgeForwarder, error) {
55
+	bid := buildid.FromIncomingContext(ctx)
56
+	if bid == "" {
57
+		return nil, errors.New("no buildid found in context")
58
+	}
59
+
60
+	ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
61
+	defer cancel()
62
+
63
+	go func() {
64
+		<-ctx.Done()
65
+		gwf.updateCond.Broadcast()
66
+	}()
67
+
68
+	gwf.mu.RLock()
69
+	defer gwf.mu.RUnlock()
70
+	for {
71
+		select {
72
+		case <-ctx.Done():
73
+			return nil, errors.Errorf("no such job %s", bid)
74
+		default:
75
+		}
76
+		fwd, ok := gwf.builds[bid]
77
+		if !ok {
78
+			gwf.updateCond.Wait()
79
+			continue
80
+		}
81
+		return fwd, nil
82
+	}
83
+}
84
+
85
+func (gwf *GatewayForwarder) ResolveImageConfig(ctx context.Context, req *gwapi.ResolveImageConfigRequest) (*gwapi.ResolveImageConfigResponse, error) {
86
+	fwd, err := gwf.lookupForwarder(ctx)
87
+	if err != nil {
88
+		return nil, errors.Wrap(err, "forwarding ResolveImageConfig")
89
+	}
90
+
91
+	return fwd.ResolveImageConfig(ctx, req)
92
+}
93
+
94
+func (gwf *GatewayForwarder) Solve(ctx context.Context, req *gwapi.SolveRequest) (*gwapi.SolveResponse, error) {
95
+	fwd, err := gwf.lookupForwarder(ctx)
96
+	if err != nil {
97
+		return nil, errors.Wrap(err, "forwarding Solve")
98
+	}
99
+
100
+	return fwd.Solve(ctx, req)
101
+}
102
+
103
+func (gwf *GatewayForwarder) ReadFile(ctx context.Context, req *gwapi.ReadFileRequest) (*gwapi.ReadFileResponse, error) {
104
+	fwd, err := gwf.lookupForwarder(ctx)
105
+	if err != nil {
106
+		return nil, errors.Wrap(err, "forwarding ReadFile")
107
+	}
108
+	return fwd.ReadFile(ctx, req)
109
+}
110
+
111
+func (gwf *GatewayForwarder) Ping(ctx context.Context, req *gwapi.PingRequest) (*gwapi.PongResponse, error) {
112
+	fwd, err := gwf.lookupForwarder(ctx)
113
+	if err != nil {
114
+		return nil, errors.Wrap(err, "forwarding Ping")
115
+	}
116
+	return fwd.Ping(ctx, req)
117
+}
118
+
119
+func (gwf *GatewayForwarder) Return(ctx context.Context, req *gwapi.ReturnRequest) (*gwapi.ReturnResponse, error) {
120
+	fwd, err := gwf.lookupForwarder(ctx)
121
+	if err != nil {
122
+		return nil, errors.Wrap(err, "forwarding Return")
123
+	}
124
+	res, err := fwd.Return(ctx, req)
125
+	return res, err
126
+}
... ...
@@ -3,8 +3,10 @@ package executor
3 3
 import (
4 4
 	"context"
5 5
 	"io"
6
+	"net"
6 7
 
7 8
 	"github.com/moby/buildkit/cache"
9
+	"github.com/moby/buildkit/solver/pb"
8 10
 )
9 11
 
10 12
 type Meta struct {
... ...
@@ -14,7 +16,8 @@ type Meta struct {
14 14
 	Cwd            string
15 15
 	Tty            bool
16 16
 	ReadonlyRootFS bool
17
-	// DisableNetworking bool
17
+	ExtraHosts     []HostIP
18
+	NetMode        pb.NetMode
18 19
 }
19 20
 
20 21
 type Mount struct {
... ...
@@ -28,3 +31,8 @@ type Executor interface {
28 28
 	// TODO: add stdout/err
29 29
 	Exec(ctx context.Context, meta Meta, rootfs cache.Mountable, mounts []Mount, stdin io.ReadCloser, stdout, stderr io.WriteCloser) error
30 30
 }
31
+
32
+type HostIP struct {
33
+	Host string
34
+	IP   net.IP
35
+}
... ...
@@ -1,10 +1,15 @@
1 1
 package oci
2 2
 
3 3
 import (
4
+	"bytes"
4 5
 	"context"
6
+	"fmt"
5 7
 	"io/ioutil"
6 8
 	"os"
7 9
 	"path/filepath"
10
+
11
+	"github.com/moby/buildkit/executor"
12
+	"github.com/moby/buildkit/identity"
8 13
 )
9 14
 
10 15
 const hostsContent = `
... ...
@@ -12,27 +17,53 @@ const hostsContent = `
12 12
 ::1	localhost ip6-localhost ip6-loopback
13 13
 `
14 14
 
15
-func GetHostsFile(ctx context.Context, stateDir string) (string, error) {
16
-	p := filepath.Join(stateDir, "hosts")
17
-	_, err := g.Do(ctx, stateDir, func(ctx context.Context) (interface{}, error) {
18
-		_, err := os.Stat(p)
19
-		if err == nil {
20
-			return "", nil
21
-		}
22
-		if !os.IsNotExist(err) {
23
-			return "", err
24
-		}
25
-		if err := ioutil.WriteFile(p+".tmp", []byte(hostsContent), 0644); err != nil {
26
-			return "", err
15
+func GetHostsFile(ctx context.Context, stateDir string, extraHosts []executor.HostIP) (string, func(), error) {
16
+	if len(extraHosts) == 0 {
17
+		_, err := g.Do(ctx, stateDir, func(ctx context.Context) (interface{}, error) {
18
+			_, _, err := makeHostsFile(stateDir, nil)
19
+			return nil, err
20
+		})
21
+		if err != nil {
22
+			return "", nil, err
27 23
 		}
24
+		return filepath.Join(stateDir, "hosts"), func() {}, nil
25
+	}
26
+	return makeHostsFile(stateDir, extraHosts)
27
+}
28
+
29
+func makeHostsFile(stateDir string, extraHosts []executor.HostIP) (string, func(), error) {
30
+	p := filepath.Join(stateDir, "hosts")
31
+	if len(extraHosts) != 0 {
32
+		p += "." + identity.NewID()
33
+	}
34
+	_, err := os.Stat(p)
35
+	if err == nil {
36
+		return "", func() {}, nil
37
+	}
38
+	if !os.IsNotExist(err) {
39
+		return "", nil, err
40
+	}
41
+
42
+	b := &bytes.Buffer{}
43
+
44
+	if _, err := b.Write([]byte(hostsContent)); err != nil {
45
+		return "", nil, err
46
+	}
28 47
 
29
-		if err := os.Rename(p+".tmp", p); err != nil {
30
-			return "", err
48
+	for _, h := range extraHosts {
49
+		if _, err := b.Write([]byte(fmt.Sprintf("%s\t%s\n", h.IP.String(), h.Host))); err != nil {
50
+			return "", nil, err
31 51
 		}
32
-		return "", nil
33
-	})
34
-	if err != nil {
35
-		return "", err
36 52
 	}
37
-	return p, nil
53
+
54
+	if err := ioutil.WriteFile(p+".tmp", b.Bytes(), 0644); err != nil {
55
+		return "", nil, err
56
+	}
57
+
58
+	if err := os.Rename(p+".tmp", p); err != nil {
59
+		return "", nil, err
60
+	}
61
+	return p, func() {
62
+		os.RemoveAll(p)
63
+	}, nil
38 64
 }
... ...
@@ -21,7 +21,7 @@ import (
21 21
 // Ideally we don't have to import whole containerd just for the default spec
22 22
 
23 23
 // GenerateSpec generates spec using containerd functionality.
24
-func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mount, id, resolvConf, hostsFile string, opts ...oci.SpecOpts) (*specs.Spec, func(), error) {
24
+func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mount, id, resolvConf, hostsFile string, hostNetwork bool, opts ...oci.SpecOpts) (*specs.Spec, func(), error) {
25 25
 	c := &containers.Container{
26 26
 		ID: id,
27 27
 	}
... ...
@@ -30,9 +30,9 @@ func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mou
30 30
 		ctx = namespaces.WithNamespace(ctx, "buildkit")
31 31
 	}
32 32
 
33
-	opts = append(opts,
34
-		oci.WithHostNamespace(specs.NetworkNamespace),
35
-	)
33
+	if hostNetwork {
34
+		opts = append(opts, oci.WithHostNamespace(specs.NetworkNamespace))
35
+	}
36 36
 
37 37
 	// Note that containerd.GenerateSpec is namespaced so as to make
38 38
 	// specs.Linux.CgroupsPath namespaced
... ...
@@ -10,6 +10,7 @@ import (
10 10
 	"path/filepath"
11 11
 	"strconv"
12 12
 	"strings"
13
+	"sync"
13 14
 	"syscall"
14 15
 
15 16
 	"github.com/containerd/containerd/contrib/seccomp"
... ...
@@ -21,9 +22,12 @@ import (
21 21
 	"github.com/moby/buildkit/executor"
22 22
 	"github.com/moby/buildkit/executor/oci"
23 23
 	"github.com/moby/buildkit/identity"
24
+	"github.com/moby/buildkit/solver/pb"
25
+	"github.com/moby/buildkit/util/network"
24 26
 	rootlessspecconv "github.com/moby/buildkit/util/rootless/specconv"
25 27
 	"github.com/moby/buildkit/util/system"
26
-	"github.com/opencontainers/runtime-spec/specs-go"
28
+	runcsystem "github.com/opencontainers/runc/libcontainer/system"
29
+	specs "github.com/opencontainers/runtime-spec/specs-go"
27 30
 	"github.com/pkg/errors"
28 31
 	"github.com/sirupsen/logrus"
29 32
 )
... ...
@@ -39,13 +43,14 @@ type Opt struct {
39 39
 var defaultCommandCandidates = []string{"buildkit-runc", "runc"}
40 40
 
41 41
 type runcExecutor struct {
42
-	runc     *runc.Runc
43
-	root     string
44
-	cmd      string
45
-	rootless bool
42
+	runc            *runc.Runc
43
+	root            string
44
+	cmd             string
45
+	rootless        bool
46
+	networkProvider network.Provider
46 47
 }
47 48
 
48
-func New(opt Opt) (executor.Executor, error) {
49
+func New(opt Opt, networkProvider network.Provider) (executor.Executor, error) {
49 50
 	cmds := opt.CommandCandidates
50 51
 	if cmds == nil {
51 52
 		cmds = defaultCommandCandidates
... ...
@@ -65,6 +70,10 @@ func New(opt Opt) (executor.Executor, error) {
65 65
 
66 66
 	root := opt.Root
67 67
 
68
+	if err := setSubReaper(); err != nil {
69
+		return nil, err
70
+	}
71
+
68 72
 	if err := os.MkdirAll(root, 0700); err != nil {
69 73
 		return nil, errors.Wrapf(err, "failed to create %s", root)
70 74
 	}
... ...
@@ -89,24 +98,49 @@ func New(opt Opt) (executor.Executor, error) {
89 89
 	}
90 90
 
91 91
 	w := &runcExecutor{
92
-		runc:     runtime,
93
-		root:     root,
94
-		rootless: opt.Rootless,
92
+		runc:            runtime,
93
+		root:            root,
94
+		rootless:        opt.Rootless,
95
+		networkProvider: networkProvider,
95 96
 	}
96 97
 	return w, nil
97 98
 }
98 99
 
99 100
 func (w *runcExecutor) Exec(ctx context.Context, meta executor.Meta, root cache.Mountable, mounts []executor.Mount, stdin io.ReadCloser, stdout, stderr io.WriteCloser) error {
101
+	var iface network.Interface
102
+	// FIXME: still uses host if no provider configured
103
+	if meta.NetMode == pb.NetMode_UNSET {
104
+		if w.networkProvider != nil {
105
+			var err error
106
+			iface, err = w.networkProvider.NewInterface()
107
+			if err != nil || iface == nil {
108
+				meta.NetMode = pb.NetMode_HOST
109
+			}
110
+		} else {
111
+			meta.NetMode = pb.NetMode_HOST
112
+		}
113
+	}
114
+	if meta.NetMode == pb.NetMode_HOST {
115
+		logrus.Info("enabling HostNetworking")
116
+	}
117
+	defer func() {
118
+		if iface != nil {
119
+			w.networkProvider.Release(iface)
120
+		}
121
+	}()
100 122
 
101 123
 	resolvConf, err := oci.GetResolvConf(ctx, w.root)
102 124
 	if err != nil {
103 125
 		return err
104 126
 	}
105 127
 
106
-	hostsFile, err := oci.GetHostsFile(ctx, w.root)
128
+	hostsFile, clean, err := oci.GetHostsFile(ctx, w.root, meta.ExtraHosts)
107 129
 	if err != nil {
108 130
 		return err
109 131
 	}
132
+	if clean != nil {
133
+		defer clean()
134
+	}
110 135
 
111 136
 	mountable, err := root.Mount(ctx, false)
112 137
 	if err != nil {
... ...
@@ -145,6 +179,7 @@ func (w *runcExecutor) Exec(ctx context.Context, meta executor.Meta, root cache.
145 145
 		return err
146 146
 	}
147 147
 	defer f.Close()
148
+
148 149
 	opts := []containerdoci.SpecOpts{oci.WithUIDGID(uid, gid, sgids)}
149 150
 	if system.SeccompSupported() {
150 151
 		opts = append(opts, seccomp.WithDefaultProfile())
... ...
@@ -152,7 +187,7 @@ func (w *runcExecutor) Exec(ctx context.Context, meta executor.Meta, root cache.
152 152
 	if meta.ReadonlyRootFS {
153 153
 		opts = append(opts, containerdoci.WithRootFSReadonly())
154 154
 	}
155
-	spec, cleanup, err := oci.GenerateSpec(ctx, meta, mounts, id, resolvConf, hostsFile, opts...)
155
+	spec, cleanup, err := oci.GenerateSpec(ctx, meta, mounts, id, resolvConf, hostsFile, meta.NetMode == pb.NetMode_HOST, opts...)
156 156
 	if err != nil {
157 157
 		return err
158 158
 	}
... ...
@@ -184,32 +219,140 @@ func (w *runcExecutor) Exec(ctx context.Context, meta executor.Meta, root cache.
184 184
 		return err
185 185
 	}
186 186
 
187
-	logrus.Debugf("> running %s %v", id, meta.Args)
187
+	forwardIO, err := newForwardIO(stdin, stdout, stderr)
188
+	if err != nil {
189
+		return errors.Wrap(err, "creating new forwarding IO")
190
+	}
191
+	defer forwardIO.Close()
188 192
 
189
-	status, err := w.runc.Run(ctx, id, bundle, &runc.CreateOpts{
190
-		IO: &forwardIO{stdin: stdin, stdout: stdout, stderr: stderr},
193
+	pidFilePath := filepath.Join(w.root, "runc_pid_"+identity.NewID())
194
+	defer os.RemoveAll(pidFilePath)
195
+
196
+	logrus.Debugf("> creating %s %v", id, meta.Args)
197
+	err = w.runc.Create(ctx, id, bundle, &runc.CreateOpts{
198
+		PidFile: pidFilePath,
199
+		IO:      forwardIO,
191 200
 	})
192
-	logrus.Debugf("< completed %s %v %v", id, status, err)
193
-	if status != 0 {
201
+	if err != nil {
202
+		return err
203
+	}
204
+	forwardIO.release()
205
+
206
+	defer func() {
207
+		go func() {
208
+			if err := w.runc.Delete(context.TODO(), id, &runc.DeleteOpts{}); err != nil {
209
+				logrus.Errorf("failed to delete %s: %+v", id, err)
210
+			}
211
+		}()
212
+	}()
213
+
214
+	dt, err := ioutil.ReadFile(pidFilePath)
215
+	if err != nil {
216
+		return err
217
+	}
218
+	pid, err := strconv.Atoi(string(dt))
219
+	if err != nil {
220
+		return err
221
+	}
222
+
223
+	done := make(chan struct{})
224
+	defer close(done)
225
+
226
+	go func() {
194 227
 		select {
228
+		case <-done:
195 229
 		case <-ctx.Done():
196
-			// runc can't report context.Cancelled directly
197
-			return errors.Wrapf(ctx.Err(), "exit code %d", status)
198
-		default:
230
+			syscall.Kill(-pid, syscall.SIGKILL)
199 231
 		}
200
-		return errors.Errorf("exit code %d", status)
232
+	}()
233
+
234
+	if iface != nil {
235
+		if err := iface.Set(pid); err != nil {
236
+			return errors.Wrap(err, "could not set the network")
237
+		}
238
+		defer func() {
239
+			iface.Remove(pid)
240
+		}()
201 241
 	}
202 242
 
203
-	return err
243
+	err = w.runc.Start(ctx, id)
244
+	if err != nil {
245
+		return err
246
+	}
247
+
248
+	p, err := os.FindProcess(pid)
249
+	if err != nil {
250
+		return err
251
+	}
252
+
253
+	status := 0
254
+	ps, err := p.Wait()
255
+	if err != nil {
256
+		status = 255
257
+	}
258
+
259
+	if ws, ok := ps.Sys().(syscall.WaitStatus); ok {
260
+		status = ws.ExitStatus()
261
+	}
262
+	if status != 0 {
263
+		return errors.Errorf("exit code: %d", status)
264
+	}
265
+
266
+	return nil
204 267
 }
205 268
 
206 269
 type forwardIO struct {
207
-	stdin          io.ReadCloser
208
-	stdout, stderr io.WriteCloser
270
+	stdin, stdout, stderr *os.File
271
+	toRelease             []io.Closer
272
+	toClose               []io.Closer
273
+}
274
+
275
+func newForwardIO(stdin io.ReadCloser, stdout, stderr io.WriteCloser) (f *forwardIO, err error) {
276
+	fio := &forwardIO{}
277
+	defer func() {
278
+		if err != nil {
279
+			fio.Close()
280
+		}
281
+	}()
282
+	if stdin != nil {
283
+		fio.stdin, err = fio.readCloserToFile(stdin)
284
+		if err != nil {
285
+			return nil, err
286
+		}
287
+	}
288
+	if stdout != nil {
289
+		fio.stdout, err = fio.writeCloserToFile(stdout)
290
+		if err != nil {
291
+			return nil, err
292
+		}
293
+	}
294
+	if stderr != nil {
295
+		fio.stderr, err = fio.writeCloserToFile(stderr)
296
+		if err != nil {
297
+			return nil, err
298
+		}
299
+	}
300
+	return fio, nil
209 301
 }
210 302
 
211 303
 func (s *forwardIO) Close() error {
212
-	return nil
304
+	s.release()
305
+	var err error
306
+	for _, cl := range s.toClose {
307
+		if err1 := cl.Close(); err == nil {
308
+			err = err1
309
+		}
310
+	}
311
+	s.toClose = nil
312
+	return err
313
+}
314
+
315
+// release releases active FDs if the process doesn't need them any more
316
+func (s *forwardIO) release() {
317
+	for _, cl := range s.toRelease {
318
+		cl.Close()
319
+	}
320
+	s.toRelease = nil
213 321
 }
214 322
 
215 323
 func (s *forwardIO) Set(cmd *exec.Cmd) {
... ...
@@ -218,6 +361,62 @@ func (s *forwardIO) Set(cmd *exec.Cmd) {
218 218
 	cmd.Stderr = s.stderr
219 219
 }
220 220
 
221
+func (s *forwardIO) readCloserToFile(rc io.ReadCloser) (*os.File, error) {
222
+	if f, ok := rc.(*os.File); ok {
223
+		return f, nil
224
+	}
225
+	pr, pw, err := os.Pipe()
226
+	if err != nil {
227
+		return nil, err
228
+	}
229
+	s.toClose = append(s.toClose, pw)
230
+	s.toRelease = append(s.toRelease, pr)
231
+	go func() {
232
+		_, err := io.Copy(pw, rc)
233
+		if err1 := pw.Close(); err == nil {
234
+			err = err1
235
+		}
236
+		_ = err
237
+	}()
238
+	return pr, nil
239
+}
240
+
241
+func (s *forwardIO) writeCloserToFile(wc io.WriteCloser) (*os.File, error) {
242
+	if f, ok := wc.(*os.File); ok {
243
+		return f, nil
244
+	}
245
+	pr, pw, err := os.Pipe()
246
+	if err != nil {
247
+		return nil, err
248
+	}
249
+	s.toClose = append(s.toClose, pr)
250
+	s.toRelease = append(s.toRelease, pw)
251
+	go func() {
252
+		_, err := io.Copy(wc, pr)
253
+		if err1 := pw.Close(); err == nil {
254
+			err = err1
255
+		}
256
+		_ = err
257
+	}()
258
+	return pw, nil
259
+}
260
+
261
+var subReaperOnce sync.Once
262
+var subReaperError error
263
+
264
+// DisableSubReaper prevents setting subreaper on the current process.
265
+// Do not rely on this function it may change or be removed.
266
+func DisableSubReaper() {
267
+	subReaperOnce.Do(func() {})
268
+}
269
+
270
+func setSubReaper() error {
271
+	subReaperOnce.Do(func() {
272
+		subReaperError = runcsystem.SetSubreaper(1)
273
+	})
274
+	return subReaperError
275
+}
276
+
221 277
 func (s *forwardIO) Stdin() io.WriteCloser {
222 278
 	return nil
223 279
 }
... ...
@@ -4,8 +4,10 @@ import (
4 4
 	"archive/tar"
5 5
 	"bytes"
6 6
 	"context"
7
+	"encoding/csv"
7 8
 	"encoding/json"
8 9
 	"fmt"
10
+	"net"
9 11
 	"regexp"
10 12
 	"strconv"
11 13
 	"strings"
... ...
@@ -36,6 +38,8 @@ const (
36 36
 	keyTargetPlatform     = "platform"
37 37
 	keyMultiPlatform      = "multi-platform"
38 38
 	keyImageResolveMode   = "image-resolve-mode"
39
+	keyGlobalAddHosts     = "add-hosts"
40
+	keyForceNetwork       = "force-network-mode"
39 41
 )
40 42
 
41 43
 var httpPrefix = regexp.MustCompile("^https?://")
... ...
@@ -64,6 +68,16 @@ func Build(ctx context.Context, c client.Client) (*client.Result, error) {
64 64
 		return nil, err
65 65
 	}
66 66
 
67
+	extraHosts, err := parseExtraHosts(opts[keyGlobalAddHosts])
68
+	if err != nil {
69
+		return nil, errors.Wrap(err, "failed to parse additional hosts")
70
+	}
71
+
72
+	defaultNetMode, err := parseNetMode(opts[keyForceNetwork])
73
+	if err != nil {
74
+		return nil, err
75
+	}
76
+
67 77
 	filename := opts[keyFilename]
68 78
 	if filename == "" {
69 79
 		filename = defaultDockerfileName
... ...
@@ -250,6 +264,8 @@ func Build(ctx context.Context, c client.Client) (*client.Result, error) {
250 250
 					BuildPlatforms:   buildPlatforms,
251 251
 					ImageResolveMode: resolveMode,
252 252
 					PrefixPlatform:   exportMap,
253
+					ExtraHosts:       extraHosts,
254
+					ForceNetMode:     defaultNetMode,
253 255
 				})
254 256
 
255 257
 				if err != nil {
... ...
@@ -413,3 +429,45 @@ func parseResolveMode(v string) (llb.ResolveMode, error) {
413 413
 		return 0, errors.Errorf("invalid image-resolve-mode: %s", v)
414 414
 	}
415 415
 }
416
+
417
+func parseExtraHosts(v string) ([]llb.HostIP, error) {
418
+	if v == "" {
419
+		return nil, nil
420
+	}
421
+	out := make([]llb.HostIP, 0)
422
+	csvReader := csv.NewReader(strings.NewReader(v))
423
+	fields, err := csvReader.Read()
424
+	if err != nil {
425
+		return nil, err
426
+	}
427
+	for _, field := range fields {
428
+		parts := strings.SplitN(field, "=", 2)
429
+		if len(parts) != 2 {
430
+			return nil, errors.Errorf("invalid key-value pair %s", field)
431
+		}
432
+		key := strings.ToLower(parts[0])
433
+		val := strings.ToLower(parts[1])
434
+		ip := net.ParseIP(val)
435
+		if ip == nil {
436
+			return nil, errors.Errorf("failed to parse IP %s", val)
437
+		}
438
+		out = append(out, llb.HostIP{Host: key, IP: ip})
439
+	}
440
+	return out, nil
441
+}
442
+
443
+func parseNetMode(v string) (pb.NetMode, error) {
444
+	if v == "" {
445
+		return llb.NetModeSandbox, nil
446
+	}
447
+	switch v {
448
+	case "none":
449
+		return llb.NetModeNone, nil
450
+	case "host":
451
+		return llb.NetModeHost, nil
452
+	case "sandbox":
453
+		return llb.NetModeSandbox, nil
454
+	default:
455
+		return 0, errors.Errorf("invalid netmode %s", v)
456
+	}
457
+}
... ...
@@ -22,6 +22,7 @@ import (
22 22
 	"github.com/moby/buildkit/frontend/dockerfile/parser"
23 23
 	"github.com/moby/buildkit/frontend/dockerfile/shell"
24 24
 	gw "github.com/moby/buildkit/frontend/gateway/client"
25
+	"github.com/moby/buildkit/solver/pb"
25 26
 	specs "github.com/opencontainers/image-spec/specs-go/v1"
26 27
 	"github.com/pkg/errors"
27 28
 	"golang.org/x/sync/errgroup"
... ...
@@ -52,6 +53,8 @@ type ConvertOpt struct {
52 52
 	TargetPlatform   *specs.Platform
53 53
 	BuildPlatforms   []specs.Platform
54 54
 	PrefixPlatform   bool
55
+	ExtraHosts       []llb.HostIP
56
+	ForceNetMode     pb.NetMode
55 57
 }
56 58
 
57 59
 func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State, *Image, error) {
... ...
@@ -282,6 +285,7 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
282 282
 				return nil, nil, err
283 283
 			}
284 284
 		}
285
+		d.state = d.state.Network(opt.ForceNetMode)
285 286
 
286 287
 		opt := dispatchOpt{
287 288
 			allDispatchStates: allDispatchStates,
... ...
@@ -294,6 +298,7 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State,
294 294
 			cacheIDNamespace:  opt.CacheIDNamespace,
295 295
 			buildPlatforms:    platformOpt.buildPlatforms,
296 296
 			targetPlatform:    platformOpt.targetPlatform,
297
+			extraHosts:        opt.ExtraHosts,
297 298
 		}
298 299
 
299 300
 		if err = dispatchOnBuild(d, d.image.Config.OnBuild, opt); err != nil {
... ...
@@ -397,6 +402,7 @@ type dispatchOpt struct {
397 397
 	cacheIDNamespace  string
398 398
 	targetPlatform    specs.Platform
399 399
 	buildPlatforms    []specs.Platform
400
+	extraHosts        []llb.HostIP
400 401
 }
401 402
 
402 403
 func dispatch(d *dispatchState, cmd command, opt dispatchOpt) error {
... ...
@@ -584,6 +590,9 @@ func dispatchRun(d *dispatchState, c *instructions.RunCommand, proxy *llb.ProxyE
584 584
 	}
585 585
 	opt = append(opt, runMounts...)
586 586
 	opt = append(opt, llb.WithCustomName(prefixCommand(d, uppercaseCmd(processCmdEnv(dopt.shlex, c.String(), d.state.Run(opt...).Env())), d.prefixPlatform, d.state.GetPlatform())))
587
+	for _, h := range dopt.extraHosts {
588
+		opt = append(opt, llb.AddExtraHost(h.Host, h.IP))
589
+	}
587 590
 	d.state = d.state.Run(opt...).Root()
588 591
 	return commitToHistory(&d.image, "RUN "+runCommandString(args, d.buildArgs), true, &d.state)
589 592
 }
590 593
new file mode 100644
... ...
@@ -0,0 +1,13 @@
0
+// +build dfrunmount,!dfsecrets
1
+
2
+package dockerfile2llb
3
+
4
+import (
5
+	"github.com/moby/buildkit/client/llb"
6
+	"github.com/moby/buildkit/frontend/dockerfile/instructions"
7
+	"github.com/pkg/errors"
8
+)
9
+
10
+func dispatchSecret(m *instructions.Mount) (llb.RunOption, error) {
11
+	return nil, errors.Errorf("secret mounts not allowed")
12
+}
... ...
@@ -57,6 +57,14 @@ func dispatchRunMounts(d *dispatchState, c *instructions.RunCommand, sources []*
57 57
 			st = llb.Scratch()
58 58
 			mountOpts = append(mountOpts, llb.Tmpfs())
59 59
 		}
60
+		if mount.Type == instructions.MountTypeSecret {
61
+			secret, err := dispatchSecret(mount)
62
+			if err != nil {
63
+				return nil, err
64
+			}
65
+			out = append(out, secret)
66
+			continue
67
+		}
60 68
 		if mount.ReadOnly {
61 69
 			mountOpts = append(mountOpts, llb.Readonly)
62 70
 		}
63 71
new file mode 100644
... ...
@@ -0,0 +1,32 @@
0
+// +build dfsecrets dfextall
1
+
2
+package dockerfile2llb
3
+
4
+import (
5
+	"path"
6
+
7
+	"github.com/moby/buildkit/client/llb"
8
+	"github.com/moby/buildkit/frontend/dockerfile/instructions"
9
+	"github.com/pkg/errors"
10
+)
11
+
12
+func dispatchSecret(m *instructions.Mount) (llb.RunOption, error) {
13
+	id := m.CacheID
14
+	if m.Source != "" {
15
+		id = m.Source
16
+	}
17
+
18
+	if id == "" {
19
+		if m.Target == "" {
20
+			return nil, errors.Errorf("one of source, target required")
21
+		}
22
+		id = path.Base(m.Target)
23
+	}
24
+
25
+	target := m.Target
26
+	if target == "" {
27
+		target = "/run/secrets/" + path.Base(id)
28
+	}
29
+
30
+	return llb.AddSecret(target, llb.SecretID(id)), nil
31
+}
0 32
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+// +build !dfsecrets
1
+
2
+package instructions
3
+
4
+func isSecretMountsSupported() bool {
5
+	return false
6
+}
... ...
@@ -13,11 +13,13 @@ import (
13 13
 const MountTypeBind = "bind"
14 14
 const MountTypeCache = "cache"
15 15
 const MountTypeTmpfs = "tmpfs"
16
+const MountTypeSecret = "secret"
16 17
 
17 18
 var allowedMountTypes = map[string]struct{}{
18
-	MountTypeBind:  {},
19
-	MountTypeCache: {},
20
-	MountTypeTmpfs: {},
19
+	MountTypeBind:   {},
20
+	MountTypeCache:  {},
21
+	MountTypeTmpfs:  {},
22
+	MountTypeSecret: {},
21 23
 }
22 24
 
23 25
 const MountSharingShared = "shared"
... ...
@@ -40,6 +42,11 @@ func init() {
40 40
 }
41 41
 
42 42
 func isValidMountType(s string) bool {
43
+	if s == "secret" {
44
+		if !isSecretMountsSupported() {
45
+			return false
46
+		}
47
+	}
43 48
 	_, ok := allowedMountTypes[s]
44 49
 	return ok
45 50
 }
... ...
@@ -177,5 +184,20 @@ func parseMount(value string) (*Mount, error) {
177 177
 		return nil, errors.Errorf("invalid cache sharing set for %v mount", m.Type)
178 178
 	}
179 179
 
180
+	if m.Type == MountTypeSecret {
181
+		if m.From != "" {
182
+			return nil, errors.Errorf("secret mount should not have a from")
183
+		}
184
+		if m.CacheSharing != "" {
185
+			return nil, errors.Errorf("secret mount should not define sharing")
186
+		}
187
+		if m.Source == "" && m.Target == "" && m.CacheID == "" {
188
+			return nil, errors.Errorf("invalid secret mount. one of source, target required")
189
+		}
190
+		if m.Source != "" && m.CacheID != "" {
191
+			return nil, errors.Errorf("both source and id can't be set")
192
+		}
193
+	}
194
+
180 195
 	return m, nil
181 196
 }
182 197
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+// +build dfsecrets dfextall
1
+
2
+package instructions
3
+
4
+func isSecretMountsSupported() bool {
5
+	return true
6
+}
... ...
@@ -215,26 +215,72 @@ func (gf *gatewayFrontend) Solve(ctx context.Context, llbBridge frontend.Fronten
215 215
 		ReadonlyRootFS: readonly,
216 216
 	}, rootFS, lbf.Stdin, lbf.Stdout, os.Stderr)
217 217
 
218
-	if lbf.err != nil {
219
-		return nil, lbf.err
218
+	if err != nil {
219
+		// An existing error (set via Return rpc) takes
220
+		// precedence over this error, which in turn takes
221
+		// precedence over a success reported via Return.
222
+		lbf.mu.Lock()
223
+		if lbf.err == nil {
224
+			lbf.result = nil
225
+			lbf.err = err
226
+		}
227
+		lbf.mu.Unlock()
220 228
 	}
221 229
 
222
-	if err != nil {
223
-		return nil, err
230
+	return lbf.Result()
231
+}
232
+
233
+func (lbf *llbBridgeForwarder) Done() <-chan struct{} {
234
+	return lbf.doneCh
235
+}
236
+
237
+func (lbf *llbBridgeForwarder) setResult(r *frontend.Result, err error) (*pb.ReturnResponse, error) {
238
+	lbf.mu.Lock()
239
+	defer lbf.mu.Unlock()
240
+
241
+	if (r == nil) == (err == nil) {
242
+		return nil, errors.New("gateway return must be either result or err")
243
+	}
244
+
245
+	if lbf.result != nil || lbf.err != nil {
246
+		return nil, errors.New("gateway result is already set")
247
+	}
248
+
249
+	lbf.result = r
250
+	lbf.err = err
251
+	close(lbf.doneCh)
252
+	return &pb.ReturnResponse{}, nil
253
+}
254
+
255
+func (lbf *llbBridgeForwarder) Result() (*frontend.Result, error) {
256
+	lbf.mu.Lock()
257
+	defer lbf.mu.Unlock()
258
+
259
+	if lbf.result == nil && lbf.err == nil {
260
+		return nil, errors.New("no result for incomplete build")
261
+	}
262
+
263
+	if lbf.err != nil {
264
+		return nil, lbf.err
224 265
 	}
225 266
 
226 267
 	return lbf.result, nil
227 268
 }
228 269
 
229
-func newLLBBridgeForwarder(ctx context.Context, llbBridge frontend.FrontendLLBBridge, workers frontend.WorkerInfos) (*llbBridgeForwarder, error) {
270
+func NewBridgeForwarder(ctx context.Context, llbBridge frontend.FrontendLLBBridge, workers frontend.WorkerInfos) *llbBridgeForwarder {
230 271
 	lbf := &llbBridgeForwarder{
231 272
 		callCtx:   ctx,
232 273
 		llbBridge: llbBridge,
233 274
 		refs:      map[string]solver.CachedResult{},
275
+		doneCh:    make(chan struct{}),
234 276
 		pipe:      newPipe(),
235 277
 		workers:   workers,
236 278
 	}
279
+	return lbf
280
+}
237 281
 
282
+func newLLBBridgeForwarder(ctx context.Context, llbBridge frontend.FrontendLLBBridge, workers frontend.WorkerInfos) (*llbBridgeForwarder, error) {
283
+	lbf := NewBridgeForwarder(ctx, llbBridge, workers)
238 284
 	server := grpc.NewServer()
239 285
 	grpc_health_v1.RegisterHealthServer(server, health.NewServer())
240 286
 	pb.RegisterLLBBridgeServer(server, lbf)
... ...
@@ -297,6 +343,12 @@ func (d dummyAddr) String() string {
297 297
 	return "localhost"
298 298
 }
299 299
 
300
+type LLBBridgeForwarder interface {
301
+	pb.LLBBridgeServer
302
+	Done() <-chan struct{}
303
+	Result() (*frontend.Result, error)
304
+}
305
+
300 306
 type llbBridgeForwarder struct {
301 307
 	mu        sync.Mutex
302 308
 	callCtx   context.Context
... ...
@@ -305,6 +357,7 @@ type llbBridgeForwarder struct {
305 305
 	// lastRef      solver.CachedResult
306 306
 	// lastRefs     map[string]solver.CachedResult
307 307
 	// err          error
308
+	doneCh       chan struct{} // closed when result or err become valid through a call to a Return
308 309
 	result       *frontend.Result
309 310
 	err          error
310 311
 	exporterAttr map[string][]byte
... ...
@@ -465,13 +518,13 @@ func (lbf *llbBridgeForwarder) Ping(context.Context, *pb.PingRequest) (*pb.PongR
465 465
 
466 466
 func (lbf *llbBridgeForwarder) Return(ctx context.Context, in *pb.ReturnRequest) (*pb.ReturnResponse, error) {
467 467
 	if in.Error != nil {
468
-		lbf.err = status.ErrorProto(&spb.Status{
468
+		return lbf.setResult(nil, status.ErrorProto(&spb.Status{
469 469
 			Code:    in.Error.Code,
470 470
 			Message: in.Error.Message,
471 471
 			// Details: in.Error.Details,
472
-		})
472
+		}))
473 473
 	} else {
474
-		lbf.result = &frontend.Result{
474
+		r := &frontend.Result{
475 475
 			Metadata: in.Result.Metadata,
476 476
 		}
477 477
 
... ...
@@ -481,7 +534,7 @@ func (lbf *llbBridgeForwarder) Return(ctx context.Context, in *pb.ReturnRequest)
481 481
 			if err != nil {
482 482
 				return nil, err
483 483
 			}
484
-			lbf.result.Ref = ref
484
+			r.Ref = ref
485 485
 		case *pb.Result_Refs:
486 486
 			m := map[string]solver.CachedResult{}
487 487
 			for k, v := range res.Refs.Refs {
... ...
@@ -491,11 +544,10 @@ func (lbf *llbBridgeForwarder) Return(ctx context.Context, in *pb.ReturnRequest)
491 491
 				}
492 492
 				m[k] = ref
493 493
 			}
494
-			lbf.result.Refs = m
494
+			r.Refs = m
495 495
 		}
496
+		return lbf.setResult(r, nil)
496 497
 	}
497
-
498
-	return &pb.ReturnResponse{}, nil
499 498
 }
500 499
 
501 500
 func (lbf *llbBridgeForwarder) convertRef(id string) (solver.CachedResult, error) {
502 501
new file mode 100644
... ...
@@ -0,0 +1,457 @@
0
+package grpcclient
1
+
2
+import (
3
+	"context"
4
+	"encoding/json"
5
+	"io"
6
+	"net"
7
+	"os"
8
+	"strings"
9
+	"time"
10
+
11
+	"github.com/gogo/googleapis/google/rpc"
12
+	"github.com/moby/buildkit/frontend/gateway/client"
13
+	pb "github.com/moby/buildkit/frontend/gateway/pb"
14
+	opspb "github.com/moby/buildkit/solver/pb"
15
+	"github.com/moby/buildkit/util/apicaps"
16
+	digest "github.com/opencontainers/go-digest"
17
+	"github.com/pkg/errors"
18
+	"google.golang.org/grpc"
19
+	"google.golang.org/grpc/status"
20
+)
21
+
22
+const frontendPrefix = "BUILDKIT_FRONTEND_OPT_"
23
+
24
+type GrpcClient interface {
25
+	Run(context.Context, client.BuildFunc) error
26
+}
27
+
28
+func New(ctx context.Context, opts map[string]string, session, product string, c pb.LLBBridgeClient, w []client.WorkerInfo) (GrpcClient, error) {
29
+	resp, err := c.Ping(ctx, &pb.PingRequest{})
30
+	if err != nil {
31
+		return nil, err
32
+	}
33
+
34
+	if resp.FrontendAPICaps == nil {
35
+		resp.FrontendAPICaps = defaultCaps()
36
+	}
37
+
38
+	if resp.LLBCaps == nil {
39
+		resp.LLBCaps = defaultLLBCaps()
40
+	}
41
+
42
+	return &grpcClient{
43
+		client:    c,
44
+		opts:      opts,
45
+		sessionID: session,
46
+		workers:   w,
47
+		product:   product,
48
+		caps:      pb.Caps.CapSet(resp.FrontendAPICaps),
49
+		llbCaps:   opspb.Caps.CapSet(resp.LLBCaps),
50
+		requests:  map[string]*pb.SolveRequest{},
51
+	}, nil
52
+}
53
+
54
+func current() (GrpcClient, error) {
55
+	if ep := product(); ep != "" {
56
+		apicaps.ExportedProduct = ep
57
+	}
58
+
59
+	ctx, conn, err := grpcClientConn(context.Background())
60
+	if err != nil {
61
+		return nil, err
62
+	}
63
+
64
+	return New(ctx, opts(), sessionID(), product(), pb.NewLLBBridgeClient(conn), workers())
65
+}
66
+
67
+func convertRef(ref client.Reference) (string, error) {
68
+	if ref == nil {
69
+		return "", nil
70
+	}
71
+	r, ok := ref.(*reference)
72
+	if !ok {
73
+		return "", errors.Errorf("invalid return reference type %T", ref)
74
+	}
75
+	return r.id, nil
76
+}
77
+
78
+func RunFromEnvironment(ctx context.Context, f client.BuildFunc) error {
79
+	client, err := current()
80
+	if err != nil {
81
+		return errors.Wrapf(err, "failed to initialize client from environment")
82
+	}
83
+	return client.Run(ctx, f)
84
+}
85
+
86
+func (c *grpcClient) Run(ctx context.Context, f client.BuildFunc) (retError error) {
87
+	export := c.caps.Supports(pb.CapReturnResult) == nil
88
+
89
+	var (
90
+		res *client.Result
91
+		err error
92
+	)
93
+	if export {
94
+		defer func() {
95
+			req := &pb.ReturnRequest{}
96
+			if retError == nil {
97
+				if res == nil {
98
+					res = &client.Result{}
99
+				}
100
+				pbRes := &pb.Result{
101
+					Metadata: res.Metadata,
102
+				}
103
+				if res.Refs != nil {
104
+					m := map[string]string{}
105
+					for k, r := range res.Refs {
106
+						id, err := convertRef(r)
107
+						if err != nil {
108
+							retError = err
109
+							continue
110
+						}
111
+						m[k] = id
112
+					}
113
+					pbRes.Result = &pb.Result_Refs{Refs: &pb.RefMap{Refs: m}}
114
+				} else {
115
+					id, err := convertRef(res.Ref)
116
+					if err != nil {
117
+						retError = err
118
+					} else {
119
+						pbRes.Result = &pb.Result_Ref{Ref: id}
120
+					}
121
+				}
122
+				if retError == nil {
123
+					req.Result = pbRes
124
+				}
125
+			}
126
+			if retError != nil {
127
+				st, _ := status.FromError(retError)
128
+				stp := st.Proto()
129
+				req.Error = &rpc.Status{
130
+					Code:    stp.Code,
131
+					Message: stp.Message,
132
+					// Details: stp.Details,
133
+				}
134
+			}
135
+			if _, err := c.client.Return(ctx, req); err != nil && retError == nil {
136
+				retError = err
137
+			}
138
+		}()
139
+	}
140
+
141
+	if res, err = f(ctx, c); err != nil {
142
+		return err
143
+	}
144
+
145
+	if err := c.caps.Supports(pb.CapReturnMap); len(res.Refs) > 1 && err != nil {
146
+		return err
147
+	}
148
+
149
+	if !export {
150
+		exportedAttrBytes, err := json.Marshal(res.Metadata)
151
+		if err != nil {
152
+			return errors.Wrapf(err, "failed to marshal return metadata")
153
+		}
154
+
155
+		req, err := c.requestForRef(res.Ref)
156
+		if err != nil {
157
+			return errors.Wrapf(err, "failed to find return ref")
158
+		}
159
+
160
+		req.Final = true
161
+		req.ExporterAttr = exportedAttrBytes
162
+
163
+		if _, err := c.client.Solve(ctx, req); err != nil {
164
+			return errors.Wrapf(err, "failed to solve")
165
+		}
166
+	}
167
+
168
+	return nil
169
+}
170
+
171
+// defaultCaps returns the capabilities that were implemented when capabilities
172
+// support was added. This list is frozen and should never be changed.
173
+func defaultCaps() []apicaps.PBCap {
174
+	return []apicaps.PBCap{
175
+		{ID: string(pb.CapSolveBase), Enabled: true},
176
+		{ID: string(pb.CapSolveInlineReturn), Enabled: true},
177
+		{ID: string(pb.CapResolveImage), Enabled: true},
178
+		{ID: string(pb.CapReadFile), Enabled: true},
179
+	}
180
+}
181
+
182
+// defaultLLBCaps returns the LLB capabilities that were implemented when capabilities
183
+// support was added. This list is frozen and should never be changed.
184
+func defaultLLBCaps() []apicaps.PBCap {
185
+	return []apicaps.PBCap{
186
+		{ID: string(opspb.CapSourceImage), Enabled: true},
187
+		{ID: string(opspb.CapSourceLocal), Enabled: true},
188
+		{ID: string(opspb.CapSourceLocalUnique), Enabled: true},
189
+		{ID: string(opspb.CapSourceLocalSessionID), Enabled: true},
190
+		{ID: string(opspb.CapSourceLocalIncludePatterns), Enabled: true},
191
+		{ID: string(opspb.CapSourceLocalFollowPaths), Enabled: true},
192
+		{ID: string(opspb.CapSourceLocalExcludePatterns), Enabled: true},
193
+		{ID: string(opspb.CapSourceLocalSharedKeyHint), Enabled: true},
194
+		{ID: string(opspb.CapSourceGit), Enabled: true},
195
+		{ID: string(opspb.CapSourceGitKeepDir), Enabled: true},
196
+		{ID: string(opspb.CapSourceGitFullURL), Enabled: true},
197
+		{ID: string(opspb.CapSourceHTTP), Enabled: true},
198
+		{ID: string(opspb.CapSourceHTTPChecksum), Enabled: true},
199
+		{ID: string(opspb.CapSourceHTTPPerm), Enabled: true},
200
+		{ID: string(opspb.CapSourceHTTPUIDGID), Enabled: true},
201
+		{ID: string(opspb.CapBuildOpLLBFileName), Enabled: true},
202
+		{ID: string(opspb.CapExecMetaBase), Enabled: true},
203
+		{ID: string(opspb.CapExecMetaProxy), Enabled: true},
204
+		{ID: string(opspb.CapExecMountBind), Enabled: true},
205
+		{ID: string(opspb.CapExecMountCache), Enabled: true},
206
+		{ID: string(opspb.CapExecMountCacheSharing), Enabled: true},
207
+		{ID: string(opspb.CapExecMountSelector), Enabled: true},
208
+		{ID: string(opspb.CapExecMountTmpfs), Enabled: true},
209
+		{ID: string(opspb.CapMountSecret), Enabled: true},
210
+		{ID: string(opspb.CapConstraints), Enabled: true},
211
+		{ID: string(opspb.CapPlatform), Enabled: true},
212
+		{ID: string(opspb.CapMetaIgnoreCache), Enabled: true},
213
+		{ID: string(opspb.CapMetaDescription), Enabled: true},
214
+		{ID: string(opspb.CapMetaExportCache), Enabled: true},
215
+	}
216
+}
217
+
218
+type grpcClient struct {
219
+	client    pb.LLBBridgeClient
220
+	opts      map[string]string
221
+	sessionID string
222
+	product   string
223
+	workers   []client.WorkerInfo
224
+	caps      apicaps.CapSet
225
+	llbCaps   apicaps.CapSet
226
+	requests  map[string]*pb.SolveRequest
227
+}
228
+
229
+func (c *grpcClient) requestForRef(ref client.Reference) (*pb.SolveRequest, error) {
230
+	emptyReq := &pb.SolveRequest{
231
+		Definition: &opspb.Definition{},
232
+	}
233
+	if ref == nil {
234
+		return emptyReq, nil
235
+	}
236
+	r, ok := ref.(*reference)
237
+	if !ok {
238
+		return nil, errors.Errorf("return reference has invalid type %T", ref)
239
+	}
240
+	if r.id == "" {
241
+		return emptyReq, nil
242
+	}
243
+	req, ok := c.requests[r.id]
244
+	if !ok {
245
+		return nil, errors.Errorf("did not find request for return reference %s", r.id)
246
+	}
247
+	return req, nil
248
+}
249
+
250
+func (c *grpcClient) Solve(ctx context.Context, creq client.SolveRequest) (*client.Result, error) {
251
+	if creq.Definition != nil {
252
+		for _, md := range creq.Definition.Metadata {
253
+			for cap := range md.Caps {
254
+				if err := c.llbCaps.Supports(cap); err != nil {
255
+					return nil, err
256
+				}
257
+			}
258
+		}
259
+	}
260
+
261
+	req := &pb.SolveRequest{
262
+		Definition:        creq.Definition,
263
+		Frontend:          creq.Frontend,
264
+		FrontendOpt:       creq.FrontendOpt,
265
+		ImportCacheRefs:   creq.ImportCacheRefs,
266
+		AllowResultReturn: true,
267
+	}
268
+
269
+	// backwards compatibility with inline return
270
+	if c.caps.Supports(pb.CapReturnResult) != nil {
271
+		req.ExporterAttr = []byte("{}")
272
+	}
273
+
274
+	resp, err := c.client.Solve(ctx, req)
275
+	if err != nil {
276
+		return nil, err
277
+	}
278
+
279
+	res := &client.Result{}
280
+
281
+	if resp.Result == nil {
282
+		if id := resp.Ref; id != "" {
283
+			c.requests[id] = req
284
+		}
285
+		res.SetRef(&reference{id: resp.Ref, c: c})
286
+	} else {
287
+		res.Metadata = resp.Result.Metadata
288
+		switch pbRes := resp.Result.Result.(type) {
289
+		case *pb.Result_Ref:
290
+			if id := pbRes.Ref; id != "" {
291
+				res.SetRef(&reference{id: id, c: c})
292
+			}
293
+		case *pb.Result_Refs:
294
+			for k, v := range pbRes.Refs.Refs {
295
+				ref := &reference{id: v, c: c}
296
+				if v == "" {
297
+					ref = nil
298
+				}
299
+				res.AddRef(k, ref)
300
+			}
301
+		}
302
+	}
303
+
304
+	return res, nil
305
+}
306
+
307
+func (c *grpcClient) ResolveImageConfig(ctx context.Context, ref string, opt client.ResolveImageConfigOpt) (digest.Digest, []byte, error) {
308
+	var p *opspb.Platform
309
+	if platform := opt.Platform; platform != nil {
310
+		p = &opspb.Platform{
311
+			OS:           platform.OS,
312
+			Architecture: platform.Architecture,
313
+			Variant:      platform.Variant,
314
+			OSVersion:    platform.OSVersion,
315
+			OSFeatures:   platform.OSFeatures,
316
+		}
317
+	}
318
+	resp, err := c.client.ResolveImageConfig(ctx, &pb.ResolveImageConfigRequest{Ref: ref, Platform: p, ResolveMode: opt.ResolveMode, LogName: opt.LogName})
319
+	if err != nil {
320
+		return "", nil, err
321
+	}
322
+	return resp.Digest, resp.Config, nil
323
+}
324
+
325
+func (c *grpcClient) BuildOpts() client.BuildOpts {
326
+	return client.BuildOpts{
327
+		Opts:      c.opts,
328
+		SessionID: c.sessionID,
329
+		Workers:   c.workers,
330
+		Product:   c.product,
331
+	}
332
+}
333
+
334
+func (c *grpcClient) Opts() map[string]string {
335
+	return c.opts
336
+}
337
+
338
+func (c *grpcClient) SessionID() string {
339
+	return c.sessionID
340
+}
341
+
342
+func (c *grpcClient) WorkerInfos() []client.WorkerInfo {
343
+	return c.workers
344
+}
345
+
346
+type reference struct {
347
+	id string
348
+	c  *grpcClient
349
+}
350
+
351
+func (r *reference) ReadFile(ctx context.Context, req client.ReadRequest) ([]byte, error) {
352
+	rfr := &pb.ReadFileRequest{FilePath: req.Filename, Ref: r.id}
353
+	if r := req.Range; r != nil {
354
+		rfr.Range = &pb.FileRange{
355
+			Offset: int64(r.Offset),
356
+			Length: int64(r.Length),
357
+		}
358
+	}
359
+	resp, err := r.c.client.ReadFile(ctx, rfr)
360
+	if err != nil {
361
+		return nil, err
362
+	}
363
+	return resp.Data, nil
364
+}
365
+
366
+func grpcClientConn(ctx context.Context) (context.Context, *grpc.ClientConn, error) {
367
+	dialOpt := grpc.WithDialer(func(addr string, d time.Duration) (net.Conn, error) {
368
+		return stdioConn(), nil
369
+	})
370
+
371
+	cc, err := grpc.DialContext(ctx, "", dialOpt, grpc.WithInsecure())
372
+	if err != nil {
373
+		return nil, nil, errors.Wrap(err, "failed to create grpc client")
374
+	}
375
+
376
+	ctx, cancel := context.WithCancel(ctx)
377
+	_ = cancel
378
+	// go monitorHealth(ctx, cc, cancel)
379
+
380
+	return ctx, cc, nil
381
+}
382
+
383
+func stdioConn() net.Conn {
384
+	return &conn{os.Stdin, os.Stdout, os.Stdout}
385
+}
386
+
387
+type conn struct {
388
+	io.Reader
389
+	io.Writer
390
+	io.Closer
391
+}
392
+
393
+func (s *conn) LocalAddr() net.Addr {
394
+	return dummyAddr{}
395
+}
396
+func (s *conn) RemoteAddr() net.Addr {
397
+	return dummyAddr{}
398
+}
399
+func (s *conn) SetDeadline(t time.Time) error {
400
+	return nil
401
+}
402
+func (s *conn) SetReadDeadline(t time.Time) error {
403
+	return nil
404
+}
405
+func (s *conn) SetWriteDeadline(t time.Time) error {
406
+	return nil
407
+}
408
+
409
+type dummyAddr struct {
410
+}
411
+
412
+func (d dummyAddr) Network() string {
413
+	return "pipe"
414
+}
415
+
416
+func (d dummyAddr) String() string {
417
+	return "localhost"
418
+}
419
+
420
+func opts() map[string]string {
421
+	opts := map[string]string{}
422
+	for _, env := range os.Environ() {
423
+		parts := strings.SplitN(env, "=", 2)
424
+		k := parts[0]
425
+		v := ""
426
+		if len(parts) == 2 {
427
+			v = parts[1]
428
+		}
429
+		if !strings.HasPrefix(k, frontendPrefix) {
430
+			continue
431
+		}
432
+		parts = strings.SplitN(v, "=", 2)
433
+		v = ""
434
+		if len(parts) == 2 {
435
+			v = parts[1]
436
+		}
437
+		opts[parts[0]] = v
438
+	}
439
+	return opts
440
+}
441
+
442
+func sessionID() string {
443
+	return os.Getenv("BUILDKIT_SESSION_ID")
444
+}
445
+
446
+func workers() []client.WorkerInfo {
447
+	var c []client.WorkerInfo
448
+	if err := json.Unmarshal([]byte(os.Getenv("BUILDKIT_WORKERS")), &c); err != nil {
449
+		return nil
450
+	}
451
+	return c
452
+}
453
+
454
+func product() string {
455
+	return os.Getenv("BUILDKIT_EXPORTEDPRODUCT")
456
+}
... ...
@@ -21,6 +21,7 @@ type ResolveOpFunc func(Vertex, Builder) (Op, error)
21 21
 type Builder interface {
22 22
 	Build(ctx context.Context, e Edge) (CachedResult, error)
23 23
 	Context(ctx context.Context) context.Context
24
+	EachValue(ctx context.Context, key string, fn func(interface{}) error) error
24 25
 }
25 26
 
26 27
 // Solver provides a shared graph of all the vertexes currently being
... ...
@@ -169,10 +170,22 @@ func (sb *subBuilder) Context(ctx context.Context) context.Context {
169 169
 	return progress.WithProgress(ctx, sb.mpw)
170 170
 }
171 171
 
172
+func (sb *subBuilder) EachValue(ctx context.Context, key string, fn func(interface{}) error) error {
173
+	sb.mu.Lock()
174
+	defer sb.mu.Lock()
175
+	for j := range sb.jobs {
176
+		if err := j.EachValue(ctx, key, fn); err != nil {
177
+			return err
178
+		}
179
+	}
180
+	return nil
181
+}
182
+
172 183
 type Job struct {
173
-	list *Solver
174
-	pr   *progress.MultiReader
175
-	pw   progress.Writer
184
+	list   *Solver
185
+	pr     *progress.MultiReader
186
+	pw     progress.Writer
187
+	values sync.Map
176 188
 
177 189
 	progressCloser func()
178 190
 	SessionID      string
... ...
@@ -446,6 +459,18 @@ func (j *Job) Context(ctx context.Context) context.Context {
446 446
 	return progress.WithProgress(ctx, j.pw)
447 447
 }
448 448
 
449
+func (j *Job) SetValue(key string, v interface{}) {
450
+	j.values.Store(key, v)
451
+}
452
+
453
+func (j *Job) EachValue(ctx context.Context, key string, fn func(interface{}) error) error {
454
+	v, ok := j.values.Load(key)
455
+	if ok {
456
+		return fn(v)
457
+	}
458
+	return nil
459
+}
460
+
449 461
 type cacheMapResp struct {
450 462
 	*CacheMap
451 463
 	complete bool
... ...
@@ -75,7 +75,12 @@ func (b *llbBridge) Solve(ctx context.Context, req frontend.SolveRequest) (res *
75 75
 	}
76 76
 
77 77
 	if req.Definition != nil && req.Definition.Def != nil {
78
-		edge, err := Load(req.Definition, WithCacheSources(cms), RuntimePlatforms(b.platforms), WithValidateCaps())
78
+		ent, err := loadEntitlements(b.builder)
79
+		if err != nil {
80
+			return nil, err
81
+		}
82
+
83
+		edge, err := Load(req.Definition, ValidateEntitlements(ent), WithCacheSources(cms), RuntimePlatforms(b.platforms), WithValidateCaps())
79 84
 		if err != nil {
80 85
 			return nil, err
81 86
 		}
... ...
@@ -6,6 +6,7 @@ import (
6 6
 	"encoding/json"
7 7
 	"fmt"
8 8
 	"io/ioutil"
9
+	"net"
9 10
 	"os"
10 11
 	"path"
11 12
 	"path/filepath"
... ...
@@ -67,6 +68,11 @@ func NewExecOp(v solver.Vertex, op *pb.Op_Exec, cm cache.Manager, sm *session.Ma
67 67
 func cloneExecOp(old *pb.ExecOp) pb.ExecOp {
68 68
 	n := *old
69 69
 	meta := *n.Meta
70
+	meta.ExtraHosts = nil
71
+	for i := range n.Meta.ExtraHosts {
72
+		h := *n.Meta.ExtraHosts[i]
73
+		meta.ExtraHosts = append(meta.ExtraHosts, &h)
74
+	}
70 75
 	n.Meta = &meta
71 76
 	n.Mounts = nil
72 77
 	for i := range n.Mounts {
... ...
@@ -78,6 +84,11 @@ func cloneExecOp(old *pb.ExecOp) pb.ExecOp {
78 78
 
79 79
 func (e *execOp) CacheMap(ctx context.Context, index int) (*solver.CacheMap, bool, error) {
80 80
 	op := cloneExecOp(e.op)
81
+	for i := range op.Meta.ExtraHosts {
82
+		h := op.Meta.ExtraHosts[i]
83
+		h.IP = ""
84
+		op.Meta.ExtraHosts[i] = h
85
+	}
81 86
 	for i := range op.Mounts {
82 87
 		op.Mounts[i].Selector = ""
83 88
 	}
... ...
@@ -504,12 +515,19 @@ func (e *execOp) Exec(ctx context.Context, inputs []solver.Result) ([]solver.Res
504 504
 		return mounts[i].Dest < mounts[j].Dest
505 505
 	})
506 506
 
507
+	extraHosts, err := parseExtraHosts(e.op.Meta.ExtraHosts)
508
+	if err != nil {
509
+		return nil, err
510
+	}
511
+
507 512
 	meta := executor.Meta{
508 513
 		Args:           e.op.Meta.Args,
509 514
 		Env:            e.op.Meta.Env,
510 515
 		Cwd:            e.op.Meta.Cwd,
511 516
 		User:           e.op.Meta.User,
512 517
 		ReadonlyRootFS: readonlyRootFS,
518
+		ExtraHosts:     extraHosts,
519
+		NetMode:        e.op.Network,
513 520
 	}
514 521
 
515 522
 	if e.op.Meta.ProxyEnv != nil {
... ...
@@ -657,3 +675,18 @@ func (r *cacheRef) Release(ctx context.Context) error {
657 657
 	}
658 658
 	return nil
659 659
 }
660
+
661
+func parseExtraHosts(ips []*pb.HostIP) ([]executor.HostIP, error) {
662
+	out := make([]executor.HostIP, len(ips))
663
+	for i, hip := range ips {
664
+		ip := net.ParseIP(hip.IP)
665
+		if ip == nil {
666
+			return nil, errors.Errorf("failed to parse IP %s", hip.IP)
667
+		}
668
+		out[i] = executor.HostIP{
669
+			IP:   ip,
670
+			Host: hip.Host,
671
+		}
672
+	}
673
+	return out, nil
674
+}
... ...
@@ -7,11 +7,14 @@ import (
7 7
 	"github.com/moby/buildkit/cache"
8 8
 	"github.com/moby/buildkit/cache/remotecache"
9 9
 	"github.com/moby/buildkit/client"
10
+	controlgateway "github.com/moby/buildkit/control/gateway"
10 11
 	"github.com/moby/buildkit/exporter"
11 12
 	"github.com/moby/buildkit/frontend"
13
+	"github.com/moby/buildkit/frontend/gateway"
12 14
 	"github.com/moby/buildkit/identity"
13 15
 	"github.com/moby/buildkit/session"
14 16
 	"github.com/moby/buildkit/solver"
17
+	"github.com/moby/buildkit/util/entitlements"
15 18
 	"github.com/moby/buildkit/util/progress"
16 19
 	"github.com/moby/buildkit/worker"
17 20
 	digest "github.com/opencontainers/go-digest"
... ...
@@ -19,6 +22,8 @@ import (
19 19
 	"github.com/pkg/errors"
20 20
 )
21 21
 
22
+const keyEntitlements = "llb.entitlements"
23
+
22 24
 type ExporterRequest struct {
23 25
 	Exporter        exporter.ExporterInstance
24 26
 	CacheExporter   remotecache.Exporter
... ...
@@ -29,18 +34,22 @@ type ExporterRequest struct {
29 29
 type ResolveWorkerFunc func() (worker.Worker, error)
30 30
 
31 31
 type Solver struct {
32
+	workerController     *worker.Controller
32 33
 	solver               *solver.Solver
33 34
 	resolveWorker        ResolveWorkerFunc
34 35
 	frontends            map[string]frontend.Frontend
35 36
 	resolveCacheImporter remotecache.ResolveCacheImporterFunc
36 37
 	platforms            []specs.Platform
38
+	gatewayForwarder     *controlgateway.GatewayForwarder
37 39
 }
38 40
 
39
-func New(wc *worker.Controller, f map[string]frontend.Frontend, cache solver.CacheManager, resolveCI remotecache.ResolveCacheImporterFunc) (*Solver, error) {
41
+func New(wc *worker.Controller, f map[string]frontend.Frontend, cache solver.CacheManager, resolveCI remotecache.ResolveCacheImporterFunc, gatewayForwarder *controlgateway.GatewayForwarder) (*Solver, error) {
40 42
 	s := &Solver{
43
+		workerController:     wc,
41 44
 		resolveWorker:        defaultResolver(wc),
42 45
 		frontends:            f,
43 46
 		resolveCacheImporter: resolveCI,
47
+		gatewayForwarder:     gatewayForwarder,
44 48
 	}
45 49
 
46 50
 	// executing is currently only allowed on default worker
... ...
@@ -78,7 +87,7 @@ func (s *Solver) Bridge(b solver.Builder) frontend.FrontendLLBBridge {
78 78
 	}
79 79
 }
80 80
 
81
-func (s *Solver) Solve(ctx context.Context, id string, req frontend.SolveRequest, exp ExporterRequest) (*client.SolveResponse, error) {
81
+func (s *Solver) Solve(ctx context.Context, id string, req frontend.SolveRequest, exp ExporterRequest, ent []entitlements.Entitlement) (*client.SolveResponse, error) {
82 82
 	j, err := s.solver.NewJob(id)
83 83
 	if err != nil {
84 84
 		return nil, err
... ...
@@ -86,12 +95,38 @@ func (s *Solver) Solve(ctx context.Context, id string, req frontend.SolveRequest
86 86
 
87 87
 	defer j.Discard()
88 88
 
89
-	j.SessionID = session.FromContext(ctx)
90
-
91
-	res, err := s.Bridge(j).Solve(ctx, req)
89
+	set, err := entitlements.WhiteList(ent, supportedEntitlements())
92 90
 	if err != nil {
93 91
 		return nil, err
94 92
 	}
93
+	j.SetValue(keyEntitlements, set)
94
+
95
+	j.SessionID = session.FromContext(ctx)
96
+
97
+	var res *frontend.Result
98
+	if s.gatewayForwarder != nil && req.Definition == nil && req.Frontend == "" {
99
+		fwd := gateway.NewBridgeForwarder(ctx, s.Bridge(j), s.workerController)
100
+		if err := s.gatewayForwarder.RegisterBuild(ctx, id, fwd); err != nil {
101
+			return nil, err
102
+		}
103
+		defer s.gatewayForwarder.UnregisterBuild(ctx, id)
104
+
105
+		var err error
106
+		select {
107
+		case <-fwd.Done():
108
+			res, err = fwd.Result()
109
+		case <-ctx.Done():
110
+			err = ctx.Err()
111
+		}
112
+		if err != nil {
113
+			return nil, err
114
+		}
115
+	} else {
116
+		res, err = s.Bridge(j).Solve(ctx, req)
117
+		if err != nil {
118
+			return nil, err
119
+		}
120
+	}
95 121
 
96 122
 	defer func() {
97 123
 		res.EachRef(func(ref solver.CachedResult) error {
... ...
@@ -105,6 +140,9 @@ func (s *Solver) Solve(ctx context.Context, id string, req frontend.SolveRequest
105 105
 		inp := exporter.Source{
106 106
 			Metadata: res.Metadata,
107 107
 		}
108
+		if inp.Metadata == nil {
109
+			inp.Metadata = make(map[string][]byte)
110
+		}
108 111
 		if res := res.Ref; res != nil {
109 112
 			workerRef, ok := res.Sys().(*worker.WorkerRef)
110 113
 			if !ok {
... ...
@@ -164,6 +202,7 @@ func (s *Solver) Solve(ctx context.Context, id string, req frontend.SolveRequest
164 164
 func (s *Solver) Status(ctx context.Context, id string, statusChan chan *client.SolveStatus) error {
165 165
 	j, err := s.solver.Get(id)
166 166
 	if err != nil {
167
+		close(statusChan)
167 168
 		return err
168 169
 	}
169 170
 	return j.Status(ctx, statusChan)
... ...
@@ -229,3 +268,31 @@ func notifyCompleted(ctx context.Context, v *client.Vertex, err error, cached bo
229 229
 	}
230 230
 	pw.Write(v.Digest.String(), *v)
231 231
 }
232
+
233
+var AllowNetworkHostUnstable = false // TODO: enable in constructor
234
+
235
+func supportedEntitlements() []entitlements.Entitlement {
236
+	out := []entitlements.Entitlement{} // nil means no filter
237
+	if AllowNetworkHostUnstable {
238
+		out = append(out, entitlements.EntitlementNetworkHost)
239
+	}
240
+	return out
241
+}
242
+
243
+func loadEntitlements(b solver.Builder) (entitlements.Set, error) {
244
+	var ent entitlements.Set = map[entitlements.Entitlement]struct{}{}
245
+	err := b.EachValue(context.TODO(), keyEntitlements, func(v interface{}) error {
246
+		set, ok := v.(entitlements.Set)
247
+		if !ok {
248
+			return errors.Errorf("invalid entitlements %T", v)
249
+		}
250
+		for k := range set {
251
+			ent[k] = struct{}{}
252
+		}
253
+		return nil
254
+	})
255
+	if err != nil {
256
+		return nil, err
257
+	}
258
+	return ent, nil
259
+}
... ...
@@ -7,6 +7,7 @@ import (
7 7
 	"github.com/moby/buildkit/solver"
8 8
 	"github.com/moby/buildkit/solver/pb"
9 9
 	"github.com/moby/buildkit/source"
10
+	"github.com/moby/buildkit/util/entitlements"
10 11
 	digest "github.com/opencontainers/go-digest"
11 12
 	specs "github.com/opencontainers/image-spec/specs-go/v1"
12 13
 	"github.com/pkg/errors"
... ...
@@ -99,6 +100,25 @@ func RuntimePlatforms(p []specs.Platform) LoadOpt {
99 99
 	}
100 100
 }
101 101
 
102
+func ValidateEntitlements(ent entitlements.Set) LoadOpt {
103
+	return func(op *pb.Op, _ *pb.OpMetadata, opt *solver.VertexOptions) error {
104
+		switch op := op.Op.(type) {
105
+		case *pb.Op_Exec:
106
+			if op.Exec.Network == pb.NetMode_HOST {
107
+				if !ent.Allowed(entitlements.EntitlementNetworkHost) {
108
+					return errors.Errorf("%s is not allowed", entitlements.EntitlementNetworkHost)
109
+				}
110
+			}
111
+			if op.Exec.Network == pb.NetMode_NONE {
112
+				if !ent.Allowed(entitlements.EntitlementNetworkNone) {
113
+					return errors.Errorf("%s is not allowed", entitlements.EntitlementNetworkNone)
114
+				}
115
+			}
116
+		}
117
+		return nil
118
+	}
119
+}
120
+
102 121
 func Load(def *pb.Definition, opts ...LoadOpt) (solver.Edge, error) {
103 122
 	return loadLLB(def, func(dgst digest.Digest, pbOp *pb.Op, load func(digest.Digest) (solver.Vertex, error)) (solver.Vertex, error) {
104 123
 		opMetadata := def.Metadata[dgst]
... ...
@@ -32,6 +32,7 @@ const (
32 32
 
33 33
 	CapExecMetaBase          apicaps.CapID = "exec.meta.base"
34 34
 	CapExecMetaProxy         apicaps.CapID = "exec.meta.proxyenv"
35
+	CapExecMetaNetwork       apicaps.CapID = "exec.meta.network"
35 36
 	CapExecMountBind         apicaps.CapID = "exec.mount.bind"
36 37
 	CapExecMountCache        apicaps.CapID = "exec.mount.cache"
37 38
 	CapExecMountCacheSharing apicaps.CapID = "exec.mount.cache.sharing"
... ...
@@ -163,6 +164,12 @@ func init() {
163 163
 	})
164 164
 
165 165
 	Caps.Init(apicaps.Cap{
166
+		ID:      CapExecMetaNetwork,
167
+		Enabled: true,
168
+		Status:  apicaps.CapStatusExperimental,
169
+	})
170
+
171
+	Caps.Init(apicaps.Cap{
166 172
 		ID:      CapExecMountBind,
167 173
 		Enabled: true,
168 174
 		Status:  apicaps.CapStatusExperimental,
... ...
@@ -29,6 +29,7 @@
29 29
 		ProxyEnv
30 30
 		WorkerConstraints
31 31
 		Definition
32
+		HostIP
32 33
 */
33 34
 package pb
34 35
 
... ...
@@ -53,6 +54,30 @@ var _ = math.Inf
53 53
 // proto package needs to be updated.
54 54
 const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
55 55
 
56
+type NetMode int32
57
+
58
+const (
59
+	NetMode_UNSET NetMode = 0
60
+	NetMode_HOST  NetMode = 1
61
+	NetMode_NONE  NetMode = 2
62
+)
63
+
64
+var NetMode_name = map[int32]string{
65
+	0: "UNSET",
66
+	1: "HOST",
67
+	2: "NONE",
68
+}
69
+var NetMode_value = map[string]int32{
70
+	"UNSET": 0,
71
+	"HOST":  1,
72
+	"NONE":  2,
73
+}
74
+
75
+func (x NetMode) String() string {
76
+	return proto.EnumName(NetMode_name, int32(x))
77
+}
78
+func (NetMode) EnumDescriptor() ([]byte, []int) { return fileDescriptorOps, []int{0} }
79
+
56 80
 // MountType defines a type of a mount from a supported set
57 81
 type MountType int32
58 82
 
... ...
@@ -82,7 +107,7 @@ var MountType_value = map[string]int32{
82 82
 func (x MountType) String() string {
83 83
 	return proto.EnumName(MountType_name, int32(x))
84 84
 }
85
-func (MountType) EnumDescriptor() ([]byte, []int) { return fileDescriptorOps, []int{0} }
85
+func (MountType) EnumDescriptor() ([]byte, []int) { return fileDescriptorOps, []int{1} }
86 86
 
87 87
 // CacheSharingOpt defines different sharing modes for cache mount
88 88
 type CacheSharingOpt int32
... ...
@@ -110,7 +135,7 @@ var CacheSharingOpt_value = map[string]int32{
110 110
 func (x CacheSharingOpt) String() string {
111 111
 	return proto.EnumName(CacheSharingOpt_name, int32(x))
112 112
 }
113
-func (CacheSharingOpt) EnumDescriptor() ([]byte, []int) { return fileDescriptorOps, []int{1} }
113
+func (CacheSharingOpt) EnumDescriptor() ([]byte, []int) { return fileDescriptorOps, []int{2} }
114 114
 
115 115
 // Op represents a vertex of the LLB DAG.
116 116
 type Op struct {
... ...
@@ -387,8 +412,9 @@ func (*Input) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{2}
387 387
 
388 388
 // ExecOp executes a command in a container.
389 389
 type ExecOp struct {
390
-	Meta   *Meta    `protobuf:"bytes,1,opt,name=meta" json:"meta,omitempty"`
391
-	Mounts []*Mount `protobuf:"bytes,2,rep,name=mounts" json:"mounts,omitempty"`
390
+	Meta    *Meta    `protobuf:"bytes,1,opt,name=meta" json:"meta,omitempty"`
391
+	Mounts  []*Mount `protobuf:"bytes,2,rep,name=mounts" json:"mounts,omitempty"`
392
+	Network NetMode  `protobuf:"varint,3,opt,name=network,proto3,enum=pb.NetMode" json:"network,omitempty"`
392 393
 }
393 394
 
394 395
 func (m *ExecOp) Reset()                    { *m = ExecOp{} }
... ...
@@ -410,15 +436,23 @@ func (m *ExecOp) GetMounts() []*Mount {
410 410
 	return nil
411 411
 }
412 412
 
413
+func (m *ExecOp) GetNetwork() NetMode {
414
+	if m != nil {
415
+		return m.Network
416
+	}
417
+	return NetMode_UNSET
418
+}
419
+
413 420
 // Meta is a set of arguments for ExecOp.
414 421
 // Meta is unrelated to LLB metadata.
415 422
 // FIXME: rename (ExecContext? ExecArgs?)
416 423
 type Meta struct {
417
-	Args     []string  `protobuf:"bytes,1,rep,name=args" json:"args,omitempty"`
418
-	Env      []string  `protobuf:"bytes,2,rep,name=env" json:"env,omitempty"`
419
-	Cwd      string    `protobuf:"bytes,3,opt,name=cwd,proto3" json:"cwd,omitempty"`
420
-	User     string    `protobuf:"bytes,4,opt,name=user,proto3" json:"user,omitempty"`
421
-	ProxyEnv *ProxyEnv `protobuf:"bytes,5,opt,name=proxy_env,json=proxyEnv" json:"proxy_env,omitempty"`
424
+	Args       []string  `protobuf:"bytes,1,rep,name=args" json:"args,omitempty"`
425
+	Env        []string  `protobuf:"bytes,2,rep,name=env" json:"env,omitempty"`
426
+	Cwd        string    `protobuf:"bytes,3,opt,name=cwd,proto3" json:"cwd,omitempty"`
427
+	User       string    `protobuf:"bytes,4,opt,name=user,proto3" json:"user,omitempty"`
428
+	ProxyEnv   *ProxyEnv `protobuf:"bytes,5,opt,name=proxy_env,json=proxyEnv" json:"proxy_env,omitempty"`
429
+	ExtraHosts []*HostIP `protobuf:"bytes,6,rep,name=extraHosts" json:"extraHosts,omitempty"`
422 430
 }
423 431
 
424 432
 func (m *Meta) Reset()                    { *m = Meta{} }
... ...
@@ -461,6 +495,13 @@ func (m *Meta) GetProxyEnv() *ProxyEnv {
461 461
 	return nil
462 462
 }
463 463
 
464
+func (m *Meta) GetExtraHosts() []*HostIP {
465
+	if m != nil {
466
+		return m.ExtraHosts
467
+	}
468
+	return nil
469
+}
470
+
464 471
 // Mount specifies how to mount an input Op as a filesystem.
465 472
 type Mount struct {
466 473
 	Input     InputIndex  `protobuf:"varint,1,opt,name=input,proto3,customtype=InputIndex" json:"input"`
... ...
@@ -864,6 +905,30 @@ func (m *Definition) GetMetadata() map[github_com_opencontainers_go_digest.Diges
864 864
 	return nil
865 865
 }
866 866
 
867
+type HostIP struct {
868
+	Host string `protobuf:"bytes,1,opt,name=Host,proto3" json:"Host,omitempty"`
869
+	IP   string `protobuf:"bytes,2,opt,name=IP,proto3" json:"IP,omitempty"`
870
+}
871
+
872
+func (m *HostIP) Reset()                    { *m = HostIP{} }
873
+func (m *HostIP) String() string            { return proto.CompactTextString(m) }
874
+func (*HostIP) ProtoMessage()               {}
875
+func (*HostIP) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{18} }
876
+
877
+func (m *HostIP) GetHost() string {
878
+	if m != nil {
879
+		return m.Host
880
+	}
881
+	return ""
882
+}
883
+
884
+func (m *HostIP) GetIP() string {
885
+	if m != nil {
886
+		return m.IP
887
+	}
888
+	return ""
889
+}
890
+
867 891
 func init() {
868 892
 	proto.RegisterType((*Op)(nil), "pb.Op")
869 893
 	proto.RegisterType((*Platform)(nil), "pb.Platform")
... ...
@@ -883,6 +948,8 @@ func init() {
883 883
 	proto.RegisterType((*ProxyEnv)(nil), "pb.ProxyEnv")
884 884
 	proto.RegisterType((*WorkerConstraints)(nil), "pb.WorkerConstraints")
885 885
 	proto.RegisterType((*Definition)(nil), "pb.Definition")
886
+	proto.RegisterType((*HostIP)(nil), "pb.HostIP")
887
+	proto.RegisterEnum("pb.NetMode", NetMode_name, NetMode_value)
886 888
 	proto.RegisterEnum("pb.MountType", MountType_name, MountType_value)
887 889
 	proto.RegisterEnum("pb.CacheSharingOpt", CacheSharingOpt_name, CacheSharingOpt_value)
888 890
 }
... ...
@@ -1122,6 +1189,11 @@ func (m *ExecOp) MarshalTo(dAtA []byte) (int, error) {
1122 1122
 			i += n
1123 1123
 		}
1124 1124
 	}
1125
+	if m.Network != 0 {
1126
+		dAtA[i] = 0x18
1127
+		i++
1128
+		i = encodeVarintOps(dAtA, i, uint64(m.Network))
1129
+	}
1125 1130
 	return i, nil
1126 1131
 }
1127 1132
 
... ...
@@ -1192,6 +1264,18 @@ func (m *Meta) MarshalTo(dAtA []byte) (int, error) {
1192 1192
 		}
1193 1193
 		i += n9
1194 1194
 	}
1195
+	if len(m.ExtraHosts) > 0 {
1196
+		for _, msg := range m.ExtraHosts {
1197
+			dAtA[i] = 0x32
1198
+			i++
1199
+			i = encodeVarintOps(dAtA, i, uint64(msg.Size()))
1200
+			n, err := msg.MarshalTo(dAtA[i:])
1201
+			if err != nil {
1202
+				return 0, err
1203
+			}
1204
+			i += n
1205
+		}
1206
+	}
1195 1207
 	return i, nil
1196 1208
 }
1197 1209
 
... ...
@@ -1790,6 +1874,36 @@ func (m *Definition) MarshalTo(dAtA []byte) (int, error) {
1790 1790
 	return i, nil
1791 1791
 }
1792 1792
 
1793
+func (m *HostIP) Marshal() (dAtA []byte, err error) {
1794
+	size := m.Size()
1795
+	dAtA = make([]byte, size)
1796
+	n, err := m.MarshalTo(dAtA)
1797
+	if err != nil {
1798
+		return nil, err
1799
+	}
1800
+	return dAtA[:n], nil
1801
+}
1802
+
1803
+func (m *HostIP) MarshalTo(dAtA []byte) (int, error) {
1804
+	var i int
1805
+	_ = i
1806
+	var l int
1807
+	_ = l
1808
+	if len(m.Host) > 0 {
1809
+		dAtA[i] = 0xa
1810
+		i++
1811
+		i = encodeVarintOps(dAtA, i, uint64(len(m.Host)))
1812
+		i += copy(dAtA[i:], m.Host)
1813
+	}
1814
+	if len(m.IP) > 0 {
1815
+		dAtA[i] = 0x12
1816
+		i++
1817
+		i = encodeVarintOps(dAtA, i, uint64(len(m.IP)))
1818
+		i += copy(dAtA[i:], m.IP)
1819
+	}
1820
+	return i, nil
1821
+}
1822
+
1793 1823
 func encodeVarintOps(dAtA []byte, offset int, v uint64) int {
1794 1824
 	for v >= 1<<7 {
1795 1825
 		dAtA[offset] = uint8(v&0x7f | 0x80)
... ...
@@ -1912,6 +2026,9 @@ func (m *ExecOp) Size() (n int) {
1912 1912
 			n += 1 + l + sovOps(uint64(l))
1913 1913
 		}
1914 1914
 	}
1915
+	if m.Network != 0 {
1916
+		n += 1 + sovOps(uint64(m.Network))
1917
+	}
1915 1918
 	return n
1916 1919
 }
1917 1920
 
... ...
@@ -1942,6 +2059,12 @@ func (m *Meta) Size() (n int) {
1942 1942
 		l = m.ProxyEnv.Size()
1943 1943
 		n += 1 + l + sovOps(uint64(l))
1944 1944
 	}
1945
+	if len(m.ExtraHosts) > 0 {
1946
+		for _, e := range m.ExtraHosts {
1947
+			l = e.Size()
1948
+			n += 1 + l + sovOps(uint64(l))
1949
+		}
1950
+	}
1945 1951
 	return n
1946 1952
 }
1947 1953
 
... ...
@@ -2197,6 +2320,20 @@ func (m *Definition) Size() (n int) {
2197 2197
 	return n
2198 2198
 }
2199 2199
 
2200
+func (m *HostIP) Size() (n int) {
2201
+	var l int
2202
+	_ = l
2203
+	l = len(m.Host)
2204
+	if l > 0 {
2205
+		n += 1 + l + sovOps(uint64(l))
2206
+	}
2207
+	l = len(m.IP)
2208
+	if l > 0 {
2209
+		n += 1 + l + sovOps(uint64(l))
2210
+	}
2211
+	return n
2212
+}
2213
+
2200 2214
 func sovOps(x uint64) (n int) {
2201 2215
 	for {
2202 2216
 		n++
... ...
@@ -2871,6 +3008,25 @@ func (m *ExecOp) Unmarshal(dAtA []byte) error {
2871 2871
 				return err
2872 2872
 			}
2873 2873
 			iNdEx = postIndex
2874
+		case 3:
2875
+			if wireType != 0 {
2876
+				return fmt.Errorf("proto: wrong wireType = %d for field Network", wireType)
2877
+			}
2878
+			m.Network = 0
2879
+			for shift := uint(0); ; shift += 7 {
2880
+				if shift >= 64 {
2881
+					return ErrIntOverflowOps
2882
+				}
2883
+				if iNdEx >= l {
2884
+					return io.ErrUnexpectedEOF
2885
+				}
2886
+				b := dAtA[iNdEx]
2887
+				iNdEx++
2888
+				m.Network |= (NetMode(b) & 0x7F) << shift
2889
+				if b < 0x80 {
2890
+					break
2891
+				}
2892
+			}
2874 2893
 		default:
2875 2894
 			iNdEx = preIndex
2876 2895
 			skippy, err := skipOps(dAtA[iNdEx:])
... ...
@@ -3070,6 +3226,37 @@ func (m *Meta) Unmarshal(dAtA []byte) error {
3070 3070
 				return err
3071 3071
 			}
3072 3072
 			iNdEx = postIndex
3073
+		case 6:
3074
+			if wireType != 2 {
3075
+				return fmt.Errorf("proto: wrong wireType = %d for field ExtraHosts", wireType)
3076
+			}
3077
+			var msglen int
3078
+			for shift := uint(0); ; shift += 7 {
3079
+				if shift >= 64 {
3080
+					return ErrIntOverflowOps
3081
+				}
3082
+				if iNdEx >= l {
3083
+					return io.ErrUnexpectedEOF
3084
+				}
3085
+				b := dAtA[iNdEx]
3086
+				iNdEx++
3087
+				msglen |= (int(b) & 0x7F) << shift
3088
+				if b < 0x80 {
3089
+					break
3090
+				}
3091
+			}
3092
+			if msglen < 0 {
3093
+				return ErrInvalidLengthOps
3094
+			}
3095
+			postIndex := iNdEx + msglen
3096
+			if postIndex > l {
3097
+				return io.ErrUnexpectedEOF
3098
+			}
3099
+			m.ExtraHosts = append(m.ExtraHosts, &HostIP{})
3100
+			if err := m.ExtraHosts[len(m.ExtraHosts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
3101
+				return err
3102
+			}
3103
+			iNdEx = postIndex
3073 3104
 		default:
3074 3105
 			iNdEx = preIndex
3075 3106
 			skippy, err := skipOps(dAtA[iNdEx:])
... ...
@@ -5260,6 +5447,114 @@ func (m *Definition) Unmarshal(dAtA []byte) error {
5260 5260
 	}
5261 5261
 	return nil
5262 5262
 }
5263
+func (m *HostIP) Unmarshal(dAtA []byte) error {
5264
+	l := len(dAtA)
5265
+	iNdEx := 0
5266
+	for iNdEx < l {
5267
+		preIndex := iNdEx
5268
+		var wire uint64
5269
+		for shift := uint(0); ; shift += 7 {
5270
+			if shift >= 64 {
5271
+				return ErrIntOverflowOps
5272
+			}
5273
+			if iNdEx >= l {
5274
+				return io.ErrUnexpectedEOF
5275
+			}
5276
+			b := dAtA[iNdEx]
5277
+			iNdEx++
5278
+			wire |= (uint64(b) & 0x7F) << shift
5279
+			if b < 0x80 {
5280
+				break
5281
+			}
5282
+		}
5283
+		fieldNum := int32(wire >> 3)
5284
+		wireType := int(wire & 0x7)
5285
+		if wireType == 4 {
5286
+			return fmt.Errorf("proto: HostIP: wiretype end group for non-group")
5287
+		}
5288
+		if fieldNum <= 0 {
5289
+			return fmt.Errorf("proto: HostIP: illegal tag %d (wire type %d)", fieldNum, wire)
5290
+		}
5291
+		switch fieldNum {
5292
+		case 1:
5293
+			if wireType != 2 {
5294
+				return fmt.Errorf("proto: wrong wireType = %d for field Host", wireType)
5295
+			}
5296
+			var stringLen uint64
5297
+			for shift := uint(0); ; shift += 7 {
5298
+				if shift >= 64 {
5299
+					return ErrIntOverflowOps
5300
+				}
5301
+				if iNdEx >= l {
5302
+					return io.ErrUnexpectedEOF
5303
+				}
5304
+				b := dAtA[iNdEx]
5305
+				iNdEx++
5306
+				stringLen |= (uint64(b) & 0x7F) << shift
5307
+				if b < 0x80 {
5308
+					break
5309
+				}
5310
+			}
5311
+			intStringLen := int(stringLen)
5312
+			if intStringLen < 0 {
5313
+				return ErrInvalidLengthOps
5314
+			}
5315
+			postIndex := iNdEx + intStringLen
5316
+			if postIndex > l {
5317
+				return io.ErrUnexpectedEOF
5318
+			}
5319
+			m.Host = string(dAtA[iNdEx:postIndex])
5320
+			iNdEx = postIndex
5321
+		case 2:
5322
+			if wireType != 2 {
5323
+				return fmt.Errorf("proto: wrong wireType = %d for field IP", wireType)
5324
+			}
5325
+			var stringLen uint64
5326
+			for shift := uint(0); ; shift += 7 {
5327
+				if shift >= 64 {
5328
+					return ErrIntOverflowOps
5329
+				}
5330
+				if iNdEx >= l {
5331
+					return io.ErrUnexpectedEOF
5332
+				}
5333
+				b := dAtA[iNdEx]
5334
+				iNdEx++
5335
+				stringLen |= (uint64(b) & 0x7F) << shift
5336
+				if b < 0x80 {
5337
+					break
5338
+				}
5339
+			}
5340
+			intStringLen := int(stringLen)
5341
+			if intStringLen < 0 {
5342
+				return ErrInvalidLengthOps
5343
+			}
5344
+			postIndex := iNdEx + intStringLen
5345
+			if postIndex > l {
5346
+				return io.ErrUnexpectedEOF
5347
+			}
5348
+			m.IP = string(dAtA[iNdEx:postIndex])
5349
+			iNdEx = postIndex
5350
+		default:
5351
+			iNdEx = preIndex
5352
+			skippy, err := skipOps(dAtA[iNdEx:])
5353
+			if err != nil {
5354
+				return err
5355
+			}
5356
+			if skippy < 0 {
5357
+				return ErrInvalidLengthOps
5358
+			}
5359
+			if (iNdEx + skippy) > l {
5360
+				return io.ErrUnexpectedEOF
5361
+			}
5362
+			iNdEx += skippy
5363
+		}
5364
+	}
5365
+
5366
+	if iNdEx > l {
5367
+		return io.ErrUnexpectedEOF
5368
+	}
5369
+	return nil
5370
+}
5263 5371
 func skipOps(dAtA []byte) (n int, err error) {
5264 5372
 	l := len(dAtA)
5265 5373
 	iNdEx := 0
... ...
@@ -5368,88 +5663,94 @@ var (
5368 5368
 func init() { proto.RegisterFile("ops.proto", fileDescriptorOps) }
5369 5369
 
5370 5370
 var fileDescriptorOps = []byte{
5371
-	// 1328 bytes of a gzipped FileDescriptorProto
5372
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xcb, 0x6e, 0xdb, 0x46,
5373
-	0x17, 0x36, 0xa9, 0x8b, 0xc9, 0x43, 0xdb, 0xd1, 0x3f, 0xb9, 0xfc, 0xfa, 0xfd, 0xa7, 0xb6, 0xcb,
5374
-	0x14, 0x85, 0x13, 0xc7, 0x12, 0xa0, 0x00, 0x49, 0xd0, 0x45, 0x50, 0xeb, 0x12, 0x58, 0x4d, 0x53,
5375
-	0x05, 0x23, 0xc3, 0x5d, 0x06, 0x14, 0x35, 0x92, 0x89, 0x48, 0x1c, 0x82, 0x1c, 0xa6, 0xd6, 0xa2,
5376
-	0x5d, 0xe4, 0x09, 0x0a, 0x14, 0xe8, 0xbe, 0x2f, 0xd0, 0x37, 0xe8, 0x3e, 0xcb, 0x6e, 0xdb, 0x45,
5377
-	0x5a, 0xa4, 0x2f, 0x52, 0x9c, 0x99, 0xe1, 0x25, 0x97, 0xa2, 0x09, 0xda, 0x15, 0x67, 0xce, 0xe5,
5378
-	0x9b, 0x33, 0xdf, 0x39, 0x67, 0x0e, 0xc1, 0xe6, 0x51, 0xd2, 0x8a, 0x62, 0x2e, 0x38, 0x31, 0xa3,
5379
-	0xc9, 0xf6, 0xe1, 0x3c, 0x10, 0x67, 0xe9, 0xa4, 0xe5, 0xf3, 0x65, 0x7b, 0xce, 0xe7, 0xbc, 0x2d,
5380
-	0x55, 0x93, 0x74, 0x26, 0x77, 0x72, 0x23, 0x57, 0xca, 0xc5, 0xfd, 0xc1, 0x04, 0x73, 0x14, 0x91,
5381
-	0x0f, 0xa1, 0x1e, 0x84, 0x51, 0x2a, 0x92, 0xa6, 0xb1, 0x57, 0xd9, 0x77, 0x3a, 0x76, 0x2b, 0x9a,
5382
-	0xb4, 0x86, 0x28, 0xa1, 0x5a, 0x41, 0xf6, 0xa0, 0xca, 0xce, 0x99, 0xdf, 0x34, 0xf7, 0x8c, 0x7d,
5383
-	0xa7, 0x03, 0x68, 0x30, 0x38, 0x67, 0xfe, 0x28, 0x3a, 0x5e, 0xa3, 0x52, 0x43, 0x3e, 0x86, 0x7a,
5384
-	0xc2, 0xd3, 0xd8, 0x67, 0xcd, 0x8a, 0xb4, 0xd9, 0x40, 0x9b, 0xb1, 0x94, 0x48, 0x2b, 0xad, 0x45,
5385
-	0x24, 0x9f, 0x47, 0xab, 0x66, 0xb5, 0x40, 0xea, 0xf1, 0x68, 0xa5, 0x90, 0x50, 0x43, 0xae, 0x41,
5386
-	0x6d, 0x92, 0x06, 0x8b, 0x69, 0xb3, 0x26, 0x4d, 0x1c, 0x34, 0xe9, 0xa2, 0x40, 0xda, 0x28, 0x1d,
5387
-	0xd9, 0x07, 0x2b, 0x5a, 0x78, 0x62, 0xc6, 0xe3, 0x65, 0x13, 0x8a, 0x03, 0x1f, 0x69, 0x19, 0xcd,
5388
-	0xb5, 0xe4, 0x0e, 0x38, 0x3e, 0x0f, 0x13, 0x11, 0x7b, 0x41, 0x28, 0x92, 0xa6, 0x23, 0x8d, 0x2f,
5389
-	0xa3, 0xf1, 0x97, 0x3c, 0x7e, 0xc2, 0xe2, 0x5e, 0xa1, 0xa4, 0x65, 0xcb, 0x6e, 0x15, 0x4c, 0x1e,
5390
-	0xb9, 0xdf, 0x1b, 0x60, 0x65, 0xa8, 0xc4, 0x85, 0x8d, 0xa3, 0xd8, 0x3f, 0x0b, 0x04, 0xf3, 0x45,
5391
-	0x1a, 0xb3, 0xa6, 0xb1, 0x67, 0xec, 0xdb, 0xf4, 0x15, 0x19, 0xd9, 0x02, 0x73, 0x34, 0x96, 0x44,
5392
-	0xd9, 0xd4, 0x1c, 0x8d, 0x49, 0x13, 0xd6, 0x4f, 0xbd, 0x38, 0xf0, 0x42, 0x21, 0x99, 0xb1, 0x69,
5393
-	0xb6, 0x25, 0x57, 0xc1, 0x1e, 0x8d, 0x4f, 0x59, 0x9c, 0x04, 0x3c, 0x94, 0x7c, 0xd8, 0xb4, 0x10,
5394
-	0x90, 0x1d, 0x80, 0xd1, 0xf8, 0x3e, 0xf3, 0x10, 0x34, 0x69, 0xd6, 0xf6, 0x2a, 0xfb, 0x36, 0x2d,
5395
-	0x49, 0xdc, 0x6f, 0xa0, 0x26, 0x73, 0x44, 0x3e, 0x83, 0xfa, 0x34, 0x98, 0xb3, 0x44, 0xa8, 0x70,
5396
-	0xba, 0x9d, 0xe7, 0x2f, 0x76, 0xd7, 0x7e, 0x7d, 0xb1, 0x7b, 0xa3, 0x54, 0x0c, 0x3c, 0x62, 0xa1,
5397
-	0xcf, 0x43, 0xe1, 0x05, 0x21, 0x8b, 0x93, 0xf6, 0x9c, 0x1f, 0x2a, 0x97, 0x56, 0x5f, 0x7e, 0xa8,
5398
-	0x46, 0x20, 0xd7, 0xa1, 0x16, 0x84, 0x53, 0x76, 0x2e, 0xe3, 0xaf, 0x74, 0x2f, 0x6a, 0x28, 0x67,
5399
-	0x94, 0x8a, 0x28, 0x15, 0x43, 0x54, 0x51, 0x65, 0xe1, 0x0e, 0xa1, 0xae, 0x4a, 0x80, 0x5c, 0x85,
5400
-	0xea, 0x92, 0x09, 0x4f, 0x1e, 0xef, 0x74, 0x2c, 0xa4, 0xf6, 0x21, 0x13, 0x1e, 0x95, 0x52, 0xac,
5401
-	0xae, 0x25, 0x4f, 0x91, 0x7a, 0xb3, 0xa8, 0xae, 0x87, 0x28, 0xa1, 0x5a, 0xe1, 0x7e, 0x0d, 0x55,
5402
-	0x74, 0x20, 0x04, 0xaa, 0x5e, 0x3c, 0x57, 0x65, 0x68, 0x53, 0xb9, 0x26, 0x0d, 0xa8, 0xb0, 0xf0,
5403
-	0xa9, 0xf4, 0xb5, 0x29, 0x2e, 0x51, 0xe2, 0x7f, 0x35, 0xd5, 0x64, 0xe2, 0x12, 0xfd, 0xd2, 0x84,
5404
-	0xc5, 0x9a, 0x43, 0xb9, 0x26, 0xd7, 0xc1, 0x8e, 0x62, 0x7e, 0xbe, 0x7a, 0x8c, 0xde, 0xb5, 0x52,
5405
-	0x85, 0xa0, 0x70, 0x10, 0x3e, 0xa5, 0x56, 0xa4, 0x57, 0xee, 0x8f, 0x26, 0xd4, 0x64, 0x40, 0x64,
5406
-	0x1f, 0xaf, 0x1f, 0xa5, 0x8a, 0xc9, 0x4a, 0x97, 0xe8, 0xeb, 0x83, 0x24, 0x3a, 0xbf, 0x3d, 0x92,
5407
-	0xbe, 0x0d, 0x56, 0xc2, 0x16, 0xcc, 0x17, 0x3c, 0xd6, 0xb9, 0xce, 0xf7, 0x18, 0xce, 0x14, 0xd3,
5408
-	0xa1, 0x22, 0x94, 0x6b, 0x72, 0x00, 0x75, 0x2e, 0x39, 0x94, 0x41, 0xfe, 0x05, 0xb3, 0xda, 0x04,
5409
-	0xc1, 0x63, 0xe6, 0x4d, 0x79, 0xb8, 0x58, 0xc9, 0xd0, 0x2d, 0x9a, 0xef, 0xc9, 0x01, 0xd8, 0x92,
5410
-	0xb5, 0x93, 0x55, 0xc4, 0x9a, 0xf5, 0x3d, 0x63, 0x7f, 0xab, 0xb3, 0x99, 0x33, 0x8a, 0x42, 0x5a,
5411
-	0xe8, 0xb1, 0x4b, 0x7c, 0xcf, 0x3f, 0x63, 0xa3, 0x48, 0x34, 0x2f, 0x15, 0x1c, 0xf4, 0xb4, 0x8c,
5412
-	0xe6, 0x5a, 0x84, 0x4d, 0x98, 0x1f, 0x33, 0x81, 0xa6, 0x97, 0xa5, 0xa9, 0x84, 0x1d, 0x67, 0x42,
5413
-	0x5a, 0xe8, 0xdd, 0x21, 0x58, 0x19, 0x04, 0x96, 0xfb, 0xb0, 0xaf, 0x1b, 0xc1, 0x1c, 0xf6, 0xc9,
5414
-	0x21, 0xac, 0x27, 0x67, 0x5e, 0x1c, 0x84, 0x73, 0xc9, 0xcb, 0x56, 0xe7, 0x62, 0x7e, 0xe2, 0x58,
5415
-	0xc9, 0x11, 0x2c, 0xb3, 0x71, 0x39, 0xd8, 0xf9, 0x11, 0x6f, 0x60, 0x35, 0xa0, 0x92, 0x06, 0x53,
5416
-	0x89, 0xb3, 0x49, 0x71, 0x89, 0x92, 0x79, 0xa0, 0x72, 0xbf, 0x49, 0x71, 0x89, 0x64, 0x2f, 0xf9,
5417
-	0x94, 0x49, 0x5a, 0x37, 0xa9, 0x5c, 0x23, 0x7f, 0x3c, 0x12, 0x01, 0x0f, 0xbd, 0x45, 0xc6, 0x5f,
5418
-	0xb6, 0x77, 0xef, 0x41, 0x5d, 0xbd, 0x37, 0x64, 0x0f, 0x2a, 0x49, 0xec, 0xeb, 0x37, 0x6f, 0x2b,
5419
-	0x7b, 0x88, 0xd4, 0x93, 0x45, 0x51, 0x95, 0x27, 0xd2, 0x2c, 0x12, 0xe9, 0x52, 0x80, 0xc2, 0xec,
5420
-	0xdf, 0x29, 0x18, 0xf7, 0x3b, 0x03, 0xac, 0xec, 0xa9, 0xc4, 0xbe, 0x0f, 0xa6, 0x2c, 0x14, 0xc1,
5421
-	0x2c, 0x60, 0xb1, 0x26, 0xa3, 0x24, 0x21, 0x87, 0x50, 0xf3, 0x84, 0x88, 0xb3, 0x76, 0xfa, 0x6f,
5422
-	0xf9, 0x9d, 0x6d, 0x1d, 0xa1, 0x66, 0x10, 0x8a, 0x78, 0x45, 0x95, 0xd5, 0xf6, 0x5d, 0x80, 0x42,
5423
-	0x88, 0xfc, 0x3d, 0x61, 0x2b, 0x8d, 0x8a, 0x4b, 0x72, 0x09, 0x6a, 0x4f, 0xbd, 0x45, 0xca, 0x74,
5424
-	0x50, 0x6a, 0xf3, 0x89, 0x79, 0xd7, 0x70, 0x7f, 0x32, 0x61, 0x5d, 0xbf, 0xbb, 0xe4, 0x26, 0xac,
5425
-	0xcb, 0x77, 0x57, 0x47, 0xf4, 0xf6, 0x9b, 0x66, 0x26, 0xa4, 0x9d, 0x0f, 0x94, 0x52, 0x8c, 0x1a,
5426
-	0x4a, 0x0d, 0x16, 0x1d, 0x63, 0x31, 0x5e, 0x2a, 0x53, 0x36, 0xd3, 0x93, 0x43, 0xa6, 0xa2, 0xcf,
5427
-	0x66, 0x41, 0x18, 0x60, 0xce, 0x28, 0xaa, 0xc8, 0xcd, 0xec, 0xd6, 0x55, 0x89, 0x78, 0xa5, 0x8c,
5428
-	0xf8, 0xe6, 0xa5, 0x87, 0xe0, 0x94, 0x8e, 0x79, 0xcb, 0xad, 0x3f, 0x2a, 0xdf, 0x5a, 0x1f, 0x29,
5429
-	0xe1, 0xd4, 0xd8, 0x2b, 0x58, 0xf8, 0x07, 0xfc, 0xdd, 0x06, 0x28, 0x20, 0xdf, 0xbd, 0x52, 0xdc,
5430
-	0x67, 0x15, 0x80, 0x51, 0x84, 0x0f, 0xe2, 0xd4, 0x93, 0xef, 0xe7, 0x46, 0x30, 0x0f, 0x79, 0xcc,
5431
-	0x1e, 0xcb, 0x66, 0x95, 0xfe, 0x16, 0x75, 0x94, 0x4c, 0xf6, 0x15, 0x39, 0x02, 0x67, 0xca, 0x12,
5432
-	0x3f, 0x0e, 0x64, 0x91, 0x6b, 0xd2, 0x77, 0xf1, 0x4e, 0x05, 0x4e, 0xab, 0x5f, 0x58, 0x28, 0xae,
5433
-	0xca, 0x3e, 0xa4, 0x03, 0x1b, 0xec, 0x3c, 0xe2, 0xb1, 0xd0, 0xa7, 0xa8, 0xf1, 0x7c, 0x41, 0x0d,
5434
-	0x7a, 0x94, 0xcb, 0x93, 0xa8, 0xc3, 0x8a, 0x0d, 0xf1, 0xa0, 0xea, 0x7b, 0x91, 0x9a, 0x4d, 0x4e,
5435
-	0xa7, 0xf9, 0xda, 0x79, 0x3d, 0x2f, 0x52, 0xa4, 0x75, 0x6f, 0xe1, 0x5d, 0x9f, 0xfd, 0xb6, 0x7b,
5436
-	0x50, 0x1a, 0x48, 0x4b, 0x3e, 0x59, 0xb5, 0x65, 0xbd, 0x3c, 0x09, 0x44, 0x3b, 0x15, 0xc1, 0xa2,
5437
-	0xed, 0x45, 0x01, 0xc2, 0xa1, 0xe3, 0xb0, 0x4f, 0x25, 0xf4, 0xf6, 0x3d, 0x68, 0xbc, 0x1e, 0xf7,
5438
-	0xfb, 0xe4, 0x60, 0xfb, 0x0e, 0xd8, 0x79, 0x1c, 0x7f, 0xe7, 0x68, 0x95, 0x93, 0x77, 0x0d, 0x9c,
5439
-	0xd2, 0xbd, 0xd1, 0xf0, 0x54, 0x1a, 0x2a, 0xf6, 0xd5, 0xc6, 0x7d, 0x86, 0xff, 0x06, 0x7a, 0x8a,
5440
-	0x90, 0x0f, 0x00, 0xce, 0x84, 0x88, 0x1e, 0xcb, 0xb1, 0xa2, 0x0f, 0xb1, 0x51, 0x22, 0x2d, 0xc8,
5441
-	0x2e, 0x38, 0xb8, 0x49, 0xb4, 0x5e, 0x45, 0x2a, 0x3d, 0x12, 0x65, 0xf0, 0x7f, 0xb0, 0x67, 0xb9,
5442
-	0xbb, 0x1a, 0x1d, 0xd6, 0x2c, 0xf3, 0xfe, 0x1f, 0x58, 0x21, 0xd7, 0x3a, 0x35, 0xe5, 0xd6, 0x43,
5443
-	0x2e, 0x55, 0xee, 0x01, 0xfc, 0xe7, 0x8d, 0x1f, 0x19, 0x72, 0x05, 0xea, 0xb3, 0x60, 0x21, 0x64,
5444
-	0xbb, 0xe2, 0xe0, 0xd4, 0x3b, 0xf7, 0x17, 0x03, 0xa0, 0x68, 0x2d, 0x64, 0x04, 0xfb, 0x0e, 0x6d,
5445
-	0x36, 0x54, 0x9f, 0x2d, 0xc0, 0x5a, 0xea, 0x0c, 0xea, 0x3a, 0xba, 0xfa, 0x6a, 0x3b, 0xb6, 0xb2,
5446
-	0x04, 0xab, 0xdc, 0x76, 0x74, 0x6e, 0xdf, 0xe7, 0x67, 0x23, 0x3f, 0x61, 0xfb, 0x01, 0x6c, 0xbe,
5447
-	0x02, 0xf7, 0x8e, 0x9d, 0x5a, 0x54, 0x59, 0x29, 0x65, 0x37, 0x3e, 0x05, 0x3b, 0x1f, 0x82, 0xc4,
5448
-	0x82, 0x6a, 0x77, 0xf8, 0x45, 0xbf, 0xb1, 0x46, 0x00, 0xea, 0xe3, 0x41, 0x8f, 0x0e, 0x4e, 0x1a,
5449
-	0x06, 0x59, 0x87, 0xca, 0x78, 0x7c, 0xdc, 0x30, 0x89, 0x0d, 0xb5, 0xde, 0x51, 0xef, 0x78, 0xd0,
5450
-	0xa8, 0xe0, 0xf2, 0xe4, 0xe1, 0xa3, 0xfb, 0xe3, 0x46, 0xf5, 0xc6, 0x6d, 0xb8, 0xf0, 0xda, 0xa0,
5451
-	0x92, 0xde, 0xc7, 0x47, 0x74, 0x80, 0x48, 0x0e, 0xac, 0x3f, 0xa2, 0xc3, 0xd3, 0xa3, 0x93, 0x41,
5452
-	0xc3, 0x40, 0xc5, 0xe7, 0xa3, 0xde, 0x83, 0x41, 0xbf, 0x61, 0x76, 0x1b, 0xcf, 0x5f, 0xee, 0x18,
5453
-	0x3f, 0xbf, 0xdc, 0x31, 0x7e, 0x7f, 0xb9, 0x63, 0x7c, 0xfb, 0xc7, 0xce, 0xda, 0xa4, 0x2e, 0x7f,
5454
-	0xb0, 0x6f, 0xfd, 0x19, 0x00, 0x00, 0xff, 0xff, 0xa3, 0xba, 0x5c, 0x6e, 0xa0, 0x0b, 0x00, 0x00,
5371
+	// 1415 bytes of a gzipped FileDescriptorProto
5372
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x57, 0xcd, 0x6f, 0x1b, 0x45,
5373
+	0x14, 0x8f, 0xd7, 0x9f, 0xfb, 0x9c, 0xa4, 0x66, 0xfa, 0x81, 0x09, 0x25, 0x09, 0x5b, 0x40, 0x69,
5374
+	0xd2, 0x38, 0x92, 0x2b, 0xb5, 0x15, 0x87, 0x8a, 0xf8, 0xa3, 0x8a, 0x29, 0x89, 0xa3, 0x71, 0x08,
5375
+	0xc7, 0x6a, 0xb3, 0x1e, 0x3b, 0xab, 0x38, 0x3b, 0xab, 0xdd, 0x71, 0x1b, 0x5f, 0x38, 0xf4, 0x2f,
5376
+	0x40, 0x42, 0xe2, 0xce, 0x91, 0x0b, 0xff, 0x01, 0xf7, 0x1e, 0xb9, 0xc2, 0xa1, 0xa0, 0xf2, 0x8f,
5377
+	0xa0, 0xf7, 0x66, 0xd6, 0xbb, 0xfd, 0x40, 0xb4, 0x82, 0x93, 0xdf, 0xbc, 0xf7, 0x9b, 0xdf, 0xcc,
5378
+	0xfc, 0xde, 0x9b, 0x79, 0x6b, 0xb0, 0x65, 0x18, 0x37, 0xc2, 0x48, 0x2a, 0xc9, 0xac, 0xf0, 0x64,
5379
+	0x65, 0x7b, 0xec, 0xab, 0xd3, 0xe9, 0x49, 0xc3, 0x93, 0xe7, 0x3b, 0x63, 0x39, 0x96, 0x3b, 0x14,
5380
+	0x3a, 0x99, 0x8e, 0x68, 0x44, 0x03, 0xb2, 0xf4, 0x14, 0xe7, 0x47, 0x0b, 0xac, 0x7e, 0xc8, 0x3e,
5381
+	0x86, 0x92, 0x1f, 0x84, 0x53, 0x15, 0xd7, 0x73, 0xeb, 0xf9, 0x8d, 0x6a, 0xd3, 0x6e, 0x84, 0x27,
5382
+	0x8d, 0x1e, 0x7a, 0xb8, 0x09, 0xb0, 0x75, 0x28, 0x88, 0x0b, 0xe1, 0xd5, 0xad, 0xf5, 0xdc, 0x46,
5383
+	0xb5, 0x09, 0x08, 0xe8, 0x5e, 0x08, 0xaf, 0x1f, 0xee, 0x2d, 0x70, 0x8a, 0xb0, 0xcf, 0xa0, 0x14,
5384
+	0xcb, 0x69, 0xe4, 0x89, 0x7a, 0x9e, 0x30, 0x8b, 0x88, 0x19, 0x90, 0x87, 0x50, 0x26, 0x8a, 0x4c,
5385
+	0x9e, 0x0c, 0x67, 0xf5, 0x42, 0xca, 0xd4, 0x96, 0xe1, 0x4c, 0x33, 0x61, 0x84, 0xdd, 0x80, 0xe2,
5386
+	0xc9, 0xd4, 0x9f, 0x0c, 0xeb, 0x45, 0x82, 0x54, 0x11, 0xd2, 0x42, 0x07, 0x61, 0x74, 0x8c, 0x6d,
5387
+	0x40, 0x25, 0x9c, 0xb8, 0x6a, 0x24, 0xa3, 0xf3, 0x3a, 0xa4, 0x0b, 0x1e, 0x1a, 0x1f, 0x9f, 0x47,
5388
+	0xd9, 0x5d, 0xa8, 0x7a, 0x32, 0x88, 0x55, 0xe4, 0xfa, 0x81, 0x8a, 0xeb, 0x55, 0x02, 0x5f, 0x45,
5389
+	0xf0, 0x37, 0x32, 0x3a, 0x13, 0x51, 0x3b, 0x0d, 0xf2, 0x2c, 0xb2, 0x55, 0x00, 0x4b, 0x86, 0xce,
5390
+	0x0f, 0x39, 0xa8, 0x24, 0xac, 0xcc, 0x81, 0xc5, 0xdd, 0xc8, 0x3b, 0xf5, 0x95, 0xf0, 0xd4, 0x34,
5391
+	0x12, 0xf5, 0xdc, 0x7a, 0x6e, 0xc3, 0xe6, 0x2f, 0xf9, 0xd8, 0x32, 0x58, 0xfd, 0x01, 0x09, 0x65,
5392
+	0x73, 0xab, 0x3f, 0x60, 0x75, 0x28, 0x1f, 0xbb, 0x91, 0xef, 0x06, 0x8a, 0x94, 0xb1, 0x79, 0x32,
5393
+	0x64, 0xd7, 0xc1, 0xee, 0x0f, 0x8e, 0x45, 0x14, 0xfb, 0x32, 0x20, 0x3d, 0x6c, 0x9e, 0x3a, 0xd8,
5394
+	0x2a, 0x40, 0x7f, 0xf0, 0x40, 0xb8, 0x48, 0x1a, 0xd7, 0x8b, 0xeb, 0xf9, 0x0d, 0x9b, 0x67, 0x3c,
5395
+	0xce, 0xb7, 0x50, 0xa4, 0x1c, 0xb1, 0x2f, 0xa1, 0x34, 0xf4, 0xc7, 0x22, 0x56, 0x7a, 0x3b, 0xad,
5396
+	0xe6, 0xb3, 0xe7, 0x6b, 0x0b, 0xbf, 0x3f, 0x5f, 0xdb, 0xcc, 0x14, 0x83, 0x0c, 0x45, 0xe0, 0xc9,
5397
+	0x40, 0xb9, 0x7e, 0x20, 0xa2, 0x78, 0x67, 0x2c, 0xb7, 0xf5, 0x94, 0x46, 0x87, 0x7e, 0xb8, 0x61,
5398
+	0x60, 0x37, 0xa1, 0xe8, 0x07, 0x43, 0x71, 0x41, 0xfb, 0xcf, 0xb7, 0x2e, 0x1b, 0xaa, 0x6a, 0x7f,
5399
+	0xaa, 0xc2, 0xa9, 0xea, 0x61, 0x88, 0x6b, 0x84, 0x13, 0x42, 0x49, 0x97, 0x00, 0xbb, 0x0e, 0x85,
5400
+	0x73, 0xa1, 0x5c, 0x5a, 0xbe, 0xda, 0xac, 0xa0, 0xb4, 0xfb, 0x42, 0xb9, 0x9c, 0xbc, 0x58, 0x5d,
5401
+	0xe7, 0x72, 0x8a, 0xd2, 0x5b, 0x69, 0x75, 0xed, 0xa3, 0x87, 0x9b, 0x00, 0xfb, 0x14, 0xca, 0x81,
5402
+	0x50, 0x4f, 0x64, 0x74, 0x46, 0x12, 0x2d, 0xeb, 0x9c, 0x1f, 0x08, 0xb5, 0x2f, 0x87, 0x82, 0x27,
5403
+	0x31, 0xe7, 0xa7, 0x1c, 0x14, 0x90, 0x98, 0x31, 0x28, 0xb8, 0xd1, 0x58, 0x97, 0xab, 0xcd, 0xc9,
5404
+	0x66, 0x35, 0xc8, 0x8b, 0xe0, 0x31, 0xad, 0x61, 0x73, 0x34, 0xd1, 0xe3, 0x3d, 0x19, 0x1a, 0xd1,
5405
+	0xd1, 0xc4, 0x79, 0xd3, 0x58, 0x44, 0x46, 0x6b, 0xb2, 0xd9, 0x4d, 0xb0, 0xc3, 0x48, 0x5e, 0xcc,
5406
+	0x1e, 0xe1, 0xec, 0x62, 0xa6, 0x92, 0xd0, 0xd9, 0x0d, 0x1e, 0xf3, 0x4a, 0x68, 0x2c, 0xb6, 0x09,
5407
+	0x20, 0x2e, 0x54, 0xe4, 0xee, 0xc9, 0x58, 0xc5, 0xf5, 0x12, 0x9d, 0x86, 0x0a, 0x18, 0x1d, 0xbd,
5408
+	0x43, 0x9e, 0x89, 0x3a, 0x3f, 0x5b, 0x50, 0xa4, 0x43, 0xb2, 0x0d, 0x94, 0x34, 0x9c, 0xea, 0xec,
5409
+	0xe4, 0x5b, 0xcc, 0x48, 0x0a, 0x94, 0xbc, 0xb9, 0xa2, 0x98, 0xc8, 0x15, 0xa8, 0xc4, 0x62, 0x22,
5410
+	0x3c, 0x25, 0x23, 0x53, 0x3f, 0xf3, 0x31, 0x6e, 0x7d, 0x88, 0x29, 0xd6, 0xa7, 0x21, 0x9b, 0x6d,
5411
+	0x41, 0x49, 0x52, 0x5e, 0xe8, 0x40, 0xff, 0x90, 0x2d, 0x03, 0x41, 0xf2, 0x48, 0xb8, 0x43, 0x19,
5412
+	0x4c, 0x66, 0x74, 0xcc, 0x0a, 0x9f, 0x8f, 0xd9, 0x16, 0xd8, 0x94, 0x89, 0xa3, 0x59, 0x28, 0xea,
5413
+	0x25, 0xca, 0xc0, 0xd2, 0x3c, 0x4b, 0xe8, 0xe4, 0x69, 0x1c, 0x6f, 0x9e, 0xe7, 0x7a, 0xa7, 0xa2,
5414
+	0x1f, 0xaa, 0xfa, 0x95, 0x54, 0xaf, 0xb6, 0xf1, 0xf1, 0x79, 0x14, 0x69, 0x63, 0xe1, 0x45, 0x42,
5415
+	0x21, 0xf4, 0x2a, 0x41, 0x89, 0x76, 0x90, 0x38, 0x79, 0x1a, 0x77, 0x7a, 0x50, 0x49, 0x28, 0xf0,
5416
+	0x0a, 0xf5, 0x3a, 0xe6, 0x72, 0x59, 0xbd, 0x0e, 0xdb, 0x86, 0x72, 0x7c, 0xea, 0x46, 0x7e, 0x30,
5417
+	0x26, 0x5d, 0x96, 0x9b, 0x97, 0xe7, 0x2b, 0x0e, 0xb4, 0x1f, 0xc9, 0x12, 0x8c, 0x23, 0xc1, 0x9e,
5418
+	0x2f, 0xf1, 0x1a, 0x57, 0x0d, 0xf2, 0x53, 0x7f, 0x48, 0x3c, 0x4b, 0x1c, 0x4d, 0xf4, 0x8c, 0x7d,
5419
+	0x5d, 0x27, 0x4b, 0x1c, 0x4d, 0x14, 0xfb, 0x5c, 0x0e, 0x05, 0xc9, 0xba, 0xc4, 0xc9, 0x46, 0xfd,
5420
+	0x64, 0xa8, 0x7c, 0x19, 0xb8, 0x93, 0x44, 0xbf, 0x64, 0xec, 0xdc, 0x87, 0x92, 0x7e, 0xc3, 0xd8,
5421
+	0x3a, 0xe4, 0xe3, 0xc8, 0x33, 0xef, 0xe8, 0x72, 0xf2, 0xb8, 0xe9, 0x67, 0x90, 0x63, 0x68, 0x9e,
5422
+	0x48, 0x2b, 0x4d, 0xa4, 0xc3, 0x01, 0x52, 0xd8, 0xff, 0x53, 0x30, 0xce, 0xf7, 0x39, 0xa8, 0x24,
5423
+	0xcf, 0x2f, 0xbe, 0x25, 0xfe, 0x50, 0x04, 0xca, 0x1f, 0xf9, 0x22, 0x32, 0x62, 0x64, 0x3c, 0x6c,
5424
+	0x1b, 0x8a, 0xae, 0x52, 0x51, 0x72, 0x45, 0xdf, 0xcf, 0xbe, 0xdd, 0x8d, 0x5d, 0x8c, 0x74, 0x03,
5425
+	0x15, 0xcd, 0xb8, 0x46, 0xad, 0xdc, 0x03, 0x48, 0x9d, 0xa8, 0xdf, 0x99, 0x98, 0x19, 0x56, 0x34,
5426
+	0xd9, 0x15, 0x28, 0x3e, 0x76, 0x27, 0x53, 0x61, 0x36, 0xa5, 0x07, 0x9f, 0x5b, 0xf7, 0x72, 0xce,
5427
+	0x2f, 0x16, 0x94, 0xcd, 0x5b, 0xce, 0x6e, 0x41, 0x99, 0xde, 0x72, 0xb3, 0xa3, 0x37, 0x9f, 0x34,
5428
+	0x81, 0xb0, 0x9d, 0x79, 0x93, 0xca, 0xec, 0xd1, 0x50, 0xe9, 0x66, 0x65, 0xf6, 0x98, 0xb6, 0xac,
5429
+	0xfc, 0x50, 0x8c, 0x4c, 0x37, 0xa2, 0x54, 0x74, 0xc4, 0xc8, 0x0f, 0x7c, 0xcc, 0x19, 0xc7, 0x10,
5430
+	0xbb, 0x95, 0x9c, 0xba, 0x40, 0x8c, 0xd7, 0xb2, 0x8c, 0xaf, 0x1f, 0xba, 0x07, 0xd5, 0xcc, 0x32,
5431
+	0x6f, 0x38, 0xf5, 0x27, 0xd9, 0x53, 0x9b, 0x25, 0x89, 0x4e, 0xb7, 0xd2, 0x54, 0x85, 0xff, 0xa0,
5432
+	0xdf, 0x1d, 0x80, 0x94, 0xf2, 0xed, 0x2b, 0xc5, 0x79, 0x9a, 0x07, 0xe8, 0x87, 0xf8, 0x78, 0x0e,
5433
+	0x5d, 0x7a, 0x93, 0x17, 0xfd, 0x71, 0x20, 0x23, 0xf1, 0x88, 0x2e, 0x2b, 0xcd, 0xaf, 0xf0, 0xaa,
5434
+	0xf6, 0xd1, 0xbd, 0x62, 0xbb, 0x50, 0x1d, 0x8a, 0xd8, 0x8b, 0x7c, 0x2a, 0x72, 0x23, 0xfa, 0x1a,
5435
+	0x9e, 0x29, 0xe5, 0x69, 0x74, 0x52, 0x84, 0xd6, 0x2a, 0x3b, 0x87, 0x35, 0x61, 0x51, 0x5c, 0x84,
5436
+	0x32, 0x52, 0x66, 0x15, 0xdd, 0xf2, 0x2f, 0xe9, 0x8f, 0x07, 0xf4, 0xd3, 0x4a, 0xbc, 0x2a, 0xd2,
5437
+	0x01, 0x73, 0xa1, 0xe0, 0xb9, 0xa1, 0xee, 0x77, 0xd5, 0x66, 0xfd, 0x95, 0xf5, 0xda, 0x6e, 0xa8,
5438
+	0x45, 0x6b, 0xdd, 0xc6, 0xb3, 0x3e, 0xfd, 0x63, 0x6d, 0x2b, 0xd3, 0xe4, 0xce, 0xe5, 0xc9, 0x6c,
5439
+	0x87, 0xea, 0xe5, 0xcc, 0x57, 0x3b, 0x53, 0xe5, 0x4f, 0x76, 0xdc, 0xd0, 0x47, 0x3a, 0x9c, 0xd8,
5440
+	0xeb, 0x70, 0xa2, 0x5e, 0xb9, 0x0f, 0xb5, 0x57, 0xf7, 0xfd, 0x2e, 0x39, 0x58, 0xb9, 0x0b, 0xf6,
5441
+	0x7c, 0x1f, 0xff, 0x36, 0xb1, 0x92, 0x4d, 0xde, 0x0d, 0xa8, 0x66, 0xce, 0x8d, 0xc0, 0x63, 0x02,
5442
+	0x6a, 0xf5, 0xf5, 0xc0, 0x79, 0x8a, 0xdf, 0x1b, 0x49, 0xc7, 0xf9, 0x08, 0xe0, 0x54, 0xa9, 0xf0,
5443
+	0x11, 0xb5, 0x20, 0xb3, 0x88, 0x8d, 0x1e, 0x42, 0xb0, 0x35, 0xa8, 0xe2, 0x20, 0x36, 0x71, 0xbd,
5444
+	0x53, 0x9a, 0x11, 0x6b, 0xc0, 0x87, 0x60, 0x8f, 0xe6, 0xd3, 0x75, 0xeb, 0xa8, 0x8c, 0x92, 0xd9,
5445
+	0x1f, 0x40, 0x25, 0x90, 0x26, 0xa6, 0x3b, 0x62, 0x39, 0x90, 0x14, 0x72, 0xb6, 0xe0, 0xbd, 0xd7,
5446
+	0x3e, 0x8e, 0xd8, 0x35, 0x28, 0x8d, 0xfc, 0x89, 0xa2, 0xeb, 0x8a, 0x4d, 0xd6, 0x8c, 0x9c, 0xdf,
5447
+	0x72, 0x00, 0xe9, 0xd5, 0x42, 0x45, 0xf0, 0xde, 0x21, 0x66, 0x51, 0xdf, 0xb3, 0x09, 0x54, 0xce,
5448
+	0x4d, 0x06, 0x4d, 0x1d, 0x5d, 0x7f, 0xf9, 0x3a, 0x36, 0x92, 0x04, 0xeb, 0xdc, 0x36, 0x4d, 0x6e,
5449
+	0xdf, 0xe5, 0x03, 0x66, 0xbe, 0xc2, 0xca, 0x43, 0x58, 0x7a, 0x89, 0xee, 0x2d, 0x6f, 0x6a, 0x5a,
5450
+	0x65, 0xd9, 0x94, 0xdd, 0x82, 0x92, 0x6e, 0xee, 0xf8, 0x6e, 0xa3, 0x65, 0x68, 0xc8, 0xa6, 0xde,
5451
+	0x72, 0x98, 0x7c, 0xea, 0xf5, 0x0e, 0x37, 0x37, 0xa0, 0x6c, 0x3e, 0x5a, 0x98, 0x0d, 0xc5, 0xaf,
5452
+	0x0f, 0x06, 0xdd, 0xa3, 0xda, 0x02, 0xab, 0x40, 0x61, 0xaf, 0x3f, 0x38, 0xaa, 0xe5, 0xd0, 0x3a,
5453
+	0xe8, 0x1f, 0x74, 0x6b, 0xd6, 0xe6, 0x17, 0x60, 0xcf, 0x9b, 0x2b, 0xba, 0x5b, 0xbd, 0x83, 0x4e,
5454
+	0x6d, 0x81, 0x01, 0x94, 0x06, 0xdd, 0x36, 0xef, 0x22, 0xb8, 0x0c, 0xf9, 0xc1, 0x60, 0xaf, 0x66,
5455
+	0x21, 0x55, 0x7b, 0xb7, 0xbd, 0xd7, 0xad, 0xe5, 0xd1, 0x3c, 0xda, 0x3f, 0x7c, 0x30, 0xa8, 0x15,
5456
+	0x36, 0xef, 0xc0, 0xa5, 0x57, 0x1a, 0x20, 0xcd, 0xde, 0xdb, 0xe5, 0x5d, 0x64, 0xaa, 0x42, 0xf9,
5457
+	0x90, 0xf7, 0x8e, 0x77, 0x8f, 0xba, 0xb5, 0x1c, 0x06, 0xbe, 0xea, 0xb7, 0x1f, 0x76, 0x3b, 0x35,
5458
+	0xab, 0x55, 0x7b, 0xf6, 0x62, 0x35, 0xf7, 0xeb, 0x8b, 0xd5, 0xdc, 0x9f, 0x2f, 0x56, 0x73, 0xdf,
5459
+	0xfd, 0xb5, 0xba, 0x70, 0x52, 0xa2, 0x3f, 0x03, 0xb7, 0xff, 0x0e, 0x00, 0x00, 0xff, 0xff, 0x8c,
5460
+	0x1e, 0x1e, 0x98, 0x4c, 0x0c, 0x00, 0x00,
5455 5461
 }
... ...
@@ -41,6 +41,7 @@ message Input {
41 41
 message ExecOp {
42 42
 	Meta meta = 1;
43 43
 	repeated Mount mounts = 2;
44
+	NetMode network = 3;
44 45
 }
45 46
 
46 47
 // Meta is a set of arguments for ExecOp.
... ...
@@ -52,6 +53,13 @@ message Meta {
52 52
 	string cwd = 3;
53 53
 	string user = 4;
54 54
 	ProxyEnv proxy_env = 5;
55
+	repeated HostIP extraHosts = 6;
56
+}
57
+
58
+enum NetMode {
59
+	UNSET = 0; // sandbox
60
+	HOST = 1;
61
+	NONE = 2;
55 62
 }
56 63
 
57 64
 // Mount specifies how to mount an input Op as a filesystem.
... ...
@@ -181,3 +189,8 @@ message Definition {
181 181
 	// 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.
182 182
 	map<string, OpMetadata> metadata = 2 [(gogoproto.castkey) = "github.com/opencontainers/go-digest.Digest", (gogoproto.nullable) = false];
183 183
 }
184
+
185
+message HostIP {
186
+	string Host = 1;
187
+	string IP = 2;
188
+}
184 189
\ No newline at end of file
185 190
new file mode 100644
... ...
@@ -0,0 +1,70 @@
0
+package entitlements
1
+
2
+import "github.com/pkg/errors"
3
+
4
+type Entitlement string
5
+
6
+const (
7
+	EntitlementSecurityConfined   Entitlement = "security.confined"
8
+	EntitlementSecurityUnconfined Entitlement = "security.unconfined" // unimplemented
9
+	EntitlementNetworkHost        Entitlement = "network.host"
10
+	EntitlementNetworkNone        Entitlement = "network.none"
11
+)
12
+
13
+var all = map[Entitlement]struct{}{
14
+	EntitlementSecurityConfined:   {},
15
+	EntitlementSecurityUnconfined: {},
16
+	EntitlementNetworkHost:        {},
17
+	EntitlementNetworkNone:        {},
18
+}
19
+
20
+var defaults = map[Entitlement]struct{}{
21
+	EntitlementSecurityConfined: {},
22
+	EntitlementNetworkNone:      {},
23
+}
24
+
25
+func Parse(s string) (Entitlement, error) {
26
+	_, ok := all[Entitlement(s)]
27
+	if !ok {
28
+		return "", errors.Errorf("unknown entitlement %s", s)
29
+	}
30
+	return Entitlement(s), nil
31
+}
32
+
33
+func WhiteList(allowed, supported []Entitlement) (Set, error) {
34
+	m := map[Entitlement]struct{}{}
35
+
36
+	var supm Set
37
+	if supported != nil {
38
+		var err error
39
+		supm, err = WhiteList(supported, nil)
40
+		if err != nil { // should not happen
41
+			return nil, err
42
+		}
43
+	}
44
+
45
+	for _, e := range allowed {
46
+		e, err := Parse(string(e))
47
+		if err != nil {
48
+			return nil, err
49
+		}
50
+		if supported != nil {
51
+			if !supm.Allowed(e) {
52
+				return nil, errors.Errorf("entitlement %s is not allowed", e)
53
+			}
54
+		}
55
+		m[e] = struct{}{}
56
+	}
57
+
58
+	for e := range defaults {
59
+		m[e] = struct{}{}
60
+	}
61
+	return Set(m), nil
62
+}
63
+
64
+type Set map[Entitlement]struct{}
65
+
66
+func (s Set) Allowed(e Entitlement) bool {
67
+	_, ok := s[e]
68
+	return ok
69
+}
0 70
new file mode 100644
... ...
@@ -0,0 +1,22 @@
0
+package network
1
+
2
+// Provider interface for Network
3
+type Provider interface {
4
+	NewInterface() (Interface, error)
5
+	Release(Interface) error
6
+}
7
+
8
+// Interface of network for workers
9
+type Interface interface {
10
+	// Set the pid with network interace namespace
11
+	Set(int) error
12
+	// Removes the network interface
13
+	Remove(int) error
14
+}
15
+
16
+// NetworkOpts hold network options
17
+type NetworkOpts struct {
18
+	Type          string
19
+	CNIConfigPath string
20
+	CNIPluginPath string
21
+}
... ...
@@ -6,7 +6,7 @@ github.com/davecgh/go-spew v1.1.0
6 6
 github.com/pmezard/go-difflib v1.0.0
7 7
 golang.org/x/sys 1b2967e3c290b7c545b3db0deeda16e9be4f98a2
8 8
 
9
-github.com/containerd/containerd a88b6319614de846458750ff882723479ca7b1a1
9
+github.com/containerd/containerd v1.2.0-beta.0
10 10
 github.com/containerd/typeurl a93fcdb778cd272c6e9b3028b2f42d813e785d40
11 11
 golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c
12 12
 github.com/sirupsen/logrus v1.0.0
... ...
@@ -21,9 +21,9 @@ github.com/opencontainers/image-spec v1.0.1
21 21
 github.com/opencontainers/runc ad0f5255060d36872be04de22f8731f38ef2d7b1
22 22
 github.com/Microsoft/go-winio v0.4.7
23 23
 github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
24
-github.com/opencontainers/runtime-spec v1.0.1
25
-github.com/containerd/go-runc f271fa2021de855d4d918dbef83c5fe19db1bdd5
26
-github.com/containerd/console 5d1b48d6114b8c9666f0c8b916f871af97b0a761
24
+github.com/opencontainers/runtime-spec d810dbc60d8c5aeeb3d054bd1132fab2121968ce # v1.0.1-43-gd810dbc
25
+github.com/containerd/go-runc edcf3de1f4971445c42d61f20d506b30612aa031
26
+github.com/containerd/console 4d8a41f4ce5b9bae77c41786ea2458330f43f081
27 27
 google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
28 28
 golang.org/x/text 19e51611da83d6be54ddafce4a4af510cb3e9ea4
29 29
 github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9