Browse code

Update containerd to v1 beta3

Signed-off-by: Brian Goff <cpuguy83@gmail.com>

Brian Goff authored on 2017/11/11 05:44:10
Showing 77 changed files
... ...
@@ -4,7 +4,7 @@ TOMLV_COMMIT=9baf8a8a9f2ed20a8e54160840c492f937eeaf9a
4 4
 
5 5
 # When updating RUNC_COMMIT, also update runc in vendor.conf accordingly
6 6
 RUNC_COMMIT=0351df1c5a66838d0c392b4ac4cf9450de844e2d
7
-CONTAINERD_COMMIT=992280e8e265f491f7a624ab82f3e238be086e49
7
+CONTAINERD_COMMIT=v1.0.0-beta.3
8 8
 TINI_COMMIT=949e6facb77383876aeff8a6944dde66b3089574
9 9
 LIBNETWORK_COMMIT=7b2b1feb1de4817d522cc372af149ff48d25028e
10 10
 VNDR_COMMIT=a6e196d8b4b0cbbdc29aebdb20c59ac6926bb384
... ...
@@ -31,8 +31,8 @@ type rpcUser struct {
31 31
 
32 32
 func (u rpcUser) Apply(r Remote) error {
33 33
 	if remote, ok := r.(*remote); ok {
34
-		remote.GRPC.Uid = u.uid
35
-		remote.GRPC.Gid = u.gid
34
+		remote.GRPC.UID = u.uid
35
+		remote.GRPC.GID = u.gid
36 36
 		return nil
37 37
 	}
38 38
 	return fmt.Errorf("WithRemoteAddr option not supported for this remote")
... ...
@@ -103,7 +103,7 @@ github.com/googleapis/gax-go da06d194a00e19ce00d9011a13931c3f6f6887c7
103 103
 google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
104 104
 
105 105
 # containerd
106
-github.com/containerd/containerd 992280e8e265f491f7a624ab82f3e238be086e49
106
+github.com/containerd/containerd v1.0.0-beta.3
107 107
 github.com/containerd/fifo fbfb6a11ec671efbe94ad1c12c2e98773f19e1e6
108 108
 github.com/containerd/continuity 35d55c5e8dd23b32037d56cf97174aff3efdfa83
109 109
 github.com/containerd/cgroups f7dd103d3e4e696aa67152f6b4ddd1779a3455a9
... ...
@@ -1,4 +1,4 @@
1
-Attribution-ShareAlike 4.0 International
1
+Attribution 4.0 International
2 2
 
3 3
 =======================================================================
4 4
 
... ...
@@ -54,18 +54,16 @@ exhaustive, and do not form part of our licenses.
54 54
 
55 55
 =======================================================================
56 56
 
57
-Creative Commons Attribution-ShareAlike 4.0 International Public
58
-License
57
+Creative Commons Attribution 4.0 International Public License
59 58
 
60 59
 By exercising the Licensed Rights (defined below), You accept and agree
61 60
 to be bound by the terms and conditions of this Creative Commons
62
-Attribution-ShareAlike 4.0 International Public License ("Public
63
-License"). To the extent this Public License may be interpreted as a
64
-contract, You are granted the Licensed Rights in consideration of Your
65
-acceptance of these terms and conditions, and the Licensor grants You
66
-such rights in consideration of benefits the Licensor receives from
67
-making the Licensed Material available under these terms and
68
-conditions.
61
+Attribution 4.0 International Public License ("Public License"). To the
62
+extent this Public License may be interpreted as a contract, You are
63
+granted the Licensed Rights in consideration of Your acceptance of
64
+these terms and conditions, and the Licensor grants You such rights in
65
+consideration of benefits the Licensor receives from making the
66
+Licensed Material available under these terms and conditions.
69 67
 
70 68
 
71 69
 Section 1 -- Definitions.
... ...
@@ -84,11 +82,7 @@ Section 1 -- Definitions.
84 84
      and Similar Rights in Your contributions to Adapted Material in
85 85
      accordance with the terms and conditions of this Public License.
86 86
 
87
-  c. BY-SA Compatible License means a license listed at
88
-     creativecommons.org/compatiblelicenses, approved by Creative
89
-     Commons as essentially the equivalent of this Public License.
90
-
91
-  d. Copyright and Similar Rights means copyright and/or similar rights
87
+  c. Copyright and Similar Rights means copyright and/or similar rights
92 88
      closely related to copyright including, without limitation,
93 89
      performance, broadcast, sound recording, and Sui Generis Database
94 90
      Rights, without regard to how the rights are labeled or
... ...
@@ -96,33 +90,29 @@ Section 1 -- Definitions.
96 96
      specified in Section 2(b)(1)-(2) are not Copyright and Similar
97 97
      Rights.
98 98
 
99
-  e. Effective Technological Measures means those measures that, in the
99
+  d. Effective Technological Measures means those measures that, in the
100 100
      absence of proper authority, may not be circumvented under laws
101 101
      fulfilling obligations under Article 11 of the WIPO Copyright
102 102
      Treaty adopted on December 20, 1996, and/or similar international
103 103
      agreements.
104 104
 
105
-  f. Exceptions and Limitations means fair use, fair dealing, and/or
105
+  e. Exceptions and Limitations means fair use, fair dealing, and/or
106 106
      any other exception or limitation to Copyright and Similar Rights
107 107
      that applies to Your use of the Licensed Material.
108 108
 
109
-  g. License Elements means the license attributes listed in the name
110
-     of a Creative Commons Public License. The License Elements of this
111
-     Public License are Attribution and ShareAlike.
112
-
113
-  h. Licensed Material means the artistic or literary work, database,
109
+  f. Licensed Material means the artistic or literary work, database,
114 110
      or other material to which the Licensor applied this Public
115 111
      License.
116 112
 
117
-  i. Licensed Rights means the rights granted to You subject to the
113
+  g. Licensed Rights means the rights granted to You subject to the
118 114
      terms and conditions of this Public License, which are limited to
119 115
      all Copyright and Similar Rights that apply to Your use of the
120 116
      Licensed Material and that the Licensor has authority to license.
121 117
 
122
-  j. Licensor means the individual(s) or entity(ies) granting rights
118
+  h. Licensor means the individual(s) or entity(ies) granting rights
123 119
      under this Public License.
124 120
 
125
-  k. Share means to provide material to the public by any means or
121
+  i. Share means to provide material to the public by any means or
126 122
      process that requires permission under the Licensed Rights, such
127 123
      as reproduction, public display, public performance, distribution,
128 124
      dissemination, communication, or importation, and to make material
... ...
@@ -130,13 +120,13 @@ Section 1 -- Definitions.
130 130
      public may access the material from a place and at a time
131 131
      individually chosen by them.
132 132
 
133
-  l. Sui Generis Database Rights means rights other than copyright
133
+  j. Sui Generis Database Rights means rights other than copyright
134 134
      resulting from Directive 96/9/EC of the European Parliament and of
135 135
      the Council of 11 March 1996 on the legal protection of databases,
136 136
      as amended and/or succeeded, as well as other essentially
137 137
      equivalent rights anywhere in the world.
138 138
 
139
-  m. You means the individual or entity exercising the Licensed Rights
139
+  k. You means the individual or entity exercising the Licensed Rights
140 140
      under this Public License. Your has a corresponding meaning.
141 141
 
142 142
 
... ...
@@ -182,13 +172,7 @@ Section 2 -- Scope.
182 182
                Licensed Rights under the terms and conditions of this
183 183
                Public License.
184 184
 
185
-            b. Additional offer from the Licensor -- Adapted Material.
186
-               Every recipient of Adapted Material from You
187
-               automatically receives an offer from the Licensor to
188
-               exercise the Licensed Rights in the Adapted Material
189
-               under the conditions of the Adapter's License You apply.
190
-
191
-            c. No downstream restrictions. You may not offer or impose
185
+            b. No downstream restrictions. You may not offer or impose
192 186
                any additional or different terms or conditions on, or
193 187
                apply any Effective Technological Measures to, the
194 188
                Licensed Material if doing so restricts exercise of the
... ...
@@ -270,24 +254,9 @@ following conditions.
270 270
           information required by Section 3(a)(1)(A) to the extent
271 271
           reasonably practicable.
272 272
 
273
-  b. ShareAlike.
274
-
275
-     In addition to the conditions in Section 3(a), if You Share
276
-     Adapted Material You produce, the following conditions also apply.
277
-
278
-       1. The Adapter's License You apply must be a Creative Commons
279
-          license with the same License Elements, this version or
280
-          later, or a BY-SA Compatible License.
281
-
282
-       2. You must include the text of, or the URI or hyperlink to, the
283
-          Adapter's License You apply. You may satisfy this condition
284
-          in any reasonable manner based on the medium, means, and
285
-          context in which You Share Adapted Material.
286
-
287
-       3. You may not offer or impose any additional or different terms
288
-          or conditions on, or apply any Effective Technological
289
-          Measures to, Adapted Material that restrict exercise of the
290
-          rights granted under the Adapter's License You apply.
273
+       4. If You Share Adapted Material You produce, the Adapter's
274
+          License You apply must not prevent recipients of the Adapted
275
+          Material from complying with this Public License.
291 276
 
292 277
 
293 278
 Section 4 -- Sui Generis Database Rights.
... ...
@@ -302,9 +271,8 @@ apply to Your use of the Licensed Material:
302 302
   b. if You include all or a substantial portion of the database
303 303
      contents in a database in which You have Sui Generis Database
304 304
      Rights, then the database in which You have Sui Generis Database
305
-     Rights (but not its individual contents) is Adapted Material,
305
+     Rights (but not its individual contents) is Adapted Material; and
306 306
 
307
-     including for purposes of Section 3(b); and
308 307
   c. You must comply with the conditions in Section 3(a) if You Share
309 308
      all or a substantial portion of the contents of the database.
310 309
 
... ...
@@ -407,11 +375,13 @@ Section 8 -- Interpretation.
407 407
 
408 408
 =======================================================================
409 409
 
410
-Creative Commons is not a party to its public licenses.
411
-Notwithstanding, Creative Commons may elect to apply one of its public
412
-licenses to material it publishes and in those instances will be
413
-considered the "Licensor." Except for the limited purpose of indicating
414
-that material is shared under a Creative Commons public license or as
410
+Creative Commons is not a party to its public
411
+licenses. Notwithstanding, Creative Commons may elect to apply one of
412
+its public licenses to material it publishes and in those instances
413
+will be considered the “Licensor.” The text of the Creative Commons
414
+public licenses is dedicated to the public domain under the CC0 Public
415
+Domain Dedication. Except for the limited purpose of indicating that
416
+material is shared under a Creative Commons public license or as
415 417
 otherwise permitted by the Creative Commons policies published at
416 418
 creativecommons.org/policies, Creative Commons does not authorize the
417 419
 use of the trademark "Creative Commons" or any other trademark or logo
... ...
@@ -419,7 +389,7 @@ of Creative Commons without its prior written consent including,
419 419
 without limitation, in connection with any unauthorized modifications
420 420
 to any of its public licenses or any other arrangements,
421 421
 understandings, or agreements concerning use of licensed material. For
422
-the avoidance of doubt, this paragraph does not form part of the public
423
-licenses.
422
+the avoidance of doubt, this paragraph does not form part of the
423
+public licenses.
424 424
 
425 425
 Creative Commons may be contacted at creativecommons.org.
... ...
@@ -198,11 +198,10 @@ For sync communication we have a community slack with a #containerd channel that
198 198
 
199 199
 __If you are reporting a security issue, please reach out discreetly at security@containerd.io__.
200 200
 
201
-## Copyright and license
202
-
203
-Copyright ©2016-2017 Docker, Inc. All rights reserved, except as follows. Code
204
-is released under the Apache 2.0 license. The README.md file, and files in the
205
-"docs" folder are licensed under the Creative Commons Attribution 4.0
206
-International License under the terms and conditions set forth in the file
207
-"LICENSE.docs". You may obtain a duplicate copy of the same license, titled
208
-CC-BY-SA-4.0, at http://creativecommons.org/licenses/by/4.0/.
201
+## Licenses
202
+
203
+The containerd codebase is released under the [Apache 2.0 license](LICENSE.code).
204
+The README.md file, and files in the "docs" folder are licensed under the
205
+Creative Commons Attribution 4.0 International License under the terms and
206
+conditions set forth in the file "[LICENSE.docs](LICENSE.docs)". You may obtain a duplicate
207
+copy of the same license, titled CC-BY-4.0, at http://creativecommons.org/licenses/by/4.0/.
209 208
new file mode 100644
... ...
@@ -0,0 +1 @@
0
+package leases
0 1
new file mode 100644
... ...
@@ -0,0 +1,1573 @@
0
+// Code generated by protoc-gen-gogo.
1
+// source: github.com/containerd/containerd/api/services/leases/v1/leases.proto
2
+// DO NOT EDIT!
3
+
4
+/*
5
+	Package leases is a generated protocol buffer package.
6
+
7
+	It is generated from these files:
8
+		github.com/containerd/containerd/api/services/leases/v1/leases.proto
9
+
10
+	It has these top-level messages:
11
+		Lease
12
+		CreateRequest
13
+		CreateResponse
14
+		DeleteRequest
15
+		ListRequest
16
+		ListResponse
17
+*/
18
+package leases
19
+
20
+import proto "github.com/gogo/protobuf/proto"
21
+import fmt "fmt"
22
+import math "math"
23
+import _ "github.com/gogo/protobuf/gogoproto"
24
+import google_protobuf1 "github.com/golang/protobuf/ptypes/empty"
25
+import _ "github.com/gogo/protobuf/types"
26
+
27
+import time "time"
28
+
29
+import (
30
+	context "golang.org/x/net/context"
31
+	grpc "google.golang.org/grpc"
32
+)
33
+
34
+import github_com_gogo_protobuf_types "github.com/gogo/protobuf/types"
35
+
36
+import strings "strings"
37
+import reflect "reflect"
38
+import github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys"
39
+
40
+import io "io"
41
+
42
+// Reference imports to suppress errors if they are not otherwise used.
43
+var _ = proto.Marshal
44
+var _ = fmt.Errorf
45
+var _ = math.Inf
46
+var _ = time.Kitchen
47
+
48
+// This is a compile-time assertion to ensure that this generated file
49
+// is compatible with the proto package it is being compiled against.
50
+// A compilation error at this line likely means your copy of the
51
+// proto package needs to be updated.
52
+const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
53
+
54
+// Lease is an object which retains resources while it exists.
55
+type Lease struct {
56
+	ID        string            `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
57
+	CreatedAt time.Time         `protobuf:"bytes,2,opt,name=created_at,json=createdAt,stdtime" json:"created_at"`
58
+	Labels    map[string]string `protobuf:"bytes,3,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
59
+}
60
+
61
+func (m *Lease) Reset()                    { *m = Lease{} }
62
+func (*Lease) ProtoMessage()               {}
63
+func (*Lease) Descriptor() ([]byte, []int) { return fileDescriptorLeases, []int{0} }
64
+
65
+type CreateRequest struct {
66
+	// ID is used to identity the lease, when the id is not set the service
67
+	// generates a random identifier for the lease.
68
+	ID     string            `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
69
+	Labels map[string]string `protobuf:"bytes,3,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
70
+}
71
+
72
+func (m *CreateRequest) Reset()                    { *m = CreateRequest{} }
73
+func (*CreateRequest) ProtoMessage()               {}
74
+func (*CreateRequest) Descriptor() ([]byte, []int) { return fileDescriptorLeases, []int{1} }
75
+
76
+type CreateResponse struct {
77
+	Lease *Lease `protobuf:"bytes,1,opt,name=lease" json:"lease,omitempty"`
78
+}
79
+
80
+func (m *CreateResponse) Reset()                    { *m = CreateResponse{} }
81
+func (*CreateResponse) ProtoMessage()               {}
82
+func (*CreateResponse) Descriptor() ([]byte, []int) { return fileDescriptorLeases, []int{2} }
83
+
84
+type DeleteRequest struct {
85
+	ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
86
+}
87
+
88
+func (m *DeleteRequest) Reset()                    { *m = DeleteRequest{} }
89
+func (*DeleteRequest) ProtoMessage()               {}
90
+func (*DeleteRequest) Descriptor() ([]byte, []int) { return fileDescriptorLeases, []int{3} }
91
+
92
+type ListRequest struct {
93
+	Filters []string `protobuf:"bytes,1,rep,name=filters" json:"filters,omitempty"`
94
+}
95
+
96
+func (m *ListRequest) Reset()                    { *m = ListRequest{} }
97
+func (*ListRequest) ProtoMessage()               {}
98
+func (*ListRequest) Descriptor() ([]byte, []int) { return fileDescriptorLeases, []int{4} }
99
+
100
+type ListResponse struct {
101
+	Leases []*Lease `protobuf:"bytes,1,rep,name=leases" json:"leases,omitempty"`
102
+}
103
+
104
+func (m *ListResponse) Reset()                    { *m = ListResponse{} }
105
+func (*ListResponse) ProtoMessage()               {}
106
+func (*ListResponse) Descriptor() ([]byte, []int) { return fileDescriptorLeases, []int{5} }
107
+
108
+func init() {
109
+	proto.RegisterType((*Lease)(nil), "containerd.services.leases.v1.Lease")
110
+	proto.RegisterType((*CreateRequest)(nil), "containerd.services.leases.v1.CreateRequest")
111
+	proto.RegisterType((*CreateResponse)(nil), "containerd.services.leases.v1.CreateResponse")
112
+	proto.RegisterType((*DeleteRequest)(nil), "containerd.services.leases.v1.DeleteRequest")
113
+	proto.RegisterType((*ListRequest)(nil), "containerd.services.leases.v1.ListRequest")
114
+	proto.RegisterType((*ListResponse)(nil), "containerd.services.leases.v1.ListResponse")
115
+}
116
+
117
+// Reference imports to suppress errors if they are not otherwise used.
118
+var _ context.Context
119
+var _ grpc.ClientConn
120
+
121
+// This is a compile-time assertion to ensure that this generated file
122
+// is compatible with the grpc package it is being compiled against.
123
+const _ = grpc.SupportPackageIsVersion4
124
+
125
+// Client API for Leases service
126
+
127
+type LeasesClient interface {
128
+	// Create creates a new lease for managing changes to metadata. A lease
129
+	// can be used to protect objects from being removed.
130
+	Create(ctx context.Context, in *CreateRequest, opts ...grpc.CallOption) (*CreateResponse, error)
131
+	// Delete deletes the lease and makes any unreferenced objects created
132
+	// during the lease eligible for garbage collection if not referenced
133
+	// or retained by other resources during the lease.
134
+	Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*google_protobuf1.Empty, error)
135
+	// ListTransactions lists all active leases, returning the full list of
136
+	// leases and optionally including the referenced resources.
137
+	List(ctx context.Context, in *ListRequest, opts ...grpc.CallOption) (*ListResponse, error)
138
+}
139
+
140
+type leasesClient struct {
141
+	cc *grpc.ClientConn
142
+}
143
+
144
+func NewLeasesClient(cc *grpc.ClientConn) LeasesClient {
145
+	return &leasesClient{cc}
146
+}
147
+
148
+func (c *leasesClient) Create(ctx context.Context, in *CreateRequest, opts ...grpc.CallOption) (*CreateResponse, error) {
149
+	out := new(CreateResponse)
150
+	err := grpc.Invoke(ctx, "/containerd.services.leases.v1.Leases/Create", in, out, c.cc, opts...)
151
+	if err != nil {
152
+		return nil, err
153
+	}
154
+	return out, nil
155
+}
156
+
157
+func (c *leasesClient) Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*google_protobuf1.Empty, error) {
158
+	out := new(google_protobuf1.Empty)
159
+	err := grpc.Invoke(ctx, "/containerd.services.leases.v1.Leases/Delete", in, out, c.cc, opts...)
160
+	if err != nil {
161
+		return nil, err
162
+	}
163
+	return out, nil
164
+}
165
+
166
+func (c *leasesClient) List(ctx context.Context, in *ListRequest, opts ...grpc.CallOption) (*ListResponse, error) {
167
+	out := new(ListResponse)
168
+	err := grpc.Invoke(ctx, "/containerd.services.leases.v1.Leases/List", in, out, c.cc, opts...)
169
+	if err != nil {
170
+		return nil, err
171
+	}
172
+	return out, nil
173
+}
174
+
175
+// Server API for Leases service
176
+
177
+type LeasesServer interface {
178
+	// Create creates a new lease for managing changes to metadata. A lease
179
+	// can be used to protect objects from being removed.
180
+	Create(context.Context, *CreateRequest) (*CreateResponse, error)
181
+	// Delete deletes the lease and makes any unreferenced objects created
182
+	// during the lease eligible for garbage collection if not referenced
183
+	// or retained by other resources during the lease.
184
+	Delete(context.Context, *DeleteRequest) (*google_protobuf1.Empty, error)
185
+	// ListTransactions lists all active leases, returning the full list of
186
+	// leases and optionally including the referenced resources.
187
+	List(context.Context, *ListRequest) (*ListResponse, error)
188
+}
189
+
190
+func RegisterLeasesServer(s *grpc.Server, srv LeasesServer) {
191
+	s.RegisterService(&_Leases_serviceDesc, srv)
192
+}
193
+
194
+func _Leases_Create_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
195
+	in := new(CreateRequest)
196
+	if err := dec(in); err != nil {
197
+		return nil, err
198
+	}
199
+	if interceptor == nil {
200
+		return srv.(LeasesServer).Create(ctx, in)
201
+	}
202
+	info := &grpc.UnaryServerInfo{
203
+		Server:     srv,
204
+		FullMethod: "/containerd.services.leases.v1.Leases/Create",
205
+	}
206
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
207
+		return srv.(LeasesServer).Create(ctx, req.(*CreateRequest))
208
+	}
209
+	return interceptor(ctx, in, info, handler)
210
+}
211
+
212
+func _Leases_Delete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
213
+	in := new(DeleteRequest)
214
+	if err := dec(in); err != nil {
215
+		return nil, err
216
+	}
217
+	if interceptor == nil {
218
+		return srv.(LeasesServer).Delete(ctx, in)
219
+	}
220
+	info := &grpc.UnaryServerInfo{
221
+		Server:     srv,
222
+		FullMethod: "/containerd.services.leases.v1.Leases/Delete",
223
+	}
224
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
225
+		return srv.(LeasesServer).Delete(ctx, req.(*DeleteRequest))
226
+	}
227
+	return interceptor(ctx, in, info, handler)
228
+}
229
+
230
+func _Leases_List_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
231
+	in := new(ListRequest)
232
+	if err := dec(in); err != nil {
233
+		return nil, err
234
+	}
235
+	if interceptor == nil {
236
+		return srv.(LeasesServer).List(ctx, in)
237
+	}
238
+	info := &grpc.UnaryServerInfo{
239
+		Server:     srv,
240
+		FullMethod: "/containerd.services.leases.v1.Leases/List",
241
+	}
242
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
243
+		return srv.(LeasesServer).List(ctx, req.(*ListRequest))
244
+	}
245
+	return interceptor(ctx, in, info, handler)
246
+}
247
+
248
+var _Leases_serviceDesc = grpc.ServiceDesc{
249
+	ServiceName: "containerd.services.leases.v1.Leases",
250
+	HandlerType: (*LeasesServer)(nil),
251
+	Methods: []grpc.MethodDesc{
252
+		{
253
+			MethodName: "Create",
254
+			Handler:    _Leases_Create_Handler,
255
+		},
256
+		{
257
+			MethodName: "Delete",
258
+			Handler:    _Leases_Delete_Handler,
259
+		},
260
+		{
261
+			MethodName: "List",
262
+			Handler:    _Leases_List_Handler,
263
+		},
264
+	},
265
+	Streams:  []grpc.StreamDesc{},
266
+	Metadata: "github.com/containerd/containerd/api/services/leases/v1/leases.proto",
267
+}
268
+
269
+func (m *Lease) Marshal() (dAtA []byte, err error) {
270
+	size := m.Size()
271
+	dAtA = make([]byte, size)
272
+	n, err := m.MarshalTo(dAtA)
273
+	if err != nil {
274
+		return nil, err
275
+	}
276
+	return dAtA[:n], nil
277
+}
278
+
279
+func (m *Lease) MarshalTo(dAtA []byte) (int, error) {
280
+	var i int
281
+	_ = i
282
+	var l int
283
+	_ = l
284
+	if len(m.ID) > 0 {
285
+		dAtA[i] = 0xa
286
+		i++
287
+		i = encodeVarintLeases(dAtA, i, uint64(len(m.ID)))
288
+		i += copy(dAtA[i:], m.ID)
289
+	}
290
+	dAtA[i] = 0x12
291
+	i++
292
+	i = encodeVarintLeases(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt)))
293
+	n1, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CreatedAt, dAtA[i:])
294
+	if err != nil {
295
+		return 0, err
296
+	}
297
+	i += n1
298
+	if len(m.Labels) > 0 {
299
+		for k, _ := range m.Labels {
300
+			dAtA[i] = 0x1a
301
+			i++
302
+			v := m.Labels[k]
303
+			mapSize := 1 + len(k) + sovLeases(uint64(len(k))) + 1 + len(v) + sovLeases(uint64(len(v)))
304
+			i = encodeVarintLeases(dAtA, i, uint64(mapSize))
305
+			dAtA[i] = 0xa
306
+			i++
307
+			i = encodeVarintLeases(dAtA, i, uint64(len(k)))
308
+			i += copy(dAtA[i:], k)
309
+			dAtA[i] = 0x12
310
+			i++
311
+			i = encodeVarintLeases(dAtA, i, uint64(len(v)))
312
+			i += copy(dAtA[i:], v)
313
+		}
314
+	}
315
+	return i, nil
316
+}
317
+
318
+func (m *CreateRequest) Marshal() (dAtA []byte, err error) {
319
+	size := m.Size()
320
+	dAtA = make([]byte, size)
321
+	n, err := m.MarshalTo(dAtA)
322
+	if err != nil {
323
+		return nil, err
324
+	}
325
+	return dAtA[:n], nil
326
+}
327
+
328
+func (m *CreateRequest) MarshalTo(dAtA []byte) (int, error) {
329
+	var i int
330
+	_ = i
331
+	var l int
332
+	_ = l
333
+	if len(m.ID) > 0 {
334
+		dAtA[i] = 0xa
335
+		i++
336
+		i = encodeVarintLeases(dAtA, i, uint64(len(m.ID)))
337
+		i += copy(dAtA[i:], m.ID)
338
+	}
339
+	if len(m.Labels) > 0 {
340
+		for k, _ := range m.Labels {
341
+			dAtA[i] = 0x1a
342
+			i++
343
+			v := m.Labels[k]
344
+			mapSize := 1 + len(k) + sovLeases(uint64(len(k))) + 1 + len(v) + sovLeases(uint64(len(v)))
345
+			i = encodeVarintLeases(dAtA, i, uint64(mapSize))
346
+			dAtA[i] = 0xa
347
+			i++
348
+			i = encodeVarintLeases(dAtA, i, uint64(len(k)))
349
+			i += copy(dAtA[i:], k)
350
+			dAtA[i] = 0x12
351
+			i++
352
+			i = encodeVarintLeases(dAtA, i, uint64(len(v)))
353
+			i += copy(dAtA[i:], v)
354
+		}
355
+	}
356
+	return i, nil
357
+}
358
+
359
+func (m *CreateResponse) Marshal() (dAtA []byte, err error) {
360
+	size := m.Size()
361
+	dAtA = make([]byte, size)
362
+	n, err := m.MarshalTo(dAtA)
363
+	if err != nil {
364
+		return nil, err
365
+	}
366
+	return dAtA[:n], nil
367
+}
368
+
369
+func (m *CreateResponse) MarshalTo(dAtA []byte) (int, error) {
370
+	var i int
371
+	_ = i
372
+	var l int
373
+	_ = l
374
+	if m.Lease != nil {
375
+		dAtA[i] = 0xa
376
+		i++
377
+		i = encodeVarintLeases(dAtA, i, uint64(m.Lease.Size()))
378
+		n2, err := m.Lease.MarshalTo(dAtA[i:])
379
+		if err != nil {
380
+			return 0, err
381
+		}
382
+		i += n2
383
+	}
384
+	return i, nil
385
+}
386
+
387
+func (m *DeleteRequest) Marshal() (dAtA []byte, err error) {
388
+	size := m.Size()
389
+	dAtA = make([]byte, size)
390
+	n, err := m.MarshalTo(dAtA)
391
+	if err != nil {
392
+		return nil, err
393
+	}
394
+	return dAtA[:n], nil
395
+}
396
+
397
+func (m *DeleteRequest) MarshalTo(dAtA []byte) (int, error) {
398
+	var i int
399
+	_ = i
400
+	var l int
401
+	_ = l
402
+	if len(m.ID) > 0 {
403
+		dAtA[i] = 0xa
404
+		i++
405
+		i = encodeVarintLeases(dAtA, i, uint64(len(m.ID)))
406
+		i += copy(dAtA[i:], m.ID)
407
+	}
408
+	return i, nil
409
+}
410
+
411
+func (m *ListRequest) Marshal() (dAtA []byte, err error) {
412
+	size := m.Size()
413
+	dAtA = make([]byte, size)
414
+	n, err := m.MarshalTo(dAtA)
415
+	if err != nil {
416
+		return nil, err
417
+	}
418
+	return dAtA[:n], nil
419
+}
420
+
421
+func (m *ListRequest) MarshalTo(dAtA []byte) (int, error) {
422
+	var i int
423
+	_ = i
424
+	var l int
425
+	_ = l
426
+	if len(m.Filters) > 0 {
427
+		for _, s := range m.Filters {
428
+			dAtA[i] = 0xa
429
+			i++
430
+			l = len(s)
431
+			for l >= 1<<7 {
432
+				dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
433
+				l >>= 7
434
+				i++
435
+			}
436
+			dAtA[i] = uint8(l)
437
+			i++
438
+			i += copy(dAtA[i:], s)
439
+		}
440
+	}
441
+	return i, nil
442
+}
443
+
444
+func (m *ListResponse) Marshal() (dAtA []byte, err error) {
445
+	size := m.Size()
446
+	dAtA = make([]byte, size)
447
+	n, err := m.MarshalTo(dAtA)
448
+	if err != nil {
449
+		return nil, err
450
+	}
451
+	return dAtA[:n], nil
452
+}
453
+
454
+func (m *ListResponse) MarshalTo(dAtA []byte) (int, error) {
455
+	var i int
456
+	_ = i
457
+	var l int
458
+	_ = l
459
+	if len(m.Leases) > 0 {
460
+		for _, msg := range m.Leases {
461
+			dAtA[i] = 0xa
462
+			i++
463
+			i = encodeVarintLeases(dAtA, i, uint64(msg.Size()))
464
+			n, err := msg.MarshalTo(dAtA[i:])
465
+			if err != nil {
466
+				return 0, err
467
+			}
468
+			i += n
469
+		}
470
+	}
471
+	return i, nil
472
+}
473
+
474
+func encodeFixed64Leases(dAtA []byte, offset int, v uint64) int {
475
+	dAtA[offset] = uint8(v)
476
+	dAtA[offset+1] = uint8(v >> 8)
477
+	dAtA[offset+2] = uint8(v >> 16)
478
+	dAtA[offset+3] = uint8(v >> 24)
479
+	dAtA[offset+4] = uint8(v >> 32)
480
+	dAtA[offset+5] = uint8(v >> 40)
481
+	dAtA[offset+6] = uint8(v >> 48)
482
+	dAtA[offset+7] = uint8(v >> 56)
483
+	return offset + 8
484
+}
485
+func encodeFixed32Leases(dAtA []byte, offset int, v uint32) int {
486
+	dAtA[offset] = uint8(v)
487
+	dAtA[offset+1] = uint8(v >> 8)
488
+	dAtA[offset+2] = uint8(v >> 16)
489
+	dAtA[offset+3] = uint8(v >> 24)
490
+	return offset + 4
491
+}
492
+func encodeVarintLeases(dAtA []byte, offset int, v uint64) int {
493
+	for v >= 1<<7 {
494
+		dAtA[offset] = uint8(v&0x7f | 0x80)
495
+		v >>= 7
496
+		offset++
497
+	}
498
+	dAtA[offset] = uint8(v)
499
+	return offset + 1
500
+}
501
+func (m *Lease) Size() (n int) {
502
+	var l int
503
+	_ = l
504
+	l = len(m.ID)
505
+	if l > 0 {
506
+		n += 1 + l + sovLeases(uint64(l))
507
+	}
508
+	l = github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt)
509
+	n += 1 + l + sovLeases(uint64(l))
510
+	if len(m.Labels) > 0 {
511
+		for k, v := range m.Labels {
512
+			_ = k
513
+			_ = v
514
+			mapEntrySize := 1 + len(k) + sovLeases(uint64(len(k))) + 1 + len(v) + sovLeases(uint64(len(v)))
515
+			n += mapEntrySize + 1 + sovLeases(uint64(mapEntrySize))
516
+		}
517
+	}
518
+	return n
519
+}
520
+
521
+func (m *CreateRequest) Size() (n int) {
522
+	var l int
523
+	_ = l
524
+	l = len(m.ID)
525
+	if l > 0 {
526
+		n += 1 + l + sovLeases(uint64(l))
527
+	}
528
+	if len(m.Labels) > 0 {
529
+		for k, v := range m.Labels {
530
+			_ = k
531
+			_ = v
532
+			mapEntrySize := 1 + len(k) + sovLeases(uint64(len(k))) + 1 + len(v) + sovLeases(uint64(len(v)))
533
+			n += mapEntrySize + 1 + sovLeases(uint64(mapEntrySize))
534
+		}
535
+	}
536
+	return n
537
+}
538
+
539
+func (m *CreateResponse) Size() (n int) {
540
+	var l int
541
+	_ = l
542
+	if m.Lease != nil {
543
+		l = m.Lease.Size()
544
+		n += 1 + l + sovLeases(uint64(l))
545
+	}
546
+	return n
547
+}
548
+
549
+func (m *DeleteRequest) Size() (n int) {
550
+	var l int
551
+	_ = l
552
+	l = len(m.ID)
553
+	if l > 0 {
554
+		n += 1 + l + sovLeases(uint64(l))
555
+	}
556
+	return n
557
+}
558
+
559
+func (m *ListRequest) Size() (n int) {
560
+	var l int
561
+	_ = l
562
+	if len(m.Filters) > 0 {
563
+		for _, s := range m.Filters {
564
+			l = len(s)
565
+			n += 1 + l + sovLeases(uint64(l))
566
+		}
567
+	}
568
+	return n
569
+}
570
+
571
+func (m *ListResponse) Size() (n int) {
572
+	var l int
573
+	_ = l
574
+	if len(m.Leases) > 0 {
575
+		for _, e := range m.Leases {
576
+			l = e.Size()
577
+			n += 1 + l + sovLeases(uint64(l))
578
+		}
579
+	}
580
+	return n
581
+}
582
+
583
+func sovLeases(x uint64) (n int) {
584
+	for {
585
+		n++
586
+		x >>= 7
587
+		if x == 0 {
588
+			break
589
+		}
590
+	}
591
+	return n
592
+}
593
+func sozLeases(x uint64) (n int) {
594
+	return sovLeases(uint64((x << 1) ^ uint64((int64(x) >> 63))))
595
+}
596
+func (this *Lease) String() string {
597
+	if this == nil {
598
+		return "nil"
599
+	}
600
+	keysForLabels := make([]string, 0, len(this.Labels))
601
+	for k, _ := range this.Labels {
602
+		keysForLabels = append(keysForLabels, k)
603
+	}
604
+	github_com_gogo_protobuf_sortkeys.Strings(keysForLabels)
605
+	mapStringForLabels := "map[string]string{"
606
+	for _, k := range keysForLabels {
607
+		mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k])
608
+	}
609
+	mapStringForLabels += "}"
610
+	s := strings.Join([]string{`&Lease{`,
611
+		`ID:` + fmt.Sprintf("%v", this.ID) + `,`,
612
+		`CreatedAt:` + strings.Replace(strings.Replace(this.CreatedAt.String(), "Timestamp", "google_protobuf2.Timestamp", 1), `&`, ``, 1) + `,`,
613
+		`Labels:` + mapStringForLabels + `,`,
614
+		`}`,
615
+	}, "")
616
+	return s
617
+}
618
+func (this *CreateRequest) String() string {
619
+	if this == nil {
620
+		return "nil"
621
+	}
622
+	keysForLabels := make([]string, 0, len(this.Labels))
623
+	for k, _ := range this.Labels {
624
+		keysForLabels = append(keysForLabels, k)
625
+	}
626
+	github_com_gogo_protobuf_sortkeys.Strings(keysForLabels)
627
+	mapStringForLabels := "map[string]string{"
628
+	for _, k := range keysForLabels {
629
+		mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k])
630
+	}
631
+	mapStringForLabels += "}"
632
+	s := strings.Join([]string{`&CreateRequest{`,
633
+		`ID:` + fmt.Sprintf("%v", this.ID) + `,`,
634
+		`Labels:` + mapStringForLabels + `,`,
635
+		`}`,
636
+	}, "")
637
+	return s
638
+}
639
+func (this *CreateResponse) String() string {
640
+	if this == nil {
641
+		return "nil"
642
+	}
643
+	s := strings.Join([]string{`&CreateResponse{`,
644
+		`Lease:` + strings.Replace(fmt.Sprintf("%v", this.Lease), "Lease", "Lease", 1) + `,`,
645
+		`}`,
646
+	}, "")
647
+	return s
648
+}
649
+func (this *DeleteRequest) String() string {
650
+	if this == nil {
651
+		return "nil"
652
+	}
653
+	s := strings.Join([]string{`&DeleteRequest{`,
654
+		`ID:` + fmt.Sprintf("%v", this.ID) + `,`,
655
+		`}`,
656
+	}, "")
657
+	return s
658
+}
659
+func (this *ListRequest) String() string {
660
+	if this == nil {
661
+		return "nil"
662
+	}
663
+	s := strings.Join([]string{`&ListRequest{`,
664
+		`Filters:` + fmt.Sprintf("%v", this.Filters) + `,`,
665
+		`}`,
666
+	}, "")
667
+	return s
668
+}
669
+func (this *ListResponse) String() string {
670
+	if this == nil {
671
+		return "nil"
672
+	}
673
+	s := strings.Join([]string{`&ListResponse{`,
674
+		`Leases:` + strings.Replace(fmt.Sprintf("%v", this.Leases), "Lease", "Lease", 1) + `,`,
675
+		`}`,
676
+	}, "")
677
+	return s
678
+}
679
+func valueToStringLeases(v interface{}) string {
680
+	rv := reflect.ValueOf(v)
681
+	if rv.IsNil() {
682
+		return "nil"
683
+	}
684
+	pv := reflect.Indirect(rv).Interface()
685
+	return fmt.Sprintf("*%v", pv)
686
+}
687
+func (m *Lease) Unmarshal(dAtA []byte) error {
688
+	l := len(dAtA)
689
+	iNdEx := 0
690
+	for iNdEx < l {
691
+		preIndex := iNdEx
692
+		var wire uint64
693
+		for shift := uint(0); ; shift += 7 {
694
+			if shift >= 64 {
695
+				return ErrIntOverflowLeases
696
+			}
697
+			if iNdEx >= l {
698
+				return io.ErrUnexpectedEOF
699
+			}
700
+			b := dAtA[iNdEx]
701
+			iNdEx++
702
+			wire |= (uint64(b) & 0x7F) << shift
703
+			if b < 0x80 {
704
+				break
705
+			}
706
+		}
707
+		fieldNum := int32(wire >> 3)
708
+		wireType := int(wire & 0x7)
709
+		if wireType == 4 {
710
+			return fmt.Errorf("proto: Lease: wiretype end group for non-group")
711
+		}
712
+		if fieldNum <= 0 {
713
+			return fmt.Errorf("proto: Lease: illegal tag %d (wire type %d)", fieldNum, wire)
714
+		}
715
+		switch fieldNum {
716
+		case 1:
717
+			if wireType != 2 {
718
+				return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType)
719
+			}
720
+			var stringLen uint64
721
+			for shift := uint(0); ; shift += 7 {
722
+				if shift >= 64 {
723
+					return ErrIntOverflowLeases
724
+				}
725
+				if iNdEx >= l {
726
+					return io.ErrUnexpectedEOF
727
+				}
728
+				b := dAtA[iNdEx]
729
+				iNdEx++
730
+				stringLen |= (uint64(b) & 0x7F) << shift
731
+				if b < 0x80 {
732
+					break
733
+				}
734
+			}
735
+			intStringLen := int(stringLen)
736
+			if intStringLen < 0 {
737
+				return ErrInvalidLengthLeases
738
+			}
739
+			postIndex := iNdEx + intStringLen
740
+			if postIndex > l {
741
+				return io.ErrUnexpectedEOF
742
+			}
743
+			m.ID = string(dAtA[iNdEx:postIndex])
744
+			iNdEx = postIndex
745
+		case 2:
746
+			if wireType != 2 {
747
+				return fmt.Errorf("proto: wrong wireType = %d for field CreatedAt", wireType)
748
+			}
749
+			var msglen int
750
+			for shift := uint(0); ; shift += 7 {
751
+				if shift >= 64 {
752
+					return ErrIntOverflowLeases
753
+				}
754
+				if iNdEx >= l {
755
+					return io.ErrUnexpectedEOF
756
+				}
757
+				b := dAtA[iNdEx]
758
+				iNdEx++
759
+				msglen |= (int(b) & 0x7F) << shift
760
+				if b < 0x80 {
761
+					break
762
+				}
763
+			}
764
+			if msglen < 0 {
765
+				return ErrInvalidLengthLeases
766
+			}
767
+			postIndex := iNdEx + msglen
768
+			if postIndex > l {
769
+				return io.ErrUnexpectedEOF
770
+			}
771
+			if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.CreatedAt, dAtA[iNdEx:postIndex]); err != nil {
772
+				return err
773
+			}
774
+			iNdEx = postIndex
775
+		case 3:
776
+			if wireType != 2 {
777
+				return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType)
778
+			}
779
+			var msglen int
780
+			for shift := uint(0); ; shift += 7 {
781
+				if shift >= 64 {
782
+					return ErrIntOverflowLeases
783
+				}
784
+				if iNdEx >= l {
785
+					return io.ErrUnexpectedEOF
786
+				}
787
+				b := dAtA[iNdEx]
788
+				iNdEx++
789
+				msglen |= (int(b) & 0x7F) << shift
790
+				if b < 0x80 {
791
+					break
792
+				}
793
+			}
794
+			if msglen < 0 {
795
+				return ErrInvalidLengthLeases
796
+			}
797
+			postIndex := iNdEx + msglen
798
+			if postIndex > l {
799
+				return io.ErrUnexpectedEOF
800
+			}
801
+			var keykey uint64
802
+			for shift := uint(0); ; shift += 7 {
803
+				if shift >= 64 {
804
+					return ErrIntOverflowLeases
805
+				}
806
+				if iNdEx >= l {
807
+					return io.ErrUnexpectedEOF
808
+				}
809
+				b := dAtA[iNdEx]
810
+				iNdEx++
811
+				keykey |= (uint64(b) & 0x7F) << shift
812
+				if b < 0x80 {
813
+					break
814
+				}
815
+			}
816
+			var stringLenmapkey uint64
817
+			for shift := uint(0); ; shift += 7 {
818
+				if shift >= 64 {
819
+					return ErrIntOverflowLeases
820
+				}
821
+				if iNdEx >= l {
822
+					return io.ErrUnexpectedEOF
823
+				}
824
+				b := dAtA[iNdEx]
825
+				iNdEx++
826
+				stringLenmapkey |= (uint64(b) & 0x7F) << shift
827
+				if b < 0x80 {
828
+					break
829
+				}
830
+			}
831
+			intStringLenmapkey := int(stringLenmapkey)
832
+			if intStringLenmapkey < 0 {
833
+				return ErrInvalidLengthLeases
834
+			}
835
+			postStringIndexmapkey := iNdEx + intStringLenmapkey
836
+			if postStringIndexmapkey > l {
837
+				return io.ErrUnexpectedEOF
838
+			}
839
+			mapkey := string(dAtA[iNdEx:postStringIndexmapkey])
840
+			iNdEx = postStringIndexmapkey
841
+			if m.Labels == nil {
842
+				m.Labels = make(map[string]string)
843
+			}
844
+			if iNdEx < postIndex {
845
+				var valuekey uint64
846
+				for shift := uint(0); ; shift += 7 {
847
+					if shift >= 64 {
848
+						return ErrIntOverflowLeases
849
+					}
850
+					if iNdEx >= l {
851
+						return io.ErrUnexpectedEOF
852
+					}
853
+					b := dAtA[iNdEx]
854
+					iNdEx++
855
+					valuekey |= (uint64(b) & 0x7F) << shift
856
+					if b < 0x80 {
857
+						break
858
+					}
859
+				}
860
+				var stringLenmapvalue uint64
861
+				for shift := uint(0); ; shift += 7 {
862
+					if shift >= 64 {
863
+						return ErrIntOverflowLeases
864
+					}
865
+					if iNdEx >= l {
866
+						return io.ErrUnexpectedEOF
867
+					}
868
+					b := dAtA[iNdEx]
869
+					iNdEx++
870
+					stringLenmapvalue |= (uint64(b) & 0x7F) << shift
871
+					if b < 0x80 {
872
+						break
873
+					}
874
+				}
875
+				intStringLenmapvalue := int(stringLenmapvalue)
876
+				if intStringLenmapvalue < 0 {
877
+					return ErrInvalidLengthLeases
878
+				}
879
+				postStringIndexmapvalue := iNdEx + intStringLenmapvalue
880
+				if postStringIndexmapvalue > l {
881
+					return io.ErrUnexpectedEOF
882
+				}
883
+				mapvalue := string(dAtA[iNdEx:postStringIndexmapvalue])
884
+				iNdEx = postStringIndexmapvalue
885
+				m.Labels[mapkey] = mapvalue
886
+			} else {
887
+				var mapvalue string
888
+				m.Labels[mapkey] = mapvalue
889
+			}
890
+			iNdEx = postIndex
891
+		default:
892
+			iNdEx = preIndex
893
+			skippy, err := skipLeases(dAtA[iNdEx:])
894
+			if err != nil {
895
+				return err
896
+			}
897
+			if skippy < 0 {
898
+				return ErrInvalidLengthLeases
899
+			}
900
+			if (iNdEx + skippy) > l {
901
+				return io.ErrUnexpectedEOF
902
+			}
903
+			iNdEx += skippy
904
+		}
905
+	}
906
+
907
+	if iNdEx > l {
908
+		return io.ErrUnexpectedEOF
909
+	}
910
+	return nil
911
+}
912
+func (m *CreateRequest) Unmarshal(dAtA []byte) error {
913
+	l := len(dAtA)
914
+	iNdEx := 0
915
+	for iNdEx < l {
916
+		preIndex := iNdEx
917
+		var wire uint64
918
+		for shift := uint(0); ; shift += 7 {
919
+			if shift >= 64 {
920
+				return ErrIntOverflowLeases
921
+			}
922
+			if iNdEx >= l {
923
+				return io.ErrUnexpectedEOF
924
+			}
925
+			b := dAtA[iNdEx]
926
+			iNdEx++
927
+			wire |= (uint64(b) & 0x7F) << shift
928
+			if b < 0x80 {
929
+				break
930
+			}
931
+		}
932
+		fieldNum := int32(wire >> 3)
933
+		wireType := int(wire & 0x7)
934
+		if wireType == 4 {
935
+			return fmt.Errorf("proto: CreateRequest: wiretype end group for non-group")
936
+		}
937
+		if fieldNum <= 0 {
938
+			return fmt.Errorf("proto: CreateRequest: illegal tag %d (wire type %d)", fieldNum, wire)
939
+		}
940
+		switch fieldNum {
941
+		case 1:
942
+			if wireType != 2 {
943
+				return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType)
944
+			}
945
+			var stringLen uint64
946
+			for shift := uint(0); ; shift += 7 {
947
+				if shift >= 64 {
948
+					return ErrIntOverflowLeases
949
+				}
950
+				if iNdEx >= l {
951
+					return io.ErrUnexpectedEOF
952
+				}
953
+				b := dAtA[iNdEx]
954
+				iNdEx++
955
+				stringLen |= (uint64(b) & 0x7F) << shift
956
+				if b < 0x80 {
957
+					break
958
+				}
959
+			}
960
+			intStringLen := int(stringLen)
961
+			if intStringLen < 0 {
962
+				return ErrInvalidLengthLeases
963
+			}
964
+			postIndex := iNdEx + intStringLen
965
+			if postIndex > l {
966
+				return io.ErrUnexpectedEOF
967
+			}
968
+			m.ID = string(dAtA[iNdEx:postIndex])
969
+			iNdEx = postIndex
970
+		case 3:
971
+			if wireType != 2 {
972
+				return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType)
973
+			}
974
+			var msglen int
975
+			for shift := uint(0); ; shift += 7 {
976
+				if shift >= 64 {
977
+					return ErrIntOverflowLeases
978
+				}
979
+				if iNdEx >= l {
980
+					return io.ErrUnexpectedEOF
981
+				}
982
+				b := dAtA[iNdEx]
983
+				iNdEx++
984
+				msglen |= (int(b) & 0x7F) << shift
985
+				if b < 0x80 {
986
+					break
987
+				}
988
+			}
989
+			if msglen < 0 {
990
+				return ErrInvalidLengthLeases
991
+			}
992
+			postIndex := iNdEx + msglen
993
+			if postIndex > l {
994
+				return io.ErrUnexpectedEOF
995
+			}
996
+			var keykey uint64
997
+			for shift := uint(0); ; shift += 7 {
998
+				if shift >= 64 {
999
+					return ErrIntOverflowLeases
1000
+				}
1001
+				if iNdEx >= l {
1002
+					return io.ErrUnexpectedEOF
1003
+				}
1004
+				b := dAtA[iNdEx]
1005
+				iNdEx++
1006
+				keykey |= (uint64(b) & 0x7F) << shift
1007
+				if b < 0x80 {
1008
+					break
1009
+				}
1010
+			}
1011
+			var stringLenmapkey uint64
1012
+			for shift := uint(0); ; shift += 7 {
1013
+				if shift >= 64 {
1014
+					return ErrIntOverflowLeases
1015
+				}
1016
+				if iNdEx >= l {
1017
+					return io.ErrUnexpectedEOF
1018
+				}
1019
+				b := dAtA[iNdEx]
1020
+				iNdEx++
1021
+				stringLenmapkey |= (uint64(b) & 0x7F) << shift
1022
+				if b < 0x80 {
1023
+					break
1024
+				}
1025
+			}
1026
+			intStringLenmapkey := int(stringLenmapkey)
1027
+			if intStringLenmapkey < 0 {
1028
+				return ErrInvalidLengthLeases
1029
+			}
1030
+			postStringIndexmapkey := iNdEx + intStringLenmapkey
1031
+			if postStringIndexmapkey > l {
1032
+				return io.ErrUnexpectedEOF
1033
+			}
1034
+			mapkey := string(dAtA[iNdEx:postStringIndexmapkey])
1035
+			iNdEx = postStringIndexmapkey
1036
+			if m.Labels == nil {
1037
+				m.Labels = make(map[string]string)
1038
+			}
1039
+			if iNdEx < postIndex {
1040
+				var valuekey uint64
1041
+				for shift := uint(0); ; shift += 7 {
1042
+					if shift >= 64 {
1043
+						return ErrIntOverflowLeases
1044
+					}
1045
+					if iNdEx >= l {
1046
+						return io.ErrUnexpectedEOF
1047
+					}
1048
+					b := dAtA[iNdEx]
1049
+					iNdEx++
1050
+					valuekey |= (uint64(b) & 0x7F) << shift
1051
+					if b < 0x80 {
1052
+						break
1053
+					}
1054
+				}
1055
+				var stringLenmapvalue uint64
1056
+				for shift := uint(0); ; shift += 7 {
1057
+					if shift >= 64 {
1058
+						return ErrIntOverflowLeases
1059
+					}
1060
+					if iNdEx >= l {
1061
+						return io.ErrUnexpectedEOF
1062
+					}
1063
+					b := dAtA[iNdEx]
1064
+					iNdEx++
1065
+					stringLenmapvalue |= (uint64(b) & 0x7F) << shift
1066
+					if b < 0x80 {
1067
+						break
1068
+					}
1069
+				}
1070
+				intStringLenmapvalue := int(stringLenmapvalue)
1071
+				if intStringLenmapvalue < 0 {
1072
+					return ErrInvalidLengthLeases
1073
+				}
1074
+				postStringIndexmapvalue := iNdEx + intStringLenmapvalue
1075
+				if postStringIndexmapvalue > l {
1076
+					return io.ErrUnexpectedEOF
1077
+				}
1078
+				mapvalue := string(dAtA[iNdEx:postStringIndexmapvalue])
1079
+				iNdEx = postStringIndexmapvalue
1080
+				m.Labels[mapkey] = mapvalue
1081
+			} else {
1082
+				var mapvalue string
1083
+				m.Labels[mapkey] = mapvalue
1084
+			}
1085
+			iNdEx = postIndex
1086
+		default:
1087
+			iNdEx = preIndex
1088
+			skippy, err := skipLeases(dAtA[iNdEx:])
1089
+			if err != nil {
1090
+				return err
1091
+			}
1092
+			if skippy < 0 {
1093
+				return ErrInvalidLengthLeases
1094
+			}
1095
+			if (iNdEx + skippy) > l {
1096
+				return io.ErrUnexpectedEOF
1097
+			}
1098
+			iNdEx += skippy
1099
+		}
1100
+	}
1101
+
1102
+	if iNdEx > l {
1103
+		return io.ErrUnexpectedEOF
1104
+	}
1105
+	return nil
1106
+}
1107
+func (m *CreateResponse) Unmarshal(dAtA []byte) error {
1108
+	l := len(dAtA)
1109
+	iNdEx := 0
1110
+	for iNdEx < l {
1111
+		preIndex := iNdEx
1112
+		var wire uint64
1113
+		for shift := uint(0); ; shift += 7 {
1114
+			if shift >= 64 {
1115
+				return ErrIntOverflowLeases
1116
+			}
1117
+			if iNdEx >= l {
1118
+				return io.ErrUnexpectedEOF
1119
+			}
1120
+			b := dAtA[iNdEx]
1121
+			iNdEx++
1122
+			wire |= (uint64(b) & 0x7F) << shift
1123
+			if b < 0x80 {
1124
+				break
1125
+			}
1126
+		}
1127
+		fieldNum := int32(wire >> 3)
1128
+		wireType := int(wire & 0x7)
1129
+		if wireType == 4 {
1130
+			return fmt.Errorf("proto: CreateResponse: wiretype end group for non-group")
1131
+		}
1132
+		if fieldNum <= 0 {
1133
+			return fmt.Errorf("proto: CreateResponse: illegal tag %d (wire type %d)", fieldNum, wire)
1134
+		}
1135
+		switch fieldNum {
1136
+		case 1:
1137
+			if wireType != 2 {
1138
+				return fmt.Errorf("proto: wrong wireType = %d for field Lease", wireType)
1139
+			}
1140
+			var msglen int
1141
+			for shift := uint(0); ; shift += 7 {
1142
+				if shift >= 64 {
1143
+					return ErrIntOverflowLeases
1144
+				}
1145
+				if iNdEx >= l {
1146
+					return io.ErrUnexpectedEOF
1147
+				}
1148
+				b := dAtA[iNdEx]
1149
+				iNdEx++
1150
+				msglen |= (int(b) & 0x7F) << shift
1151
+				if b < 0x80 {
1152
+					break
1153
+				}
1154
+			}
1155
+			if msglen < 0 {
1156
+				return ErrInvalidLengthLeases
1157
+			}
1158
+			postIndex := iNdEx + msglen
1159
+			if postIndex > l {
1160
+				return io.ErrUnexpectedEOF
1161
+			}
1162
+			if m.Lease == nil {
1163
+				m.Lease = &Lease{}
1164
+			}
1165
+			if err := m.Lease.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
1166
+				return err
1167
+			}
1168
+			iNdEx = postIndex
1169
+		default:
1170
+			iNdEx = preIndex
1171
+			skippy, err := skipLeases(dAtA[iNdEx:])
1172
+			if err != nil {
1173
+				return err
1174
+			}
1175
+			if skippy < 0 {
1176
+				return ErrInvalidLengthLeases
1177
+			}
1178
+			if (iNdEx + skippy) > l {
1179
+				return io.ErrUnexpectedEOF
1180
+			}
1181
+			iNdEx += skippy
1182
+		}
1183
+	}
1184
+
1185
+	if iNdEx > l {
1186
+		return io.ErrUnexpectedEOF
1187
+	}
1188
+	return nil
1189
+}
1190
+func (m *DeleteRequest) Unmarshal(dAtA []byte) error {
1191
+	l := len(dAtA)
1192
+	iNdEx := 0
1193
+	for iNdEx < l {
1194
+		preIndex := iNdEx
1195
+		var wire uint64
1196
+		for shift := uint(0); ; shift += 7 {
1197
+			if shift >= 64 {
1198
+				return ErrIntOverflowLeases
1199
+			}
1200
+			if iNdEx >= l {
1201
+				return io.ErrUnexpectedEOF
1202
+			}
1203
+			b := dAtA[iNdEx]
1204
+			iNdEx++
1205
+			wire |= (uint64(b) & 0x7F) << shift
1206
+			if b < 0x80 {
1207
+				break
1208
+			}
1209
+		}
1210
+		fieldNum := int32(wire >> 3)
1211
+		wireType := int(wire & 0x7)
1212
+		if wireType == 4 {
1213
+			return fmt.Errorf("proto: DeleteRequest: wiretype end group for non-group")
1214
+		}
1215
+		if fieldNum <= 0 {
1216
+			return fmt.Errorf("proto: DeleteRequest: illegal tag %d (wire type %d)", fieldNum, wire)
1217
+		}
1218
+		switch fieldNum {
1219
+		case 1:
1220
+			if wireType != 2 {
1221
+				return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType)
1222
+			}
1223
+			var stringLen uint64
1224
+			for shift := uint(0); ; shift += 7 {
1225
+				if shift >= 64 {
1226
+					return ErrIntOverflowLeases
1227
+				}
1228
+				if iNdEx >= l {
1229
+					return io.ErrUnexpectedEOF
1230
+				}
1231
+				b := dAtA[iNdEx]
1232
+				iNdEx++
1233
+				stringLen |= (uint64(b) & 0x7F) << shift
1234
+				if b < 0x80 {
1235
+					break
1236
+				}
1237
+			}
1238
+			intStringLen := int(stringLen)
1239
+			if intStringLen < 0 {
1240
+				return ErrInvalidLengthLeases
1241
+			}
1242
+			postIndex := iNdEx + intStringLen
1243
+			if postIndex > l {
1244
+				return io.ErrUnexpectedEOF
1245
+			}
1246
+			m.ID = string(dAtA[iNdEx:postIndex])
1247
+			iNdEx = postIndex
1248
+		default:
1249
+			iNdEx = preIndex
1250
+			skippy, err := skipLeases(dAtA[iNdEx:])
1251
+			if err != nil {
1252
+				return err
1253
+			}
1254
+			if skippy < 0 {
1255
+				return ErrInvalidLengthLeases
1256
+			}
1257
+			if (iNdEx + skippy) > l {
1258
+				return io.ErrUnexpectedEOF
1259
+			}
1260
+			iNdEx += skippy
1261
+		}
1262
+	}
1263
+
1264
+	if iNdEx > l {
1265
+		return io.ErrUnexpectedEOF
1266
+	}
1267
+	return nil
1268
+}
1269
+func (m *ListRequest) Unmarshal(dAtA []byte) error {
1270
+	l := len(dAtA)
1271
+	iNdEx := 0
1272
+	for iNdEx < l {
1273
+		preIndex := iNdEx
1274
+		var wire uint64
1275
+		for shift := uint(0); ; shift += 7 {
1276
+			if shift >= 64 {
1277
+				return ErrIntOverflowLeases
1278
+			}
1279
+			if iNdEx >= l {
1280
+				return io.ErrUnexpectedEOF
1281
+			}
1282
+			b := dAtA[iNdEx]
1283
+			iNdEx++
1284
+			wire |= (uint64(b) & 0x7F) << shift
1285
+			if b < 0x80 {
1286
+				break
1287
+			}
1288
+		}
1289
+		fieldNum := int32(wire >> 3)
1290
+		wireType := int(wire & 0x7)
1291
+		if wireType == 4 {
1292
+			return fmt.Errorf("proto: ListRequest: wiretype end group for non-group")
1293
+		}
1294
+		if fieldNum <= 0 {
1295
+			return fmt.Errorf("proto: ListRequest: illegal tag %d (wire type %d)", fieldNum, wire)
1296
+		}
1297
+		switch fieldNum {
1298
+		case 1:
1299
+			if wireType != 2 {
1300
+				return fmt.Errorf("proto: wrong wireType = %d for field Filters", wireType)
1301
+			}
1302
+			var stringLen uint64
1303
+			for shift := uint(0); ; shift += 7 {
1304
+				if shift >= 64 {
1305
+					return ErrIntOverflowLeases
1306
+				}
1307
+				if iNdEx >= l {
1308
+					return io.ErrUnexpectedEOF
1309
+				}
1310
+				b := dAtA[iNdEx]
1311
+				iNdEx++
1312
+				stringLen |= (uint64(b) & 0x7F) << shift
1313
+				if b < 0x80 {
1314
+					break
1315
+				}
1316
+			}
1317
+			intStringLen := int(stringLen)
1318
+			if intStringLen < 0 {
1319
+				return ErrInvalidLengthLeases
1320
+			}
1321
+			postIndex := iNdEx + intStringLen
1322
+			if postIndex > l {
1323
+				return io.ErrUnexpectedEOF
1324
+			}
1325
+			m.Filters = append(m.Filters, string(dAtA[iNdEx:postIndex]))
1326
+			iNdEx = postIndex
1327
+		default:
1328
+			iNdEx = preIndex
1329
+			skippy, err := skipLeases(dAtA[iNdEx:])
1330
+			if err != nil {
1331
+				return err
1332
+			}
1333
+			if skippy < 0 {
1334
+				return ErrInvalidLengthLeases
1335
+			}
1336
+			if (iNdEx + skippy) > l {
1337
+				return io.ErrUnexpectedEOF
1338
+			}
1339
+			iNdEx += skippy
1340
+		}
1341
+	}
1342
+
1343
+	if iNdEx > l {
1344
+		return io.ErrUnexpectedEOF
1345
+	}
1346
+	return nil
1347
+}
1348
+func (m *ListResponse) Unmarshal(dAtA []byte) error {
1349
+	l := len(dAtA)
1350
+	iNdEx := 0
1351
+	for iNdEx < l {
1352
+		preIndex := iNdEx
1353
+		var wire uint64
1354
+		for shift := uint(0); ; shift += 7 {
1355
+			if shift >= 64 {
1356
+				return ErrIntOverflowLeases
1357
+			}
1358
+			if iNdEx >= l {
1359
+				return io.ErrUnexpectedEOF
1360
+			}
1361
+			b := dAtA[iNdEx]
1362
+			iNdEx++
1363
+			wire |= (uint64(b) & 0x7F) << shift
1364
+			if b < 0x80 {
1365
+				break
1366
+			}
1367
+		}
1368
+		fieldNum := int32(wire >> 3)
1369
+		wireType := int(wire & 0x7)
1370
+		if wireType == 4 {
1371
+			return fmt.Errorf("proto: ListResponse: wiretype end group for non-group")
1372
+		}
1373
+		if fieldNum <= 0 {
1374
+			return fmt.Errorf("proto: ListResponse: illegal tag %d (wire type %d)", fieldNum, wire)
1375
+		}
1376
+		switch fieldNum {
1377
+		case 1:
1378
+			if wireType != 2 {
1379
+				return fmt.Errorf("proto: wrong wireType = %d for field Leases", wireType)
1380
+			}
1381
+			var msglen int
1382
+			for shift := uint(0); ; shift += 7 {
1383
+				if shift >= 64 {
1384
+					return ErrIntOverflowLeases
1385
+				}
1386
+				if iNdEx >= l {
1387
+					return io.ErrUnexpectedEOF
1388
+				}
1389
+				b := dAtA[iNdEx]
1390
+				iNdEx++
1391
+				msglen |= (int(b) & 0x7F) << shift
1392
+				if b < 0x80 {
1393
+					break
1394
+				}
1395
+			}
1396
+			if msglen < 0 {
1397
+				return ErrInvalidLengthLeases
1398
+			}
1399
+			postIndex := iNdEx + msglen
1400
+			if postIndex > l {
1401
+				return io.ErrUnexpectedEOF
1402
+			}
1403
+			m.Leases = append(m.Leases, &Lease{})
1404
+			if err := m.Leases[len(m.Leases)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
1405
+				return err
1406
+			}
1407
+			iNdEx = postIndex
1408
+		default:
1409
+			iNdEx = preIndex
1410
+			skippy, err := skipLeases(dAtA[iNdEx:])
1411
+			if err != nil {
1412
+				return err
1413
+			}
1414
+			if skippy < 0 {
1415
+				return ErrInvalidLengthLeases
1416
+			}
1417
+			if (iNdEx + skippy) > l {
1418
+				return io.ErrUnexpectedEOF
1419
+			}
1420
+			iNdEx += skippy
1421
+		}
1422
+	}
1423
+
1424
+	if iNdEx > l {
1425
+		return io.ErrUnexpectedEOF
1426
+	}
1427
+	return nil
1428
+}
1429
+func skipLeases(dAtA []byte) (n int, err error) {
1430
+	l := len(dAtA)
1431
+	iNdEx := 0
1432
+	for iNdEx < l {
1433
+		var wire uint64
1434
+		for shift := uint(0); ; shift += 7 {
1435
+			if shift >= 64 {
1436
+				return 0, ErrIntOverflowLeases
1437
+			}
1438
+			if iNdEx >= l {
1439
+				return 0, io.ErrUnexpectedEOF
1440
+			}
1441
+			b := dAtA[iNdEx]
1442
+			iNdEx++
1443
+			wire |= (uint64(b) & 0x7F) << shift
1444
+			if b < 0x80 {
1445
+				break
1446
+			}
1447
+		}
1448
+		wireType := int(wire & 0x7)
1449
+		switch wireType {
1450
+		case 0:
1451
+			for shift := uint(0); ; shift += 7 {
1452
+				if shift >= 64 {
1453
+					return 0, ErrIntOverflowLeases
1454
+				}
1455
+				if iNdEx >= l {
1456
+					return 0, io.ErrUnexpectedEOF
1457
+				}
1458
+				iNdEx++
1459
+				if dAtA[iNdEx-1] < 0x80 {
1460
+					break
1461
+				}
1462
+			}
1463
+			return iNdEx, nil
1464
+		case 1:
1465
+			iNdEx += 8
1466
+			return iNdEx, nil
1467
+		case 2:
1468
+			var length int
1469
+			for shift := uint(0); ; shift += 7 {
1470
+				if shift >= 64 {
1471
+					return 0, ErrIntOverflowLeases
1472
+				}
1473
+				if iNdEx >= l {
1474
+					return 0, io.ErrUnexpectedEOF
1475
+				}
1476
+				b := dAtA[iNdEx]
1477
+				iNdEx++
1478
+				length |= (int(b) & 0x7F) << shift
1479
+				if b < 0x80 {
1480
+					break
1481
+				}
1482
+			}
1483
+			iNdEx += length
1484
+			if length < 0 {
1485
+				return 0, ErrInvalidLengthLeases
1486
+			}
1487
+			return iNdEx, nil
1488
+		case 3:
1489
+			for {
1490
+				var innerWire uint64
1491
+				var start int = iNdEx
1492
+				for shift := uint(0); ; shift += 7 {
1493
+					if shift >= 64 {
1494
+						return 0, ErrIntOverflowLeases
1495
+					}
1496
+					if iNdEx >= l {
1497
+						return 0, io.ErrUnexpectedEOF
1498
+					}
1499
+					b := dAtA[iNdEx]
1500
+					iNdEx++
1501
+					innerWire |= (uint64(b) & 0x7F) << shift
1502
+					if b < 0x80 {
1503
+						break
1504
+					}
1505
+				}
1506
+				innerWireType := int(innerWire & 0x7)
1507
+				if innerWireType == 4 {
1508
+					break
1509
+				}
1510
+				next, err := skipLeases(dAtA[start:])
1511
+				if err != nil {
1512
+					return 0, err
1513
+				}
1514
+				iNdEx = start + next
1515
+			}
1516
+			return iNdEx, nil
1517
+		case 4:
1518
+			return iNdEx, nil
1519
+		case 5:
1520
+			iNdEx += 4
1521
+			return iNdEx, nil
1522
+		default:
1523
+			return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
1524
+		}
1525
+	}
1526
+	panic("unreachable")
1527
+}
1528
+
1529
+var (
1530
+	ErrInvalidLengthLeases = fmt.Errorf("proto: negative length found during unmarshaling")
1531
+	ErrIntOverflowLeases   = fmt.Errorf("proto: integer overflow")
1532
+)
1533
+
1534
+func init() {
1535
+	proto.RegisterFile("github.com/containerd/containerd/api/services/leases/v1/leases.proto", fileDescriptorLeases)
1536
+}
1537
+
1538
+var fileDescriptorLeases = []byte{
1539
+	// 501 bytes of a gzipped FileDescriptorProto
1540
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x94, 0xdf, 0x8a, 0xd3, 0x40,
1541
+	0x14, 0xc6, 0x3b, 0xa9, 0x8d, 0xf6, 0xd4, 0x15, 0x19, 0x96, 0x25, 0x44, 0x4c, 0x4b, 0x10, 0xb6,
1542
+	0xf8, 0x67, 0xe2, 0xd6, 0x9b, 0x75, 0x15, 0xc1, 0x6e, 0x17, 0x14, 0x82, 0x48, 0xf0, 0x42, 0xbc,
1543
+	0x59, 0xd2, 0xf6, 0x6c, 0x0c, 0xa6, 0x9d, 0x98, 0x99, 0x16, 0x7a, 0xe7, 0x23, 0xf8, 0x08, 0x3e,
1544
+	0x84, 0x0f, 0xd1, 0x4b, 0x2f, 0xbd, 0x5a, 0xdd, 0xdc, 0xf9, 0x16, 0x92, 0x99, 0x84, 0xfd, 0x23,
1545
+	0xda, 0x2a, 0xde, 0x9d, 0xc9, 0x7c, 0xdf, 0x39, 0xbf, 0xf3, 0xc1, 0x04, 0x06, 0x51, 0x2c, 0xdf,
1546
+	0xce, 0x86, 0x6c, 0xc4, 0x27, 0xde, 0x88, 0x4f, 0x65, 0x18, 0x4f, 0x31, 0x1b, 0x9f, 0x2d, 0xc3,
1547
+	0x34, 0xf6, 0x04, 0x66, 0xf3, 0x78, 0x84, 0xc2, 0x4b, 0x30, 0x14, 0x28, 0xbc, 0xf9, 0x4e, 0x59,
1548
+	0xb1, 0x34, 0xe3, 0x92, 0xd3, 0x9b, 0xa7, 0x7a, 0x56, 0x69, 0x59, 0xa9, 0x98, 0xef, 0xd8, 0x9b,
1549
+	0x11, 0x8f, 0xb8, 0x52, 0x7a, 0x45, 0xa5, 0x4d, 0xf6, 0x8d, 0x88, 0xf3, 0x28, 0x41, 0x4f, 0x9d,
1550
+	0x86, 0xb3, 0x23, 0x0f, 0x27, 0xa9, 0x5c, 0x94, 0x97, 0xed, 0x8b, 0x97, 0x32, 0x9e, 0xa0, 0x90,
1551
+	0xe1, 0x24, 0xd5, 0x02, 0xf7, 0x07, 0x81, 0x86, 0x5f, 0x4c, 0xa0, 0x5b, 0x60, 0xc4, 0x63, 0x8b,
1552
+	0x74, 0x48, 0xb7, 0xd9, 0x37, 0xf3, 0xe3, 0xb6, 0xf1, 0x7c, 0x10, 0x18, 0xf1, 0x98, 0xee, 0x03,
1553
+	0x8c, 0x32, 0x0c, 0x25, 0x8e, 0x0f, 0x43, 0x69, 0x19, 0x1d, 0xd2, 0x6d, 0xf5, 0x6c, 0xa6, 0xfb,
1554
+	0xb2, 0xaa, 0x2f, 0x7b, 0x55, 0xf5, 0xed, 0x5f, 0x59, 0x1e, 0xb7, 0x6b, 0x1f, 0xbf, 0xb5, 0x49,
1555
+	0xd0, 0x2c, 0x7d, 0x4f, 0x25, 0x7d, 0x06, 0x66, 0x12, 0x0e, 0x31, 0x11, 0x56, 0xbd, 0x53, 0xef,
1556
+	0xb6, 0x7a, 0xf7, 0xd9, 0x1f, 0x57, 0x65, 0x0a, 0x89, 0xf9, 0xca, 0x72, 0x30, 0x95, 0xd9, 0x22,
1557
+	0x28, 0xfd, 0xf6, 0x43, 0x68, 0x9d, 0xf9, 0x4c, 0xaf, 0x43, 0xfd, 0x1d, 0x2e, 0x34, 0x76, 0x50,
1558
+	0x94, 0x74, 0x13, 0x1a, 0xf3, 0x30, 0x99, 0xa1, 0x42, 0x6d, 0x06, 0xfa, 0xb0, 0x67, 0xec, 0x12,
1559
+	0xf7, 0x33, 0x81, 0x8d, 0x7d, 0x85, 0x14, 0xe0, 0xfb, 0x19, 0x0a, 0xf9, 0xdb, 0x9d, 0x5f, 0x5e,
1560
+	0xc0, 0xdd, 0x5d, 0x81, 0x7b, 0xae, 0xeb, 0xff, 0xc6, 0xf6, 0xe1, 0x5a, 0xd5, 0x5f, 0xa4, 0x7c,
1561
+	0x2a, 0x90, 0xee, 0x41, 0x43, 0xcd, 0x56, 0xfe, 0x56, 0xef, 0xd6, 0x3a, 0x61, 0x06, 0xda, 0xe2,
1562
+	0x6e, 0xc3, 0xc6, 0x00, 0x13, 0x5c, 0x99, 0x81, 0xbb, 0x0d, 0x2d, 0x3f, 0x16, 0xb2, 0x92, 0x59,
1563
+	0x70, 0xf9, 0x28, 0x4e, 0x24, 0x66, 0xc2, 0x22, 0x9d, 0x7a, 0xb7, 0x19, 0x54, 0x47, 0xd7, 0x87,
1564
+	0xab, 0x5a, 0x58, 0xd2, 0x3d, 0x06, 0x53, 0xcf, 0x56, 0xc2, 0x75, 0xf1, 0x4a, 0x4f, 0xef, 0x93,
1565
+	0x01, 0xa6, 0xfa, 0x22, 0x28, 0x82, 0xa9, 0x17, 0xa7, 0x77, 0xff, 0x26, 0x7f, 0xfb, 0xde, 0x9a,
1566
+	0xea, 0x92, 0xf7, 0x05, 0x98, 0x3a, 0x91, 0x95, 0x63, 0xce, 0x05, 0x67, 0x6f, 0xfd, 0xf2, 0x08,
1567
+	0x0e, 0x8a, 0x97, 0x47, 0x0f, 0xe1, 0x52, 0x91, 0x07, 0xbd, 0xbd, 0x6a, 0xef, 0xd3, 0x74, 0xed,
1568
+	0x3b, 0x6b, 0x69, 0x35, 0x70, 0xff, 0xf5, 0xf2, 0xc4, 0xa9, 0x7d, 0x3d, 0x71, 0x6a, 0x1f, 0x72,
1569
+	0x87, 0x2c, 0x73, 0x87, 0x7c, 0xc9, 0x1d, 0xf2, 0x3d, 0x77, 0xc8, 0x9b, 0x27, 0xff, 0xf8, 0x1b,
1570
+	0x7a, 0xa4, 0xab, 0xa1, 0xa9, 0x56, 0x79, 0xf0, 0x33, 0x00, 0x00, 0xff, 0xff, 0x1d, 0xb9, 0xa6,
1571
+	0x63, 0xcf, 0x04, 0x00, 0x00,
1572
+}
0 1573
new file mode 100644
... ...
@@ -0,0 +1,58 @@
0
+syntax = "proto3";
1
+
2
+package containerd.services.leases.v1;
3
+
4
+import "gogoproto/gogo.proto";
5
+import "google/protobuf/empty.proto";
6
+import "google/protobuf/timestamp.proto";
7
+
8
+option go_package = "github.com/containerd/containerd/api/services/leases/v1;leases";
9
+
10
+// Leases service manages resources leases within the metadata store.
11
+service Leases {
12
+	// Create creates a new lease for managing changes to metadata. A lease
13
+	// can be used to protect objects from being removed.
14
+	rpc Create(CreateRequest) returns (CreateResponse);
15
+
16
+	// Delete deletes the lease and makes any unreferenced objects created
17
+	// during the lease eligible for garbage collection if not referenced
18
+	// or retained by other resources during the lease.
19
+	rpc Delete(DeleteRequest) returns (google.protobuf.Empty);
20
+
21
+	// ListTransactions lists all active leases, returning the full list of
22
+	// leases and optionally including the referenced resources.
23
+	rpc List(ListRequest) returns (ListResponse);
24
+}
25
+
26
+// Lease is an object which retains resources while it exists.
27
+message Lease {
28
+	string id = 1;
29
+
30
+	google.protobuf.Timestamp created_at = 2 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
31
+
32
+	map<string, string> labels = 3;
33
+}
34
+
35
+message CreateRequest {
36
+	// ID is used to identity the lease, when the id is not set the service
37
+	// generates a random identifier for the lease.
38
+	string id = 1;
39
+
40
+	map<string, string> labels = 3;
41
+}
42
+
43
+message CreateResponse {
44
+	Lease lease = 1;
45
+}
46
+
47
+message DeleteRequest {
48
+	string id = 1;
49
+}
50
+
51
+message ListRequest {
52
+	repeated string filters = 1;
53
+}
54
+
55
+message ListResponse {
56
+	repeated Lease leases = 1;
57
+}
... ...
@@ -22,9 +22,11 @@ import (
22 22
 	versionservice "github.com/containerd/containerd/api/services/version/v1"
23 23
 	"github.com/containerd/containerd/containers"
24 24
 	"github.com/containerd/containerd/content"
25
+	"github.com/containerd/containerd/dialer"
25 26
 	"github.com/containerd/containerd/diff"
26 27
 	"github.com/containerd/containerd/errdefs"
27 28
 	"github.com/containerd/containerd/images"
29
+	"github.com/containerd/containerd/namespaces"
28 30
 	"github.com/containerd/containerd/platforms"
29 31
 	"github.com/containerd/containerd/plugin"
30 32
 	"github.com/containerd/containerd/reference"
... ...
@@ -34,6 +36,7 @@ import (
34 34
 	contentservice "github.com/containerd/containerd/services/content"
35 35
 	diffservice "github.com/containerd/containerd/services/diff"
36 36
 	imagesservice "github.com/containerd/containerd/services/images"
37
+	namespacesservice "github.com/containerd/containerd/services/namespaces"
37 38
 	snapshotservice "github.com/containerd/containerd/services/snapshot"
38 39
 	"github.com/containerd/containerd/snapshot"
39 40
 	"github.com/containerd/typeurl"
... ...
@@ -70,7 +73,7 @@ func New(address string, opts ...ClientOpt) (*Client, error) {
70 70
 		grpc.WithTimeout(60 * time.Second),
71 71
 		grpc.FailOnNonTempDialError(true),
72 72
 		grpc.WithBackoffMaxDelay(3 * time.Second),
73
-		grpc.WithDialer(Dialer),
73
+		grpc.WithDialer(dialer.Dialer),
74 74
 	}
75 75
 	if len(copts.dialOptions) > 0 {
76 76
 		gopts = copts.dialOptions
... ...
@@ -82,7 +85,7 @@ func New(address string, opts ...ClientOpt) (*Client, error) {
82 82
 			grpc.WithStreamInterceptor(stream),
83 83
 		)
84 84
 	}
85
-	conn, err := grpc.Dial(DialAddress(address), gopts...)
85
+	conn, err := grpc.Dial(dialer.DialAddress(address), gopts...)
86 86
 	if err != nil {
87 87
 		return nil, errors.Wrapf(err, "failed to dial %q", address)
88 88
 	}
... ...
@@ -135,6 +138,12 @@ func (c *Client) Containers(ctx context.Context, filters ...string) ([]Container
135 135
 // NewContainer will create a new container in container with the provided id
136 136
 // the id must be unique within the namespace
137 137
 func (c *Client) NewContainer(ctx context.Context, id string, opts ...NewContainerOpts) (Container, error) {
138
+	ctx, done, err := c.withLease(ctx)
139
+	if err != nil {
140
+		return nil, err
141
+	}
142
+	defer done()
143
+
138 144
 	container := containers.Container{
139 145
 		ID: id,
140 146
 		Runtime: containers.RuntimeInfo{
... ...
@@ -210,6 +219,12 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image
210 210
 	}
211 211
 	store := c.ContentStore()
212 212
 
213
+	ctx, done, err := c.withLease(ctx)
214
+	if err != nil {
215
+		return nil, err
216
+	}
217
+	defer done()
218
+
213 219
 	name, desc, err := pullCtx.Resolver.Resolve(ctx, ref)
214 220
 	if err != nil {
215 221
 		return nil, err
... ...
@@ -228,7 +243,7 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image
228 228
 		handler = images.Handlers(append(pullCtx.BaseHandlers, schema1Converter)...)
229 229
 	} else {
230 230
 		handler = images.Handlers(append(pullCtx.BaseHandlers,
231
-			remotes.FetchHandler(store, fetcher, desc),
231
+			remotes.FetchHandler(store, fetcher),
232 232
 			images.ChildrenHandler(store, platforms.Default()))...,
233 233
 		)
234 234
 	}
... ...
@@ -265,11 +280,6 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image
265 265
 		imgrec = created
266 266
 	}
267 267
 
268
-	// Remove root tag from manifest now that image refers to it
269
-	if _, err := store.Update(ctx, content.Info{Digest: desc.Digest}, "labels.containerd.io/gc.root"); err != nil {
270
-		return nil, errors.Wrap(err, "failed to remove manifest root tag")
271
-	}
272
-
273 268
 	img := &image{
274 269
 		client: c,
275 270
 		i:      imgrec,
... ...
@@ -414,9 +424,9 @@ func (c *Client) Close() error {
414 414
 	return c.conn.Close()
415 415
 }
416 416
 
417
-// NamespaceService returns the underlying NamespacesClient
418
-func (c *Client) NamespaceService() namespacesapi.NamespacesClient {
419
-	return namespacesapi.NewNamespacesClient(c.conn)
417
+// NamespaceService returns the underlying Namespaces Store
418
+func (c *Client) NamespaceService() namespaces.Store {
419
+	return namespacesservice.NewStoreFromClient(namespacesapi.NewNamespacesClient(c.conn))
420 420
 }
421 421
 
422 422
 // ContainerService returns the underlying container Store
... ...
@@ -449,6 +459,7 @@ func (c *Client) DiffService() diff.Differ {
449 449
 	return diffservice.NewDiffServiceFromClient(diffapi.NewDiffClient(c.conn))
450 450
 }
451 451
 
452
+// IntrospectionService returns the underlying Introspection Client
452 453
 func (c *Client) IntrospectionService() introspectionapi.IntrospectionClient {
453 454
 	return introspectionapi.NewIntrospectionClient(c.conn)
454 455
 }
... ...
@@ -580,6 +591,13 @@ func (c *Client) Import(ctx context.Context, ref string, reader io.Reader, opts
580 580
 	if err != nil {
581 581
 		return nil, err
582 582
 	}
583
+
584
+	ctx, done, err := c.withLease(ctx)
585
+	if err != nil {
586
+		return nil, err
587
+	}
588
+	defer done()
589
+
583 590
 	switch iopts.format {
584 591
 	case ociImageFormat:
585 592
 		return c.importFromOCITar(ctx, ref, reader, iopts)
... ...
@@ -2,12 +2,10 @@ package containerd
2 2
 
3 3
 import (
4 4
 	"context"
5
-	"time"
6 5
 
7 6
 	"github.com/containerd/containerd/containers"
8 7
 	"github.com/containerd/containerd/errdefs"
9 8
 	"github.com/containerd/containerd/platforms"
10
-	"github.com/containerd/containerd/snapshot"
11 9
 	"github.com/containerd/typeurl"
12 10
 	"github.com/gogo/protobuf/types"
13 11
 	"github.com/opencontainers/image-spec/identity"
... ...
@@ -93,11 +91,8 @@ func WithNewSnapshot(id string, i Image) NewContainerOpts {
93 93
 			return err
94 94
 		}
95 95
 		setSnapshotterIfEmpty(c)
96
-		labels := map[string]string{
97
-			"containerd.io/gc.root": time.Now().String(),
98
-		}
99 96
 		parent := identity.ChainID(diffIDs).String()
100
-		if _, err := client.SnapshotService(c.Snapshotter).Prepare(ctx, id, parent, snapshot.WithLabels(labels)); err != nil {
97
+		if _, err := client.SnapshotService(c.Snapshotter).Prepare(ctx, id, parent); err != nil {
101 98
 			return err
102 99
 		}
103 100
 		c.SnapshotKey = id
... ...
@@ -126,11 +121,8 @@ func WithNewSnapshotView(id string, i Image) NewContainerOpts {
126 126
 			return err
127 127
 		}
128 128
 		setSnapshotterIfEmpty(c)
129
-		labels := map[string]string{
130
-			"containerd.io/gc.root": time.Now().String(),
131
-		}
132 129
 		parent := identity.ChainID(diffIDs).String()
133
-		if _, err := client.SnapshotService(c.Snapshotter).View(ctx, id, parent, snapshot.WithLabels(labels)); err != nil {
130
+		if _, err := client.SnapshotService(c.Snapshotter).View(ctx, id, parent); err != nil {
134 131
 			return err
135 132
 		}
136 133
 		c.SnapshotKey = id
... ...
@@ -8,6 +8,7 @@ import (
8 8
 	"os"
9 9
 	"path/filepath"
10 10
 	"strconv"
11
+	"strings"
11 12
 	"sync"
12 13
 	"time"
13 14
 
... ...
@@ -27,6 +28,19 @@ var (
27 27
 	}
28 28
 )
29 29
 
30
+// LabelStore is used to store mutable labels for digests
31
+type LabelStore interface {
32
+	// Get returns all the labels for the given digest
33
+	Get(digest.Digest) (map[string]string, error)
34
+
35
+	// Set sets all the labels for a given digest
36
+	Set(digest.Digest, map[string]string) error
37
+
38
+	// Update replaces the given labels for a digest,
39
+	// a key with an empty value removes a label.
40
+	Update(digest.Digest, map[string]string) (map[string]string, error)
41
+}
42
+
30 43
 // Store is digest-keyed store for content. All data written into the store is
31 44
 // stored under a verifiable digest.
32 45
 //
... ...
@@ -34,16 +48,27 @@ var (
34 34
 // including resumable ingest.
35 35
 type store struct {
36 36
 	root string
37
+	ls   LabelStore
37 38
 }
38 39
 
39 40
 // NewStore returns a local content store
40 41
 func NewStore(root string) (content.Store, error) {
42
+	return NewLabeledStore(root, nil)
43
+}
44
+
45
+// NewLabeledStore returns a new content store using the provided label store
46
+//
47
+// Note: content stores which are used underneath a metadata store may not
48
+// require labels and should use `NewStore`. `NewLabeledStore` is primarily
49
+// useful for tests or standalone implementations.
50
+func NewLabeledStore(root string, ls LabelStore) (content.Store, error) {
41 51
 	if err := os.MkdirAll(filepath.Join(root, "ingest"), 0777); err != nil && !os.IsExist(err) {
42 52
 		return nil, err
43 53
 	}
44 54
 
45 55
 	return &store{
46 56
 		root: root,
57
+		ls:   ls,
47 58
 	}, nil
48 59
 }
49 60
 
... ...
@@ -57,16 +82,23 @@ func (s *store) Info(ctx context.Context, dgst digest.Digest) (content.Info, err
57 57
 
58 58
 		return content.Info{}, err
59 59
 	}
60
-
61
-	return s.info(dgst, fi), nil
60
+	var labels map[string]string
61
+	if s.ls != nil {
62
+		labels, err = s.ls.Get(dgst)
63
+		if err != nil {
64
+			return content.Info{}, err
65
+		}
66
+	}
67
+	return s.info(dgst, fi, labels), nil
62 68
 }
63 69
 
64
-func (s *store) info(dgst digest.Digest, fi os.FileInfo) content.Info {
70
+func (s *store) info(dgst digest.Digest, fi os.FileInfo, labels map[string]string) content.Info {
65 71
 	return content.Info{
66 72
 		Digest:    dgst,
67 73
 		Size:      fi.Size(),
68 74
 		CreatedAt: fi.ModTime(),
69
-		UpdatedAt: fi.ModTime(),
75
+		UpdatedAt: getATime(fi),
76
+		Labels:    labels,
70 77
 	}
71 78
 }
72 79
 
... ...
@@ -111,8 +143,66 @@ func (s *store) Delete(ctx context.Context, dgst digest.Digest) error {
111 111
 }
112 112
 
113 113
 func (s *store) Update(ctx context.Context, info content.Info, fieldpaths ...string) (content.Info, error) {
114
-	// TODO: Support persisting and updating mutable content data
115
-	return content.Info{}, errors.Wrapf(errdefs.ErrFailedPrecondition, "update not supported on immutable content store")
114
+	if s.ls == nil {
115
+		return content.Info{}, errors.Wrapf(errdefs.ErrFailedPrecondition, "update not supported on immutable content store")
116
+	}
117
+
118
+	p := s.blobPath(info.Digest)
119
+	fi, err := os.Stat(p)
120
+	if err != nil {
121
+		if os.IsNotExist(err) {
122
+			err = errors.Wrapf(errdefs.ErrNotFound, "content %v", info.Digest)
123
+		}
124
+
125
+		return content.Info{}, err
126
+	}
127
+
128
+	var (
129
+		all    bool
130
+		labels map[string]string
131
+	)
132
+	if len(fieldpaths) > 0 {
133
+		for _, path := range fieldpaths {
134
+			if strings.HasPrefix(path, "labels.") {
135
+				if labels == nil {
136
+					labels = map[string]string{}
137
+				}
138
+
139
+				key := strings.TrimPrefix(path, "labels.")
140
+				labels[key] = info.Labels[key]
141
+				continue
142
+			}
143
+
144
+			switch path {
145
+			case "labels":
146
+				all = true
147
+				labels = info.Labels
148
+			default:
149
+				return content.Info{}, errors.Wrapf(errdefs.ErrInvalidArgument, "cannot update %q field on content info %q", path, info.Digest)
150
+			}
151
+		}
152
+	} else {
153
+		all = true
154
+		labels = info.Labels
155
+	}
156
+
157
+	if all {
158
+		err = s.ls.Set(info.Digest, labels)
159
+	} else {
160
+		labels, err = s.ls.Update(info.Digest, labels)
161
+	}
162
+	if err != nil {
163
+		return content.Info{}, err
164
+	}
165
+
166
+	info = s.info(info.Digest, fi, labels)
167
+	info.UpdatedAt = time.Now()
168
+
169
+	if err := os.Chtimes(p, info.UpdatedAt, info.CreatedAt); err != nil {
170
+		log.G(ctx).WithError(err).Warnf("could not change access time for %s", info.Digest)
171
+	}
172
+
173
+	return info, nil
116 174
 }
117 175
 
118 176
 func (s *store) Walk(ctx context.Context, fn content.WalkFunc, filters ...string) error {
... ...
@@ -154,7 +244,14 @@ func (s *store) Walk(ctx context.Context, fn content.WalkFunc, filters ...string
154 154
 			// store or extra paths not expected previously.
155 155
 		}
156 156
 
157
-		return fn(s.info(dgst, fi))
157
+		var labels map[string]string
158
+		if s.ls != nil {
159
+			labels, err = s.ls.Get(dgst)
160
+			if err != nil {
161
+				return err
162
+			}
163
+		}
164
+		return fn(s.info(dgst, fi, labels))
158 165
 	})
159 166
 }
160 167
 
... ...
@@ -18,3 +18,12 @@ func getStartTime(fi os.FileInfo) time.Time {
18 18
 
19 19
 	return fi.ModTime()
20 20
 }
21
+
22
+func getATime(fi os.FileInfo) time.Time {
23
+	if st, ok := fi.Sys().(*syscall.Stat_t); ok {
24
+		return time.Unix(int64(sys.StatAtime(st).Sec),
25
+			int64(sys.StatAtime(st).Nsec))
26
+	}
27
+
28
+	return fi.ModTime()
29
+}
... ...
@@ -8,3 +8,7 @@ import (
8 8
 func getStartTime(fi os.FileInfo) time.Time {
9 9
 	return fi.ModTime()
10 10
 }
11
+
12
+func getATime(fi os.FileInfo) time.Time {
13
+	return fi.ModTime()
14
+}
... ...
@@ -56,6 +56,13 @@ func (w *writer) Write(p []byte) (n int, err error) {
56 56
 }
57 57
 
58 58
 func (w *writer) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...content.Opt) error {
59
+	var base content.Info
60
+	for _, opt := range opts {
61
+		if err := opt(&base); err != nil {
62
+			return err
63
+		}
64
+	}
65
+
59 66
 	if w.fp == nil {
60 67
 		return errors.Wrap(errdefs.ErrFailedPrecondition, "cannot commit on closed writer")
61 68
 	}
... ...
@@ -123,6 +130,12 @@ func (w *writer) Commit(ctx context.Context, size int64, expected digest.Digest,
123 123
 	w.fp = nil
124 124
 	unlock(w.ref)
125 125
 
126
+	if w.s.ls != nil && base.Labels != nil {
127
+		if err := w.s.ls.Set(dgst, base.Labels); err != nil {
128
+			return err
129
+		}
130
+	}
131
+
126 132
 	return nil
127 133
 }
128 134
 
129 135
deleted file mode 100644
... ...
@@ -1,51 +0,0 @@
1
-package containerd
2
-
3
-import (
4
-	"net"
5
-	"time"
6
-
7
-	"github.com/pkg/errors"
8
-)
9
-
10
-type dialResult struct {
11
-	c   net.Conn
12
-	err error
13
-}
14
-
15
-// Dialer returns a GRPC net.Conn connected to the provided address
16
-func Dialer(address string, timeout time.Duration) (net.Conn, error) {
17
-	var (
18
-		stopC = make(chan struct{})
19
-		synC  = make(chan *dialResult)
20
-	)
21
-	go func() {
22
-		defer close(synC)
23
-		for {
24
-			select {
25
-			case <-stopC:
26
-				return
27
-			default:
28
-				c, err := dialer(address, timeout)
29
-				if isNoent(err) {
30
-					<-time.After(10 * time.Millisecond)
31
-					continue
32
-				}
33
-				synC <- &dialResult{c, err}
34
-				return
35
-			}
36
-		}
37
-	}()
38
-	select {
39
-	case dr := <-synC:
40
-		return dr.c, dr.err
41
-	case <-time.After(timeout):
42
-		close(stopC)
43
-		go func() {
44
-			dr := <-synC
45
-			if dr != nil {
46
-				dr.c.Close()
47
-			}
48
-		}()
49
-		return nil, errors.Errorf("dial %s: timeout", address)
50
-	}
51
-}
52 1
new file mode 100644
... ...
@@ -0,0 +1,51 @@
0
+package dialer
1
+
2
+import (
3
+	"net"
4
+	"time"
5
+
6
+	"github.com/pkg/errors"
7
+)
8
+
9
+type dialResult struct {
10
+	c   net.Conn
11
+	err error
12
+}
13
+
14
+// Dialer returns a GRPC net.Conn connected to the provided address
15
+func Dialer(address string, timeout time.Duration) (net.Conn, error) {
16
+	var (
17
+		stopC = make(chan struct{})
18
+		synC  = make(chan *dialResult)
19
+	)
20
+	go func() {
21
+		defer close(synC)
22
+		for {
23
+			select {
24
+			case <-stopC:
25
+				return
26
+			default:
27
+				c, err := dialer(address, timeout)
28
+				if isNoent(err) {
29
+					<-time.After(10 * time.Millisecond)
30
+					continue
31
+				}
32
+				synC <- &dialResult{c, err}
33
+				return
34
+			}
35
+		}
36
+	}()
37
+	select {
38
+	case dr := <-synC:
39
+		return dr.c, dr.err
40
+	case <-time.After(timeout):
41
+		close(stopC)
42
+		go func() {
43
+			dr := <-synC
44
+			if dr != nil {
45
+				dr.c.Close()
46
+			}
47
+		}()
48
+		return nil, errors.Errorf("dial %s: timeout", address)
49
+	}
50
+}
0 51
new file mode 100644
... ...
@@ -0,0 +1,36 @@
0
+// +build !windows
1
+
2
+package dialer
3
+
4
+import (
5
+	"fmt"
6
+	"net"
7
+	"os"
8
+	"strings"
9
+	"syscall"
10
+	"time"
11
+)
12
+
13
+// DialAddress returns the address with unix:// prepended to the
14
+// provided address
15
+func DialAddress(address string) string {
16
+	return fmt.Sprintf("unix://%s", address)
17
+}
18
+
19
+func isNoent(err error) bool {
20
+	if err != nil {
21
+		if nerr, ok := err.(*net.OpError); ok {
22
+			if serr, ok := nerr.Err.(*os.SyscallError); ok {
23
+				if serr.Err == syscall.ENOENT {
24
+					return true
25
+				}
26
+			}
27
+		}
28
+	}
29
+	return false
30
+}
31
+
32
+func dialer(address string, timeout time.Duration) (net.Conn, error) {
33
+	address = strings.TrimPrefix(address, "unix://")
34
+	return net.DialTimeout("unix", address, timeout)
35
+}
0 36
new file mode 100644
... ...
@@ -0,0 +1,30 @@
0
+package dialer
1
+
2
+import (
3
+	"net"
4
+	"os"
5
+	"syscall"
6
+	"time"
7
+
8
+	winio "github.com/Microsoft/go-winio"
9
+)
10
+
11
+func isNoent(err error) bool {
12
+	if err != nil {
13
+		if oerr, ok := err.(*os.PathError); ok {
14
+			if oerr.Err == syscall.ENOENT {
15
+				return true
16
+			}
17
+		}
18
+	}
19
+	return false
20
+}
21
+
22
+func dialer(address string, timeout time.Duration) (net.Conn, error) {
23
+	return winio.DialPipe(address, &timeout)
24
+}
25
+
26
+// DialAddress returns the dial address
27
+func DialAddress(address string) string {
28
+	return address
29
+}
0 30
deleted file mode 100644
... ...
@@ -1,36 +0,0 @@
1
-// +build !windows
2
-
3
-package containerd
4
-
5
-import (
6
-	"fmt"
7
-	"net"
8
-	"os"
9
-	"strings"
10
-	"syscall"
11
-	"time"
12
-)
13
-
14
-func isNoent(err error) bool {
15
-	if err != nil {
16
-		if nerr, ok := err.(*net.OpError); ok {
17
-			if serr, ok := nerr.Err.(*os.SyscallError); ok {
18
-				if serr.Err == syscall.ENOENT {
19
-					return true
20
-				}
21
-			}
22
-		}
23
-	}
24
-	return false
25
-}
26
-
27
-func dialer(address string, timeout time.Duration) (net.Conn, error) {
28
-	address = strings.TrimPrefix(address, "unix://")
29
-	return net.DialTimeout("unix", address, timeout)
30
-}
31
-
32
-// DialAddress returns the address with unix:// prepended to the
33
-// provided address
34
-func DialAddress(address string) string {
35
-	return fmt.Sprintf("unix://%s", address)
36
-}
37 1
deleted file mode 100644
... ...
@@ -1,29 +0,0 @@
1
-package containerd
2
-
3
-import (
4
-	"net"
5
-	"os"
6
-	"syscall"
7
-	"time"
8
-
9
-	winio "github.com/Microsoft/go-winio"
10
-)
11
-
12
-func isNoent(err error) bool {
13
-	if err != nil {
14
-		if oerr, ok := err.(*os.PathError); ok {
15
-			if oerr.Err == syscall.ENOENT {
16
-				return true
17
-			}
18
-		}
19
-	}
20
-	return false
21
-}
22
-
23
-func dialer(address string, timeout time.Duration) (net.Conn, error) {
24
-	return winio.DialPipe(address, &timeout)
25
-}
26
-
27
-func DialAddress(address string) string {
28
-	return address
29
-}
30 1
deleted file mode 100644
... ...
@@ -1,231 +0,0 @@
1
-package events
2
-
3
-import (
4
-	"context"
5
-	"strings"
6
-	"time"
7
-
8
-	events "github.com/containerd/containerd/api/services/events/v1"
9
-	"github.com/containerd/containerd/errdefs"
10
-	"github.com/containerd/containerd/filters"
11
-	"github.com/containerd/containerd/identifiers"
12
-	"github.com/containerd/containerd/log"
13
-	"github.com/containerd/containerd/namespaces"
14
-	"github.com/containerd/typeurl"
15
-	goevents "github.com/docker/go-events"
16
-	"github.com/gogo/protobuf/types"
17
-	"github.com/pkg/errors"
18
-	"github.com/sirupsen/logrus"
19
-)
20
-
21
-// Exchange broadcasts events
22
-type Exchange struct {
23
-	broadcaster *goevents.Broadcaster
24
-}
25
-
26
-// NewExchange returns a new event Exchange
27
-func NewExchange() *Exchange {
28
-	return &Exchange{
29
-		broadcaster: goevents.NewBroadcaster(),
30
-	}
31
-}
32
-
33
-// Forward accepts an envelope to be direcly distributed on the exchange.
34
-//
35
-// This is useful when an event is forwaded on behalf of another namespace or
36
-// when the event is propagated on behalf of another publisher.
37
-func (e *Exchange) Forward(ctx context.Context, envelope *events.Envelope) (err error) {
38
-	if err := validateEnvelope(envelope); err != nil {
39
-		return err
40
-	}
41
-
42
-	defer func() {
43
-		logger := log.G(ctx).WithFields(logrus.Fields{
44
-			"topic": envelope.Topic,
45
-			"ns":    envelope.Namespace,
46
-			"type":  envelope.Event.TypeUrl,
47
-		})
48
-
49
-		if err != nil {
50
-			logger.WithError(err).Error("error forwarding event")
51
-		} else {
52
-			logger.Debug("event forwarded")
53
-		}
54
-	}()
55
-
56
-	return e.broadcaster.Write(envelope)
57
-}
58
-
59
-// Publish packages and sends an event. The caller will be considered the
60
-// initial publisher of the event. This means the timestamp will be calculated
61
-// at this point and this method may read from the calling context.
62
-func (e *Exchange) Publish(ctx context.Context, topic string, event Event) (err error) {
63
-	var (
64
-		namespace string
65
-		encoded   *types.Any
66
-		envelope  events.Envelope
67
-	)
68
-
69
-	namespace, err = namespaces.NamespaceRequired(ctx)
70
-	if err != nil {
71
-		return errors.Wrapf(err, "failed publishing event")
72
-	}
73
-	if err := validateTopic(topic); err != nil {
74
-		return errors.Wrapf(err, "envelope topic %q", topic)
75
-	}
76
-
77
-	encoded, err = typeurl.MarshalAny(event)
78
-	if err != nil {
79
-		return err
80
-	}
81
-
82
-	envelope.Timestamp = time.Now().UTC()
83
-	envelope.Namespace = namespace
84
-	envelope.Topic = topic
85
-	envelope.Event = encoded
86
-
87
-	defer func() {
88
-		logger := log.G(ctx).WithFields(logrus.Fields{
89
-			"topic": envelope.Topic,
90
-			"ns":    envelope.Namespace,
91
-			"type":  envelope.Event.TypeUrl,
92
-		})
93
-
94
-		if err != nil {
95
-			logger.WithError(err).Error("error publishing event")
96
-		} else {
97
-			logger.Debug("event published")
98
-		}
99
-	}()
100
-
101
-	return e.broadcaster.Write(&envelope)
102
-}
103
-
104
-// Subscribe to events on the exchange. Events are sent through the returned
105
-// channel ch. If an error is encountered, it will be sent on channel errs and
106
-// errs will be closed. To end the subscription, cancel the provided context.
107
-//
108
-// Zero or more filters may be provided as strings. Only events that match
109
-// *any* of the provided filters will be sent on the channel. The filters use
110
-// the standard containerd filters package syntax.
111
-func (e *Exchange) Subscribe(ctx context.Context, fs ...string) (ch <-chan *events.Envelope, errs <-chan error) {
112
-	var (
113
-		evch                  = make(chan *events.Envelope)
114
-		errq                  = make(chan error, 1)
115
-		channel               = goevents.NewChannel(0)
116
-		queue                 = goevents.NewQueue(channel)
117
-		dst     goevents.Sink = queue
118
-	)
119
-
120
-	closeAll := func() {
121
-		defer close(errq)
122
-		defer e.broadcaster.Remove(dst)
123
-		defer queue.Close()
124
-		defer channel.Close()
125
-	}
126
-
127
-	ch = evch
128
-	errs = errq
129
-
130
-	if len(fs) > 0 {
131
-		filter, err := filters.ParseAll(fs...)
132
-		if err != nil {
133
-			errq <- errors.Wrapf(err, "failed parsing subscription filters")
134
-			closeAll()
135
-			return
136
-		}
137
-
138
-		dst = goevents.NewFilter(queue, goevents.MatcherFunc(func(gev goevents.Event) bool {
139
-			return filter.Match(adapt(gev))
140
-		}))
141
-	}
142
-
143
-	e.broadcaster.Add(dst)
144
-
145
-	go func() {
146
-		defer closeAll()
147
-
148
-		var err error
149
-	loop:
150
-		for {
151
-			select {
152
-			case ev := <-channel.C:
153
-				env, ok := ev.(*events.Envelope)
154
-				if !ok {
155
-					// TODO(stevvooe): For the most part, we are well protected
156
-					// from this condition. Both Forward and Publish protect
157
-					// from this.
158
-					err = errors.Errorf("invalid envelope encountered %#v; please file a bug", ev)
159
-					break
160
-				}
161
-
162
-				select {
163
-				case evch <- env:
164
-				case <-ctx.Done():
165
-					break loop
166
-				}
167
-			case <-ctx.Done():
168
-				break loop
169
-			}
170
-		}
171
-
172
-		if err == nil {
173
-			if cerr := ctx.Err(); cerr != context.Canceled {
174
-				err = cerr
175
-			}
176
-		}
177
-
178
-		errq <- err
179
-	}()
180
-
181
-	return
182
-}
183
-
184
-func validateTopic(topic string) error {
185
-	if topic == "" {
186
-		return errors.Wrap(errdefs.ErrInvalidArgument, "must not be empty")
187
-	}
188
-
189
-	if topic[0] != '/' {
190
-		return errors.Wrapf(errdefs.ErrInvalidArgument, "must start with '/'")
191
-	}
192
-
193
-	if len(topic) == 1 {
194
-		return errors.Wrapf(errdefs.ErrInvalidArgument, "must have at least one component")
195
-	}
196
-
197
-	components := strings.Split(topic[1:], "/")
198
-	for _, component := range components {
199
-		if err := identifiers.Validate(component); err != nil {
200
-			return errors.Wrapf(err, "failed validation on component %q", component)
201
-		}
202
-	}
203
-
204
-	return nil
205
-}
206
-
207
-func validateEnvelope(envelope *events.Envelope) error {
208
-	if err := namespaces.Validate(envelope.Namespace); err != nil {
209
-		return errors.Wrapf(err, "event envelope has invalid namespace")
210
-	}
211
-
212
-	if err := validateTopic(envelope.Topic); err != nil {
213
-		return errors.Wrapf(err, "envelope topic %q", envelope.Topic)
214
-	}
215
-
216
-	if envelope.Timestamp.IsZero() {
217
-		return errors.Wrapf(errdefs.ErrInvalidArgument, "timestamp must be set on forwarded event")
218
-	}
219
-
220
-	return nil
221
-}
222
-
223
-func adapt(ev interface{}) filters.Adaptor {
224
-	if adaptor, ok := ev.(filters.Adaptor); ok {
225
-		return adaptor
226
-	}
227
-
228
-	return filters.AdapterFunc(func(fieldpath []string) (string, bool) {
229
-		return "", false
230
-	})
231
-}
232 1
new file mode 100644
... ...
@@ -0,0 +1,232 @@
0
+package exchange
1
+
2
+import (
3
+	"context"
4
+	"strings"
5
+	"time"
6
+
7
+	v1 "github.com/containerd/containerd/api/services/events/v1"
8
+	"github.com/containerd/containerd/errdefs"
9
+	"github.com/containerd/containerd/events"
10
+	"github.com/containerd/containerd/filters"
11
+	"github.com/containerd/containerd/identifiers"
12
+	"github.com/containerd/containerd/log"
13
+	"github.com/containerd/containerd/namespaces"
14
+	"github.com/containerd/typeurl"
15
+	goevents "github.com/docker/go-events"
16
+	"github.com/gogo/protobuf/types"
17
+	"github.com/pkg/errors"
18
+	"github.com/sirupsen/logrus"
19
+)
20
+
21
+// Exchange broadcasts events
22
+type Exchange struct {
23
+	broadcaster *goevents.Broadcaster
24
+}
25
+
26
+// NewExchange returns a new event Exchange
27
+func NewExchange() *Exchange {
28
+	return &Exchange{
29
+		broadcaster: goevents.NewBroadcaster(),
30
+	}
31
+}
32
+
33
+// Forward accepts an envelope to be direcly distributed on the exchange.
34
+//
35
+// This is useful when an event is forwaded on behalf of another namespace or
36
+// when the event is propagated on behalf of another publisher.
37
+func (e *Exchange) Forward(ctx context.Context, envelope *v1.Envelope) (err error) {
38
+	if err := validateEnvelope(envelope); err != nil {
39
+		return err
40
+	}
41
+
42
+	defer func() {
43
+		logger := log.G(ctx).WithFields(logrus.Fields{
44
+			"topic": envelope.Topic,
45
+			"ns":    envelope.Namespace,
46
+			"type":  envelope.Event.TypeUrl,
47
+		})
48
+
49
+		if err != nil {
50
+			logger.WithError(err).Error("error forwarding event")
51
+		} else {
52
+			logger.Debug("event forwarded")
53
+		}
54
+	}()
55
+
56
+	return e.broadcaster.Write(envelope)
57
+}
58
+
59
+// Publish packages and sends an event. The caller will be considered the
60
+// initial publisher of the event. This means the timestamp will be calculated
61
+// at this point and this method may read from the calling context.
62
+func (e *Exchange) Publish(ctx context.Context, topic string, event events.Event) (err error) {
63
+	var (
64
+		namespace string
65
+		encoded   *types.Any
66
+		envelope  v1.Envelope
67
+	)
68
+
69
+	namespace, err = namespaces.NamespaceRequired(ctx)
70
+	if err != nil {
71
+		return errors.Wrapf(err, "failed publishing event")
72
+	}
73
+	if err := validateTopic(topic); err != nil {
74
+		return errors.Wrapf(err, "envelope topic %q", topic)
75
+	}
76
+
77
+	encoded, err = typeurl.MarshalAny(event)
78
+	if err != nil {
79
+		return err
80
+	}
81
+
82
+	envelope.Timestamp = time.Now().UTC()
83
+	envelope.Namespace = namespace
84
+	envelope.Topic = topic
85
+	envelope.Event = encoded
86
+
87
+	defer func() {
88
+		logger := log.G(ctx).WithFields(logrus.Fields{
89
+			"topic": envelope.Topic,
90
+			"ns":    envelope.Namespace,
91
+			"type":  envelope.Event.TypeUrl,
92
+		})
93
+
94
+		if err != nil {
95
+			logger.WithError(err).Error("error publishing event")
96
+		} else {
97
+			logger.Debug("event published")
98
+		}
99
+	}()
100
+
101
+	return e.broadcaster.Write(&envelope)
102
+}
103
+
104
+// Subscribe to events on the exchange. Events are sent through the returned
105
+// channel ch. If an error is encountered, it will be sent on channel errs and
106
+// errs will be closed. To end the subscription, cancel the provided context.
107
+//
108
+// Zero or more filters may be provided as strings. Only events that match
109
+// *any* of the provided filters will be sent on the channel. The filters use
110
+// the standard containerd filters package syntax.
111
+func (e *Exchange) Subscribe(ctx context.Context, fs ...string) (ch <-chan *v1.Envelope, errs <-chan error) {
112
+	var (
113
+		evch                  = make(chan *v1.Envelope)
114
+		errq                  = make(chan error, 1)
115
+		channel               = goevents.NewChannel(0)
116
+		queue                 = goevents.NewQueue(channel)
117
+		dst     goevents.Sink = queue
118
+	)
119
+
120
+	closeAll := func() {
121
+		defer close(errq)
122
+		defer e.broadcaster.Remove(dst)
123
+		defer queue.Close()
124
+		defer channel.Close()
125
+	}
126
+
127
+	ch = evch
128
+	errs = errq
129
+
130
+	if len(fs) > 0 {
131
+		filter, err := filters.ParseAll(fs...)
132
+		if err != nil {
133
+			errq <- errors.Wrapf(err, "failed parsing subscription filters")
134
+			closeAll()
135
+			return
136
+		}
137
+
138
+		dst = goevents.NewFilter(queue, goevents.MatcherFunc(func(gev goevents.Event) bool {
139
+			return filter.Match(adapt(gev))
140
+		}))
141
+	}
142
+
143
+	e.broadcaster.Add(dst)
144
+
145
+	go func() {
146
+		defer closeAll()
147
+
148
+		var err error
149
+	loop:
150
+		for {
151
+			select {
152
+			case ev := <-channel.C:
153
+				env, ok := ev.(*v1.Envelope)
154
+				if !ok {
155
+					// TODO(stevvooe): For the most part, we are well protected
156
+					// from this condition. Both Forward and Publish protect
157
+					// from this.
158
+					err = errors.Errorf("invalid envelope encountered %#v; please file a bug", ev)
159
+					break
160
+				}
161
+
162
+				select {
163
+				case evch <- env:
164
+				case <-ctx.Done():
165
+					break loop
166
+				}
167
+			case <-ctx.Done():
168
+				break loop
169
+			}
170
+		}
171
+
172
+		if err == nil {
173
+			if cerr := ctx.Err(); cerr != context.Canceled {
174
+				err = cerr
175
+			}
176
+		}
177
+
178
+		errq <- err
179
+	}()
180
+
181
+	return
182
+}
183
+
184
+func validateTopic(topic string) error {
185
+	if topic == "" {
186
+		return errors.Wrap(errdefs.ErrInvalidArgument, "must not be empty")
187
+	}
188
+
189
+	if topic[0] != '/' {
190
+		return errors.Wrapf(errdefs.ErrInvalidArgument, "must start with '/'")
191
+	}
192
+
193
+	if len(topic) == 1 {
194
+		return errors.Wrapf(errdefs.ErrInvalidArgument, "must have at least one component")
195
+	}
196
+
197
+	components := strings.Split(topic[1:], "/")
198
+	for _, component := range components {
199
+		if err := identifiers.Validate(component); err != nil {
200
+			return errors.Wrapf(err, "failed validation on component %q", component)
201
+		}
202
+	}
203
+
204
+	return nil
205
+}
206
+
207
+func validateEnvelope(envelope *v1.Envelope) error {
208
+	if err := namespaces.Validate(envelope.Namespace); err != nil {
209
+		return errors.Wrapf(err, "event envelope has invalid namespace")
210
+	}
211
+
212
+	if err := validateTopic(envelope.Topic); err != nil {
213
+		return errors.Wrapf(err, "envelope topic %q", envelope.Topic)
214
+	}
215
+
216
+	if envelope.Timestamp.IsZero() {
217
+		return errors.Wrapf(errdefs.ErrInvalidArgument, "timestamp must be set on forwarded event")
218
+	}
219
+
220
+	return nil
221
+}
222
+
223
+func adapt(ev interface{}) filters.Adaptor {
224
+	if adaptor, ok := ev.(filters.Adaptor); ok {
225
+		return adaptor
226
+	}
227
+
228
+	return filters.AdapterFunc(func(fieldpath []string) (string, bool) {
229
+		return "", false
230
+	})
231
+}
... ...
@@ -10,7 +10,7 @@ import (
10 10
 	"sync"
11 11
 )
12 12
 
13
-// Resourcetype represents type of resource at a node
13
+// ResourceType represents type of resource at a node
14 14
 type ResourceType uint8
15 15
 
16 16
 // Node presents a resource which has a type and key,
... ...
@@ -145,10 +145,10 @@ func ConcurrentMark(ctx context.Context, root <-chan Node, refs func(context.Con
145 145
 
146 146
 // Sweep removes all nodes returned through the channel which are not in
147 147
 // the reachable set by calling the provided remove function.
148
-func Sweep(reachable map[Node]struct{}, all <-chan Node, remove func(Node) error) error {
148
+func Sweep(reachable map[Node]struct{}, all []Node, remove func(Node) error) error {
149 149
 	// All black objects are now reachable, and all white objects are
150 150
 	// unreachable. Free those that are white!
151
-	for node := range all {
151
+	for _, node := range all {
152 152
 		if _, ok := reachable[node]; !ok {
153 153
 			if err := remove(node); err != nil {
154 154
 				return err
... ...
@@ -3,9 +3,9 @@ package containerd
3 3
 import (
4 4
 	"context"
5 5
 	"fmt"
6
-	"time"
7 6
 
8 7
 	"github.com/containerd/containerd/content"
8
+	"github.com/containerd/containerd/errdefs"
9 9
 	"github.com/containerd/containerd/images"
10 10
 	"github.com/containerd/containerd/platforms"
11 11
 	"github.com/containerd/containerd/rootfs"
... ...
@@ -30,6 +30,8 @@ type Image interface {
30 30
 	Size(ctx context.Context) (int64, error)
31 31
 	// Config descriptor for the image.
32 32
 	Config(ctx context.Context) (ocispec.Descriptor, error)
33
+	// IsUnpacked returns whether or not an image is unpacked.
34
+	IsUnpacked(context.Context, string) (bool, error)
33 35
 }
34 36
 
35 37
 var _ = (Image)(&image{})
... ...
@@ -63,6 +65,26 @@ func (i *image) Config(ctx context.Context) (ocispec.Descriptor, error) {
63 63
 	return i.i.Config(ctx, provider, platforms.Default())
64 64
 }
65 65
 
66
+func (i *image) IsUnpacked(ctx context.Context, snapshotterName string) (bool, error) {
67
+	sn := i.client.SnapshotService(snapshotterName)
68
+	cs := i.client.ContentStore()
69
+
70
+	diffs, err := i.i.RootFS(ctx, cs, platforms.Default())
71
+	if err != nil {
72
+		return false, err
73
+	}
74
+
75
+	chainID := identity.ChainID(diffs)
76
+	_, err = sn.Stat(ctx, chainID.String())
77
+	if err == nil {
78
+		return true, nil
79
+	} else if !errdefs.IsNotFound(err) {
80
+		return false, err
81
+	}
82
+
83
+	return false, nil
84
+}
85
+
66 86
 func (i *image) Unpack(ctx context.Context, snapshotterName string) error {
67 87
 	layers, err := i.getLayers(ctx, platforms.Default())
68 88
 	if err != nil {
... ...
@@ -79,27 +101,14 @@ func (i *image) Unpack(ctx context.Context, snapshotterName string) error {
79 79
 	)
80 80
 	for _, layer := range layers {
81 81
 		labels := map[string]string{
82
-			"containerd.io/gc.root":      time.Now().UTC().Format(time.RFC3339),
83 82
 			"containerd.io/uncompressed": layer.Diff.Digest.String(),
84 83
 		}
85
-		lastUnpacked := unpacked
86 84
 
87 85
 		unpacked, err = rootfs.ApplyLayer(ctx, layer, chain, sn, a, snapshot.WithLabels(labels))
88 86
 		if err != nil {
89 87
 			return err
90 88
 		}
91 89
 
92
-		if lastUnpacked {
93
-			info := snapshot.Info{
94
-				Name: identity.ChainID(chain).String(),
95
-			}
96
-
97
-			// Remove previously created gc.root label
98
-			if _, err := sn.Update(ctx, info, "labels.containerd.io/gc.root"); err != nil {
99
-				return err
100
-			}
101
-		}
102
-
103 90
 		chain = append(chain, layer.Diff.Digest)
104 91
 	}
105 92
 
... ...
@@ -120,15 +129,6 @@ func (i *image) Unpack(ctx context.Context, snapshotterName string) error {
120 120
 		if _, err := cs.Update(ctx, cinfo, fmt.Sprintf("labels.containerd.io/gc.ref.snapshot.%s", snapshotterName)); err != nil {
121 121
 			return err
122 122
 		}
123
-
124
-		sinfo := snapshot.Info{
125
-			Name: rootfs,
126
-		}
127
-
128
-		// Config now referenced snapshot, release root reference
129
-		if _, err := sn.Update(ctx, sinfo, "labels.containerd.io/gc.root"); err != nil {
130
-			return err
131
-		}
132 123
 	}
133 124
 
134 125
 	return nil
... ...
@@ -16,7 +16,7 @@ import (
16 16
 
17 17
 // NewFifos returns a new set of fifos for the task
18 18
 func NewFifos(id string) (*FIFOSet, error) {
19
-	root := filepath.Join(os.TempDir(), "containerd")
19
+	root := "/run/containerd/fifo"
20 20
 	if err := os.MkdirAll(root, 0700); err != nil {
21 21
 		return nil, err
22 22
 	}
23 23
new file mode 100644
... ...
@@ -0,0 +1,91 @@
0
+package containerd
1
+
2
+import (
3
+	"context"
4
+	"time"
5
+
6
+	leasesapi "github.com/containerd/containerd/api/services/leases/v1"
7
+	"github.com/containerd/containerd/leases"
8
+)
9
+
10
+// Lease is used to hold a reference to active resources which have not been
11
+// referenced by a root resource. This is useful for preventing garbage
12
+// collection of resources while they are actively being updated.
13
+type Lease struct {
14
+	id        string
15
+	createdAt time.Time
16
+
17
+	client *Client
18
+}
19
+
20
+// CreateLease creates a new lease
21
+func (c *Client) CreateLease(ctx context.Context) (Lease, error) {
22
+	lapi := leasesapi.NewLeasesClient(c.conn)
23
+	resp, err := lapi.Create(ctx, &leasesapi.CreateRequest{})
24
+	if err != nil {
25
+		return Lease{}, err
26
+	}
27
+
28
+	return Lease{
29
+		id:     resp.Lease.ID,
30
+		client: c,
31
+	}, nil
32
+}
33
+
34
+// ListLeases lists active leases
35
+func (c *Client) ListLeases(ctx context.Context) ([]Lease, error) {
36
+	lapi := leasesapi.NewLeasesClient(c.conn)
37
+	resp, err := lapi.List(ctx, &leasesapi.ListRequest{})
38
+	if err != nil {
39
+		return nil, err
40
+	}
41
+	leases := make([]Lease, len(resp.Leases))
42
+	for i := range resp.Leases {
43
+		leases[i] = Lease{
44
+			id:        resp.Leases[i].ID,
45
+			createdAt: resp.Leases[i].CreatedAt,
46
+			client:    c,
47
+		}
48
+	}
49
+
50
+	return leases, nil
51
+}
52
+
53
+func (c *Client) withLease(ctx context.Context) (context.Context, func() error, error) {
54
+	_, ok := leases.Lease(ctx)
55
+	if ok {
56
+		return ctx, func() error {
57
+			return nil
58
+		}, nil
59
+	}
60
+
61
+	l, err := c.CreateLease(ctx)
62
+	if err != nil {
63
+		return nil, nil, err
64
+	}
65
+
66
+	ctx = leases.WithLease(ctx, l.ID())
67
+	return ctx, func() error {
68
+		return l.Delete(ctx)
69
+	}, nil
70
+}
71
+
72
+// ID returns the lease ID
73
+func (l Lease) ID() string {
74
+	return l.id
75
+}
76
+
77
+// CreatedAt returns the time at which the lease was created
78
+func (l Lease) CreatedAt() time.Time {
79
+	return l.createdAt
80
+}
81
+
82
+// Delete deletes the lease, removing the reference to all resources created
83
+// during the lease.
84
+func (l Lease) Delete(ctx context.Context) error {
85
+	lapi := leasesapi.NewLeasesClient(l.client.conn)
86
+	_, err := lapi.Delete(ctx, &leasesapi.DeleteRequest{
87
+		ID: l.id,
88
+	})
89
+	return err
90
+}
0 91
new file mode 100644
... ...
@@ -0,0 +1,24 @@
0
+package leases
1
+
2
+import "context"
3
+
4
+type leaseKey struct{}
5
+
6
+// WithLease sets a given lease on the context
7
+func WithLease(ctx context.Context, lid string) context.Context {
8
+	ctx = context.WithValue(ctx, leaseKey{}, lid)
9
+
10
+	// also store on the grpc headers so it gets picked up by any clients that
11
+	// are using this.
12
+	return withGRPCLeaseHeader(ctx, lid)
13
+}
14
+
15
+// Lease returns the lease from the context.
16
+func Lease(ctx context.Context) (string, bool) {
17
+	lid, ok := ctx.Value(leaseKey{}).(string)
18
+	if !ok {
19
+		return fromGRPCHeader(ctx)
20
+	}
21
+
22
+	return lid, ok
23
+}
0 24
new file mode 100644
... ...
@@ -0,0 +1,41 @@
0
+package leases
1
+
2
+import (
3
+	"golang.org/x/net/context"
4
+	"google.golang.org/grpc/metadata"
5
+)
6
+
7
+const (
8
+	// GRPCHeader defines the header name for specifying a containerd lease.
9
+	GRPCHeader = "containerd-lease"
10
+)
11
+
12
+func withGRPCLeaseHeader(ctx context.Context, lid string) context.Context {
13
+	// also store on the grpc headers so it gets picked up by any clients
14
+	// that are using this.
15
+	txheader := metadata.Pairs(GRPCHeader, lid)
16
+	md, ok := metadata.FromOutgoingContext(ctx) // merge with outgoing context.
17
+	if !ok {
18
+		md = txheader
19
+	} else {
20
+		// order ensures the latest is first in this list.
21
+		md = metadata.Join(txheader, md)
22
+	}
23
+
24
+	return metadata.NewOutgoingContext(ctx, md)
25
+}
26
+
27
+func fromGRPCHeader(ctx context.Context) (string, bool) {
28
+	// try to extract for use in grpc servers.
29
+	md, ok := metadata.FromIncomingContext(ctx)
30
+	if !ok {
31
+		return "", false
32
+	}
33
+
34
+	values := md[GRPCHeader]
35
+	if len(values) == 0 {
36
+		return "", false
37
+	}
38
+
39
+	return values[0], true
40
+}
... ...
@@ -9,9 +9,10 @@ import (
9 9
 	"os"
10 10
 	"path/filepath"
11 11
 
12
-	"github.com/containerd/containerd/events"
12
+	"github.com/containerd/containerd/events/exchange"
13 13
 	"github.com/containerd/containerd/linux/runcopts"
14
-	client "github.com/containerd/containerd/linux/shim"
14
+	"github.com/containerd/containerd/linux/shim"
15
+	"github.com/containerd/containerd/linux/shim/client"
15 16
 	"github.com/pkg/errors"
16 17
 )
17 18
 
... ...
@@ -70,32 +71,33 @@ type bundle struct {
70 70
 	workDir string
71 71
 }
72 72
 
73
-type shimOpt func(*bundle, string, *runcopts.RuncOptions) (client.Config, client.ClientOpt)
73
+// ShimOpt specifies shim options for initialization and connection
74
+type ShimOpt func(*bundle, string, *runcopts.RuncOptions) (shim.Config, client.Opt)
74 75
 
75
-// ShimRemote is a shimOpt for connecting and starting a remote shim
76
-func ShimRemote(shim, daemonAddress, cgroup string, nonewns, debug bool, exitHandler func()) shimOpt {
77
-	return func(b *bundle, ns string, ropts *runcopts.RuncOptions) (client.Config, client.ClientOpt) {
76
+// ShimRemote is a ShimOpt for connecting and starting a remote shim
77
+func ShimRemote(shimBinary, daemonAddress, cgroup string, nonewns, debug bool, exitHandler func()) ShimOpt {
78
+	return func(b *bundle, ns string, ropts *runcopts.RuncOptions) (shim.Config, client.Opt) {
78 79
 		return b.shimConfig(ns, ropts),
79
-			client.WithStart(shim, b.shimAddress(ns), daemonAddress, cgroup, nonewns, debug, exitHandler)
80
+			client.WithStart(shimBinary, b.shimAddress(ns), daemonAddress, cgroup, nonewns, debug, exitHandler)
80 81
 	}
81 82
 }
82 83
 
83
-// ShimLocal is a shimOpt for using an in process shim implementation
84
-func ShimLocal(exchange *events.Exchange) shimOpt {
85
-	return func(b *bundle, ns string, ropts *runcopts.RuncOptions) (client.Config, client.ClientOpt) {
84
+// ShimLocal is a ShimOpt for using an in process shim implementation
85
+func ShimLocal(exchange *exchange.Exchange) ShimOpt {
86
+	return func(b *bundle, ns string, ropts *runcopts.RuncOptions) (shim.Config, client.Opt) {
86 87
 		return b.shimConfig(ns, ropts), client.WithLocal(exchange)
87 88
 	}
88 89
 }
89 90
 
90
-// ShimConnect is a shimOpt for connecting to an existing remote shim
91
-func ShimConnect() shimOpt {
92
-	return func(b *bundle, ns string, ropts *runcopts.RuncOptions) (client.Config, client.ClientOpt) {
91
+// ShimConnect is a ShimOpt for connecting to an existing remote shim
92
+func ShimConnect() ShimOpt {
93
+	return func(b *bundle, ns string, ropts *runcopts.RuncOptions) (shim.Config, client.Opt) {
93 94
 		return b.shimConfig(ns, ropts), client.WithConnect(b.shimAddress(ns))
94 95
 	}
95 96
 }
96 97
 
97 98
 // NewShimClient connects to the shim managing the bundle and tasks creating it if needed
98
-func (b *bundle) NewShimClient(ctx context.Context, namespace string, getClientOpts shimOpt, runcOpts *runcopts.RuncOptions) (*client.Client, error) {
99
+func (b *bundle) NewShimClient(ctx context.Context, namespace string, getClientOpts ShimOpt, runcOpts *runcopts.RuncOptions) (*client.Client, error) {
99 100
 	cfg, opt := getClientOpts(b, namespace, runcOpts)
100 101
 	return client.New(ctx, cfg, opt)
101 102
 }
... ...
@@ -118,7 +120,7 @@ func (b *bundle) shimAddress(namespace string) string {
118 118
 	return filepath.Join(string(filepath.Separator), "containerd-shim", namespace, b.id, "shim.sock")
119 119
 }
120 120
 
121
-func (b *bundle) shimConfig(namespace string, runcOptions *runcopts.RuncOptions) client.Config {
121
+func (b *bundle) shimConfig(namespace string, runcOptions *runcopts.RuncOptions) shim.Config {
122 122
 	var (
123 123
 		criuPath      string
124 124
 		runtimeRoot   string
... ...
@@ -129,7 +131,7 @@ func (b *bundle) shimConfig(namespace string, runcOptions *runcopts.RuncOptions)
129 129
 		systemdCgroup = runcOptions.SystemdCgroup
130 130
 		runtimeRoot = runcOptions.RuntimeRoot
131 131
 	}
132
-	return client.Config{
132
+	return shim.Config{
133 133
 		Path:          b.path,
134 134
 		WorkDir:       b.workDir,
135 135
 		Namespace:     namespace,
... ...
@@ -15,7 +15,7 @@ import (
15 15
 	"github.com/containerd/containerd/api/types"
16 16
 	"github.com/containerd/containerd/containers"
17 17
 	"github.com/containerd/containerd/errdefs"
18
-	"github.com/containerd/containerd/events"
18
+	"github.com/containerd/containerd/events/exchange"
19 19
 	"github.com/containerd/containerd/identifiers"
20 20
 	"github.com/containerd/containerd/linux/runcopts"
21 21
 	client "github.com/containerd/containerd/linux/shim"
... ...
@@ -143,7 +143,7 @@ type Runtime struct {
143 143
 	monitor runtime.TaskMonitor
144 144
 	tasks   *runtime.TaskList
145 145
 	db      *metadata.DB
146
-	events  *events.Exchange
146
+	events  *exchange.Exchange
147 147
 
148 148
 	config *Config
149 149
 }
150 150
deleted file mode 100644
... ...
@@ -1,282 +0,0 @@
1
-// +build !windows
2
-
3
-package shim
4
-
5
-import (
6
-	"context"
7
-	"fmt"
8
-	"io"
9
-	"net"
10
-	"os"
11
-	"os/exec"
12
-	"strings"
13
-	"sync"
14
-	"syscall"
15
-	"time"
16
-
17
-	"golang.org/x/sys/unix"
18
-
19
-	"github.com/pkg/errors"
20
-	"github.com/sirupsen/logrus"
21
-
22
-	"github.com/containerd/containerd/events"
23
-	shim "github.com/containerd/containerd/linux/shim/v1"
24
-	"github.com/containerd/containerd/log"
25
-	"github.com/containerd/containerd/reaper"
26
-	"github.com/containerd/containerd/sys"
27
-	"google.golang.org/grpc"
28
-)
29
-
30
-// ClientOpt is an option for a shim client configuration
31
-type ClientOpt func(context.Context, Config) (shim.ShimClient, io.Closer, error)
32
-
33
-// WithStart executes a new shim process
34
-func WithStart(binary, address, daemonAddress, cgroup string, nonewns, debug bool, exitHandler func()) ClientOpt {
35
-	return func(ctx context.Context, config Config) (_ shim.ShimClient, _ io.Closer, err error) {
36
-		socket, err := newSocket(address)
37
-		if err != nil {
38
-			return nil, nil, err
39
-		}
40
-		defer socket.Close()
41
-		f, err := socket.File()
42
-		if err != nil {
43
-			return nil, nil, errors.Wrapf(err, "failed to get fd for socket %s", address)
44
-		}
45
-		defer f.Close()
46
-
47
-		cmd := newCommand(binary, daemonAddress, nonewns, debug, config, f)
48
-		ec, err := reaper.Default.Start(cmd)
49
-		if err != nil {
50
-			return nil, nil, errors.Wrapf(err, "failed to start shim")
51
-		}
52
-		defer func() {
53
-			if err != nil {
54
-				cmd.Process.Kill()
55
-			}
56
-		}()
57
-		go func() {
58
-			reaper.Default.Wait(cmd, ec)
59
-			exitHandler()
60
-		}()
61
-		log.G(ctx).WithFields(logrus.Fields{
62
-			"pid":     cmd.Process.Pid,
63
-			"address": address,
64
-			"debug":   debug,
65
-		}).Infof("shim %s started", binary)
66
-		// set shim in cgroup if it is provided
67
-		if cgroup != "" {
68
-			if err := setCgroup(cgroup, cmd); err != nil {
69
-				return nil, nil, err
70
-			}
71
-			log.G(ctx).WithFields(logrus.Fields{
72
-				"pid":     cmd.Process.Pid,
73
-				"address": address,
74
-			}).Infof("shim placed in cgroup %s", cgroup)
75
-		}
76
-		if err = sys.SetOOMScore(cmd.Process.Pid, sys.OOMScoreMaxKillable); err != nil {
77
-			return nil, nil, errors.Wrap(err, "failed to set OOM Score on shim")
78
-		}
79
-		c, clo, err := WithConnect(address)(ctx, config)
80
-		if err != nil {
81
-			return nil, nil, errors.Wrap(err, "failed to connect")
82
-		}
83
-		return c, clo, nil
84
-	}
85
-}
86
-
87
-func newCommand(binary, daemonAddress string, nonewns, debug bool, config Config, socket *os.File) *exec.Cmd {
88
-	args := []string{
89
-		"--namespace", config.Namespace,
90
-		"--workdir", config.WorkDir,
91
-		"--address", daemonAddress,
92
-	}
93
-
94
-	if config.Criu != "" {
95
-		args = append(args, "--criu-path", config.Criu)
96
-	}
97
-	if config.RuntimeRoot != "" {
98
-		args = append(args, "--runtime-root", config.RuntimeRoot)
99
-	}
100
-	if config.SystemdCgroup {
101
-		args = append(args, "--systemd-cgroup")
102
-	}
103
-	if debug {
104
-		args = append(args, "--debug")
105
-	}
106
-
107
-	cmd := exec.Command(binary, args...)
108
-	cmd.Dir = config.Path
109
-	// make sure the shim can be re-parented to system init
110
-	// and is cloned in a new mount namespace because the overlay/filesystems
111
-	// will be mounted by the shim
112
-	cmd.SysProcAttr = getSysProcAttr(nonewns)
113
-	cmd.ExtraFiles = append(cmd.ExtraFiles, socket)
114
-	if debug {
115
-		cmd.Stdout = os.Stdout
116
-		cmd.Stderr = os.Stderr
117
-	}
118
-	return cmd
119
-}
120
-
121
-func newSocket(address string) (*net.UnixListener, error) {
122
-	if len(address) > 106 {
123
-		return nil, errors.Errorf("%q: unix socket path too long (limit 106)", address)
124
-	}
125
-	l, err := net.Listen("unix", "\x00"+address)
126
-	if err != nil {
127
-		return nil, errors.Wrapf(err, "failed to listen to abstract unix socket %q", address)
128
-	}
129
-
130
-	return l.(*net.UnixListener), nil
131
-}
132
-
133
-func connect(address string, d func(string, time.Duration) (net.Conn, error)) (*grpc.ClientConn, error) {
134
-	gopts := []grpc.DialOption{
135
-		grpc.WithBlock(),
136
-		grpc.WithInsecure(),
137
-		grpc.WithTimeout(100 * time.Second),
138
-		grpc.WithDialer(d),
139
-		grpc.FailOnNonTempDialError(true),
140
-	}
141
-	conn, err := grpc.Dial(dialAddress(address), gopts...)
142
-	if err != nil {
143
-		return nil, errors.Wrapf(err, "failed to dial %q", address)
144
-	}
145
-	return conn, nil
146
-}
147
-
148
-func dialer(address string, timeout time.Duration) (net.Conn, error) {
149
-	address = strings.TrimPrefix(address, "unix://")
150
-	return net.DialTimeout("unix", address, timeout)
151
-}
152
-
153
-func annonDialer(address string, timeout time.Duration) (net.Conn, error) {
154
-	address = strings.TrimPrefix(address, "unix://")
155
-	return net.DialTimeout("unix", "\x00"+address, timeout)
156
-}
157
-
158
-func dialAddress(address string) string {
159
-	return fmt.Sprintf("unix://%s", address)
160
-}
161
-
162
-// WithConnect connects to an existing shim
163
-func WithConnect(address string) ClientOpt {
164
-	return func(ctx context.Context, config Config) (shim.ShimClient, io.Closer, error) {
165
-		conn, err := connect(address, annonDialer)
166
-		if err != nil {
167
-			return nil, nil, err
168
-		}
169
-		return shim.NewShimClient(conn), conn, nil
170
-	}
171
-}
172
-
173
-// WithLocal uses an in process shim
174
-func WithLocal(publisher events.Publisher) func(context.Context, Config) (shim.ShimClient, io.Closer, error) {
175
-	return func(ctx context.Context, config Config) (shim.ShimClient, io.Closer, error) {
176
-		service, err := NewService(config, publisher)
177
-		if err != nil {
178
-			return nil, nil, err
179
-		}
180
-		return NewLocal(service), nil, nil
181
-	}
182
-}
183
-
184
-// Config contains shim specific configuration
185
-type Config struct {
186
-	Path          string
187
-	Namespace     string
188
-	WorkDir       string
189
-	Criu          string
190
-	RuntimeRoot   string
191
-	SystemdCgroup bool
192
-}
193
-
194
-// New returns a new shim client
195
-func New(ctx context.Context, config Config, opt ClientOpt) (*Client, error) {
196
-	s, c, err := opt(ctx, config)
197
-	if err != nil {
198
-		return nil, err
199
-	}
200
-	return &Client{
201
-		ShimClient: s,
202
-		c:          c,
203
-		exitCh:     make(chan struct{}),
204
-	}, nil
205
-}
206
-
207
-// Client is a shim client containing the connection to a shim
208
-type Client struct {
209
-	shim.ShimClient
210
-
211
-	c        io.Closer
212
-	exitCh   chan struct{}
213
-	exitOnce sync.Once
214
-}
215
-
216
-// IsAlive returns true if the shim can be contacted.
217
-// NOTE: a negative answer doesn't mean that the process is gone.
218
-func (c *Client) IsAlive(ctx context.Context) (bool, error) {
219
-	_, err := c.ShimInfo(ctx, empty)
220
-	if err != nil {
221
-		if err != grpc.ErrServerStopped {
222
-			return false, err
223
-		}
224
-		return false, nil
225
-	}
226
-	return true, nil
227
-}
228
-
229
-// StopShim signals the shim to exit and wait for the process to disappear
230
-func (c *Client) StopShim(ctx context.Context) error {
231
-	return c.signalShim(ctx, unix.SIGTERM)
232
-}
233
-
234
-// KillShim kills the shim forcefully and wait for the process to disappear
235
-func (c *Client) KillShim(ctx context.Context) error {
236
-	return c.signalShim(ctx, unix.SIGKILL)
237
-}
238
-
239
-// Close the cient connection
240
-func (c *Client) Close() error {
241
-	if c.c == nil {
242
-		return nil
243
-	}
244
-	return c.c.Close()
245
-}
246
-
247
-func (c *Client) signalShim(ctx context.Context, sig syscall.Signal) error {
248
-	info, err := c.ShimInfo(ctx, empty)
249
-	if err != nil {
250
-		return err
251
-	}
252
-	pid := int(info.ShimPid)
253
-	// make sure we don't kill ourselves if we are running a local shim
254
-	if os.Getpid() == pid {
255
-		return nil
256
-	}
257
-	if err := unix.Kill(pid, sig); err != nil && err != unix.ESRCH {
258
-		return err
259
-	}
260
-	// wait for shim to die after being signaled
261
-	select {
262
-	case <-ctx.Done():
263
-		return ctx.Err()
264
-	case <-c.waitForExit(pid):
265
-		return nil
266
-	}
267
-}
268
-
269
-func (c *Client) waitForExit(pid int) <-chan struct{} {
270
-	c.exitOnce.Do(func() {
271
-		for {
272
-			// use kill(pid, 0) here because the shim could have been reparented
273
-			// and we are no longer able to waitpid(pid, ...) on the shim
274
-			if err := unix.Kill(pid, 0); err == unix.ESRCH {
275
-				close(c.exitCh)
276
-				return
277
-			}
278
-			time.Sleep(10 * time.Millisecond)
279
-		}
280
-	})
281
-	return c.exitCh
282
-}
283 1
new file mode 100644
... ...
@@ -0,0 +1,276 @@
0
+// +build !windows
1
+
2
+package client
3
+
4
+import (
5
+	"context"
6
+	"fmt"
7
+	"io"
8
+	"net"
9
+	"os"
10
+	"os/exec"
11
+	"strings"
12
+	"sync"
13
+	"syscall"
14
+	"time"
15
+
16
+	"golang.org/x/sys/unix"
17
+
18
+	"github.com/pkg/errors"
19
+	"github.com/sirupsen/logrus"
20
+
21
+	"github.com/containerd/containerd/events"
22
+	"github.com/containerd/containerd/linux/shim"
23
+	shimapi "github.com/containerd/containerd/linux/shim/v1"
24
+	"github.com/containerd/containerd/log"
25
+	"github.com/containerd/containerd/reaper"
26
+	"github.com/containerd/containerd/sys"
27
+	google_protobuf "github.com/golang/protobuf/ptypes/empty"
28
+	"google.golang.org/grpc"
29
+)
30
+
31
+var empty = &google_protobuf.Empty{}
32
+
33
+// Opt is an option for a shim client configuration
34
+type Opt func(context.Context, shim.Config) (shimapi.ShimClient, io.Closer, error)
35
+
36
+// WithStart executes a new shim process
37
+func WithStart(binary, address, daemonAddress, cgroup string, nonewns, debug bool, exitHandler func()) Opt {
38
+	return func(ctx context.Context, config shim.Config) (_ shimapi.ShimClient, _ io.Closer, err error) {
39
+		socket, err := newSocket(address)
40
+		if err != nil {
41
+			return nil, nil, err
42
+		}
43
+		defer socket.Close()
44
+		f, err := socket.File()
45
+		if err != nil {
46
+			return nil, nil, errors.Wrapf(err, "failed to get fd for socket %s", address)
47
+		}
48
+		defer f.Close()
49
+
50
+		cmd := newCommand(binary, daemonAddress, nonewns, debug, config, f)
51
+		ec, err := reaper.Default.Start(cmd)
52
+		if err != nil {
53
+			return nil, nil, errors.Wrapf(err, "failed to start shim")
54
+		}
55
+		defer func() {
56
+			if err != nil {
57
+				cmd.Process.Kill()
58
+			}
59
+		}()
60
+		go func() {
61
+			reaper.Default.Wait(cmd, ec)
62
+			exitHandler()
63
+		}()
64
+		log.G(ctx).WithFields(logrus.Fields{
65
+			"pid":     cmd.Process.Pid,
66
+			"address": address,
67
+			"debug":   debug,
68
+		}).Infof("shim %s started", binary)
69
+		// set shim in cgroup if it is provided
70
+		if cgroup != "" {
71
+			if err := setCgroup(cgroup, cmd); err != nil {
72
+				return nil, nil, err
73
+			}
74
+			log.G(ctx).WithFields(logrus.Fields{
75
+				"pid":     cmd.Process.Pid,
76
+				"address": address,
77
+			}).Infof("shim placed in cgroup %s", cgroup)
78
+		}
79
+		if err = sys.SetOOMScore(cmd.Process.Pid, sys.OOMScoreMaxKillable); err != nil {
80
+			return nil, nil, errors.Wrap(err, "failed to set OOM Score on shim")
81
+		}
82
+		c, clo, err := WithConnect(address)(ctx, config)
83
+		if err != nil {
84
+			return nil, nil, errors.Wrap(err, "failed to connect")
85
+		}
86
+		return c, clo, nil
87
+	}
88
+}
89
+
90
+func newCommand(binary, daemonAddress string, nonewns, debug bool, config shim.Config, socket *os.File) *exec.Cmd {
91
+	args := []string{
92
+		"-namespace", config.Namespace,
93
+		"-workdir", config.WorkDir,
94
+		"-address", daemonAddress,
95
+	}
96
+
97
+	if config.Criu != "" {
98
+		args = append(args, "-criu-path", config.Criu)
99
+	}
100
+	if config.RuntimeRoot != "" {
101
+		args = append(args, "-runtime-root", config.RuntimeRoot)
102
+	}
103
+	if config.SystemdCgroup {
104
+		args = append(args, "-systemd-cgroup")
105
+	}
106
+	if debug {
107
+		args = append(args, "-debug")
108
+	}
109
+
110
+	cmd := exec.Command(binary, args...)
111
+	cmd.Dir = config.Path
112
+	// make sure the shim can be re-parented to system init
113
+	// and is cloned in a new mount namespace because the overlay/filesystems
114
+	// will be mounted by the shim
115
+	cmd.SysProcAttr = getSysProcAttr(nonewns)
116
+	cmd.ExtraFiles = append(cmd.ExtraFiles, socket)
117
+	if debug {
118
+		cmd.Stdout = os.Stdout
119
+		cmd.Stderr = os.Stderr
120
+	}
121
+	return cmd
122
+}
123
+
124
+func newSocket(address string) (*net.UnixListener, error) {
125
+	if len(address) > 106 {
126
+		return nil, errors.Errorf("%q: unix socket path too long (limit 106)", address)
127
+	}
128
+	l, err := net.Listen("unix", "\x00"+address)
129
+	if err != nil {
130
+		return nil, errors.Wrapf(err, "failed to listen to abstract unix socket %q", address)
131
+	}
132
+
133
+	return l.(*net.UnixListener), nil
134
+}
135
+
136
+func connect(address string, d func(string, time.Duration) (net.Conn, error)) (*grpc.ClientConn, error) {
137
+	gopts := []grpc.DialOption{
138
+		grpc.WithBlock(),
139
+		grpc.WithInsecure(),
140
+		grpc.WithTimeout(100 * time.Second),
141
+		grpc.WithDialer(d),
142
+		grpc.FailOnNonTempDialError(true),
143
+	}
144
+	conn, err := grpc.Dial(dialAddress(address), gopts...)
145
+	if err != nil {
146
+		return nil, errors.Wrapf(err, "failed to dial %q", address)
147
+	}
148
+	return conn, nil
149
+}
150
+
151
+func dialer(address string, timeout time.Duration) (net.Conn, error) {
152
+	address = strings.TrimPrefix(address, "unix://")
153
+	return net.DialTimeout("unix", address, timeout)
154
+}
155
+
156
+func annonDialer(address string, timeout time.Duration) (net.Conn, error) {
157
+	address = strings.TrimPrefix(address, "unix://")
158
+	return net.DialTimeout("unix", "\x00"+address, timeout)
159
+}
160
+
161
+func dialAddress(address string) string {
162
+	return fmt.Sprintf("unix://%s", address)
163
+}
164
+
165
+// WithConnect connects to an existing shim
166
+func WithConnect(address string) Opt {
167
+	return func(ctx context.Context, config shim.Config) (shimapi.ShimClient, io.Closer, error) {
168
+		conn, err := connect(address, annonDialer)
169
+		if err != nil {
170
+			return nil, nil, err
171
+		}
172
+		return shimapi.NewShimClient(conn), conn, nil
173
+	}
174
+}
175
+
176
+// WithLocal uses an in process shim
177
+func WithLocal(publisher events.Publisher) func(context.Context, shim.Config) (shimapi.ShimClient, io.Closer, error) {
178
+	return func(ctx context.Context, config shim.Config) (shimapi.ShimClient, io.Closer, error) {
179
+		service, err := shim.NewService(config, publisher)
180
+		if err != nil {
181
+			return nil, nil, err
182
+		}
183
+		return shim.NewLocal(service), nil, nil
184
+	}
185
+}
186
+
187
+// New returns a new shim client
188
+func New(ctx context.Context, config shim.Config, opt Opt) (*Client, error) {
189
+	s, c, err := opt(ctx, config)
190
+	if err != nil {
191
+		return nil, err
192
+	}
193
+	return &Client{
194
+		ShimClient: s,
195
+		c:          c,
196
+		exitCh:     make(chan struct{}),
197
+	}, nil
198
+}
199
+
200
+// Client is a shim client containing the connection to a shim
201
+type Client struct {
202
+	shimapi.ShimClient
203
+
204
+	c        io.Closer
205
+	exitCh   chan struct{}
206
+	exitOnce sync.Once
207
+}
208
+
209
+// IsAlive returns true if the shim can be contacted.
210
+// NOTE: a negative answer doesn't mean that the process is gone.
211
+func (c *Client) IsAlive(ctx context.Context) (bool, error) {
212
+	_, err := c.ShimInfo(ctx, empty)
213
+	if err != nil {
214
+		if err != grpc.ErrServerStopped {
215
+			return false, err
216
+		}
217
+		return false, nil
218
+	}
219
+	return true, nil
220
+}
221
+
222
+// StopShim signals the shim to exit and wait for the process to disappear
223
+func (c *Client) StopShim(ctx context.Context) error {
224
+	return c.signalShim(ctx, unix.SIGTERM)
225
+}
226
+
227
+// KillShim kills the shim forcefully and wait for the process to disappear
228
+func (c *Client) KillShim(ctx context.Context) error {
229
+	return c.signalShim(ctx, unix.SIGKILL)
230
+}
231
+
232
+// Close the cient connection
233
+func (c *Client) Close() error {
234
+	if c.c == nil {
235
+		return nil
236
+	}
237
+	return c.c.Close()
238
+}
239
+
240
+func (c *Client) signalShim(ctx context.Context, sig syscall.Signal) error {
241
+	info, err := c.ShimInfo(ctx, empty)
242
+	if err != nil {
243
+		return err
244
+	}
245
+	pid := int(info.ShimPid)
246
+	// make sure we don't kill ourselves if we are running a local shim
247
+	if os.Getpid() == pid {
248
+		return nil
249
+	}
250
+	if err := unix.Kill(pid, sig); err != nil && err != unix.ESRCH {
251
+		return err
252
+	}
253
+	// wait for shim to die after being signaled
254
+	select {
255
+	case <-ctx.Done():
256
+		return ctx.Err()
257
+	case <-c.waitForExit(pid):
258
+		return nil
259
+	}
260
+}
261
+
262
+func (c *Client) waitForExit(pid int) <-chan struct{} {
263
+	c.exitOnce.Do(func() {
264
+		for {
265
+			// use kill(pid, 0) here because the shim could have been reparented
266
+			// and we are no longer able to waitpid(pid, ...) on the shim
267
+			if err := unix.Kill(pid, 0); err == unix.ESRCH {
268
+				close(c.exitCh)
269
+				return
270
+			}
271
+			time.Sleep(10 * time.Millisecond)
272
+		}
273
+	})
274
+	return c.exitCh
275
+}
0 276
new file mode 100644
... ...
@@ -0,0 +1,34 @@
0
+// +build linux
1
+
2
+package client
3
+
4
+import (
5
+	"os/exec"
6
+	"syscall"
7
+
8
+	"github.com/containerd/cgroups"
9
+	"github.com/pkg/errors"
10
+)
11
+
12
+func getSysProcAttr(nonewns bool) *syscall.SysProcAttr {
13
+	attr := syscall.SysProcAttr{
14
+		Setpgid: true,
15
+	}
16
+	if !nonewns {
17
+		attr.Cloneflags = syscall.CLONE_NEWNS
18
+	}
19
+	return &attr
20
+}
21
+
22
+func setCgroup(cgroupPath string, cmd *exec.Cmd) error {
23
+	cg, err := cgroups.Load(cgroups.V1, cgroups.StaticPath(cgroupPath))
24
+	if err != nil {
25
+		return errors.Wrapf(err, "failed to load cgroup %s", cgroupPath)
26
+	}
27
+	if err := cg.Add(cgroups.Process{
28
+		Pid: cmd.Process.Pid,
29
+	}); err != nil {
30
+		return errors.Wrapf(err, "failed to join cgroup %s", cgroupPath)
31
+	}
32
+	return nil
33
+}
0 34
new file mode 100644
... ...
@@ -0,0 +1,18 @@
0
+// +build !linux,!windows
1
+
2
+package client
3
+
4
+import (
5
+	"os/exec"
6
+	"syscall"
7
+)
8
+
9
+func getSysProcAttr(nonewns bool) *syscall.SysProcAttr {
10
+	return &syscall.SysProcAttr{
11
+		Setpgid: true,
12
+	}
13
+}
14
+
15
+func setCgroup(cgroupPath string, cmd *exec.Cmd) error {
16
+	return nil
17
+}
0 18
deleted file mode 100644
... ...
@@ -1,34 +0,0 @@
1
-// +build linux
2
-
3
-package shim
4
-
5
-import (
6
-	"os/exec"
7
-	"syscall"
8
-
9
-	"github.com/containerd/cgroups"
10
-	"github.com/pkg/errors"
11
-)
12
-
13
-func getSysProcAttr(nonewns bool) *syscall.SysProcAttr {
14
-	attr := syscall.SysProcAttr{
15
-		Setpgid: true,
16
-	}
17
-	if !nonewns {
18
-		attr.Cloneflags = syscall.CLONE_NEWNS
19
-	}
20
-	return &attr
21
-}
22
-
23
-func setCgroup(cgroupPath string, cmd *exec.Cmd) error {
24
-	cg, err := cgroups.Load(cgroups.V1, cgroups.StaticPath(cgroupPath))
25
-	if err != nil {
26
-		return errors.Wrapf(err, "failed to load cgroup %s", cgroupPath)
27
-	}
28
-	if err := cg.Add(cgroups.Process{
29
-		Pid: cmd.Process.Pid,
30
-	}); err != nil {
31
-		return errors.Wrapf(err, "failed to join cgroup %s", cgroupPath)
32
-	}
33
-	return nil
34
-}
35 1
deleted file mode 100644
... ...
@@ -1,18 +0,0 @@
1
-// +build !linux,!windows
2
-
3
-package shim
4
-
5
-import (
6
-	"os/exec"
7
-	"syscall"
8
-)
9
-
10
-func getSysProcAttr(nonewns bool) *syscall.SysProcAttr {
11
-	return &syscall.SysProcAttr{
12
-		Setpgid: true,
13
-	}
14
-}
15
-
16
-func setCgroup(cgroupPath string, cmd *exec.Cmd) error {
17
-	return nil
18
-}
... ...
@@ -98,12 +98,16 @@ func (s *Service) newInitProcess(context context.Context, r *shimapi.CreateTaskR
98 98
 			return nil, errors.Wrapf(err, "failed to mount rootfs component %v", m)
99 99
 		}
100 100
 	}
101
+	root := s.config.RuntimeRoot
102
+	if root == "" {
103
+		root = RuncRoot
104
+	}
101 105
 	runtime := &runc.Runc{
102 106
 		Command:       r.Runtime,
103 107
 		Log:           filepath.Join(s.config.Path, "log.json"),
104 108
 		LogFormat:     runc.JSON,
105 109
 		PdeathSignal:  syscall.SIGKILL,
106
-		Root:          filepath.Join(s.config.RuntimeRoot, s.config.Namespace),
110
+		Root:          filepath.Join(root, s.config.Namespace),
107 111
 		Criu:          s.config.Criu,
108 112
 		SystemdCgroup: s.config.SystemdCgroup,
109 113
 	}
... ...
@@ -32,6 +32,16 @@ var empty = &google_protobuf.Empty{}
32 32
 // RuncRoot is the path to the root runc state directory
33 33
 const RuncRoot = "/run/containerd/runc"
34 34
 
35
+// Config contains shim specific configuration
36
+type Config struct {
37
+	Path          string
38
+	Namespace     string
39
+	WorkDir       string
40
+	Criu          string
41
+	RuntimeRoot   string
42
+	SystemdCgroup bool
43
+}
44
+
35 45
 // NewService returns a new shim service that can be used via GRPC
36 46
 func NewService(config Config, publisher events.Publisher) (*Service, error) {
37 47
 	if config.Namespace == "" {
... ...
@@ -11,7 +11,7 @@ import (
11 11
 	"github.com/containerd/cgroups"
12 12
 	"github.com/containerd/containerd/api/types/task"
13 13
 	"github.com/containerd/containerd/errdefs"
14
-	client "github.com/containerd/containerd/linux/shim"
14
+	"github.com/containerd/containerd/linux/shim/client"
15 15
 	shim "github.com/containerd/containerd/linux/shim/v1"
16 16
 	"github.com/containerd/containerd/runtime"
17 17
 	"github.com/gogo/protobuf/types"
... ...
@@ -38,6 +38,7 @@ var (
38 38
 	bucketKeyObjectContent    = []byte("content")    // stores content references
39 39
 	bucketKeyObjectBlob       = []byte("blob")       // stores content links
40 40
 	bucketKeyObjectIngest     = []byte("ingest")     // stores ingest links
41
+	bucketKeyObjectLeases     = []byte("leases")     // stores leases
41 42
 
42 43
 	bucketKeyDigest      = []byte("digest")
43 44
 	bucketKeyMediaType   = []byte("mediatype")
... ...
@@ -53,6 +54,7 @@ var (
53 53
 	bucketKeySnapshotter = []byte("snapshotter")
54 54
 	bucketKeyTarget      = []byte("target")
55 55
 	bucketKeyExtensions  = []byte("extensions")
56
+	bucketKeyCreatedAt   = []byte("createdat")
56 57
 )
57 58
 
58 59
 func getBucket(tx *bolt.Tx, keys ...[]byte) *bolt.Bucket {
... ...
@@ -391,27 +391,31 @@ func (nw *namespacedWriter) Commit(ctx context.Context, size int64, expected dig
391 391
 				return err
392 392
 			}
393 393
 		}
394
-		return nw.commit(ctx, tx, size, expected, opts...)
394
+		dgst, err := nw.commit(ctx, tx, size, expected, opts...)
395
+		if err != nil {
396
+			return err
397
+		}
398
+		return addContentLease(ctx, tx, dgst)
395 399
 	})
396 400
 }
397 401
 
398
-func (nw *namespacedWriter) commit(ctx context.Context, tx *bolt.Tx, size int64, expected digest.Digest, opts ...content.Opt) error {
402
+func (nw *namespacedWriter) commit(ctx context.Context, tx *bolt.Tx, size int64, expected digest.Digest, opts ...content.Opt) (digest.Digest, error) {
399 403
 	var base content.Info
400 404
 	for _, opt := range opts {
401 405
 		if err := opt(&base); err != nil {
402
-			return err
406
+			return "", err
403 407
 		}
404 408
 	}
405 409
 	if err := validateInfo(&base); err != nil {
406
-		return err
410
+		return "", err
407 411
 	}
408 412
 
409 413
 	status, err := nw.Writer.Status()
410 414
 	if err != nil {
411
-		return err
415
+		return "", err
412 416
 	}
413 417
 	if size != 0 && size != status.Offset {
414
-		return errors.Errorf("%q failed size validation: %v != %v", nw.ref, status.Offset, size)
418
+		return "", errors.Errorf("%q failed size validation: %v != %v", nw.ref, status.Offset, size)
415 419
 	}
416 420
 	size = status.Offset
417 421
 
... ...
@@ -419,32 +423,32 @@ func (nw *namespacedWriter) commit(ctx context.Context, tx *bolt.Tx, size int64,
419 419
 
420 420
 	if err := nw.Writer.Commit(ctx, size, expected); err != nil {
421 421
 		if !errdefs.IsAlreadyExists(err) {
422
-			return err
422
+			return "", err
423 423
 		}
424 424
 		if getBlobBucket(tx, nw.namespace, actual) != nil {
425
-			return errors.Wrapf(errdefs.ErrAlreadyExists, "content %v", actual)
425
+			return "", errors.Wrapf(errdefs.ErrAlreadyExists, "content %v", actual)
426 426
 		}
427 427
 	}
428 428
 
429 429
 	bkt, err := createBlobBucket(tx, nw.namespace, actual)
430 430
 	if err != nil {
431
-		return err
431
+		return "", err
432 432
 	}
433 433
 
434 434
 	commitTime := time.Now().UTC()
435 435
 
436 436
 	sizeEncoded, err := encodeInt(size)
437 437
 	if err != nil {
438
-		return err
438
+		return "", err
439 439
 	}
440 440
 
441 441
 	if err := boltutil.WriteTimestamps(bkt, commitTime, commitTime); err != nil {
442
-		return err
442
+		return "", err
443 443
 	}
444 444
 	if err := boltutil.WriteLabels(bkt, base.Labels); err != nil {
445
-		return err
445
+		return "", err
446 446
 	}
447
-	return bkt.Put(bucketKeySize, sizeEncoded)
447
+	return actual, bkt.Put(bucketKeySize, sizeEncoded)
448 448
 }
449 449
 
450 450
 func (nw *namespacedWriter) Status() (content.Status, error) {
... ...
@@ -566,7 +570,7 @@ func (cs *contentStore) garbageCollect(ctx context.Context) error {
566 566
 		return err
567 567
 	}
568 568
 
569
-	if err := cs.Store.Walk(ctx, func(info content.Info) error {
569
+	return cs.Store.Walk(ctx, func(info content.Info) error {
570 570
 		if _, ok := seen[info.Digest.String()]; !ok {
571 571
 			if err := cs.Store.Delete(ctx, info.Digest); err != nil {
572 572
 				return err
... ...
@@ -574,9 +578,5 @@ func (cs *contentStore) garbageCollect(ctx context.Context) error {
574 574
 			log.G(ctx).WithField("digest", info.Digest).Debug("removed content")
575 575
 		}
576 576
 		return nil
577
-	}); err != nil {
578
-		return err
579
-	}
580
-
581
-	return nil
577
+	})
582 578
 }
... ...
@@ -190,6 +190,7 @@ func (m *DB) Update(fn func(*bolt.Tx) error) error {
190 190
 	return m.db.Update(fn)
191 191
 }
192 192
 
193
+// GarbageCollect starts garbage collection
193 194
 func (m *DB) GarbageCollect(ctx context.Context) error {
194 195
 	lt1 := time.Now()
195 196
 	m.wlock.Lock()
... ...
@@ -198,39 +199,8 @@ func (m *DB) GarbageCollect(ctx context.Context) error {
198 198
 		log.G(ctx).WithField("d", time.Now().Sub(lt1)).Debug("metadata garbage collected")
199 199
 	}()
200 200
 
201
-	var marked map[gc.Node]struct{}
202
-
203
-	if err := m.db.View(func(tx *bolt.Tx) error {
204
-		ctx, cancel := context.WithCancel(ctx)
205
-		defer cancel()
206
-
207
-		roots := make(chan gc.Node)
208
-		errChan := make(chan error)
209
-		go func() {
210
-			defer close(errChan)
211
-			defer close(roots)
212
-
213
-			// Call roots
214
-			if err := scanRoots(ctx, tx, roots); err != nil {
215
-				cancel()
216
-				errChan <- err
217
-			}
218
-		}()
219
-
220
-		refs := func(ctx context.Context, n gc.Node, fn func(gc.Node)) error {
221
-			return references(ctx, tx, n, fn)
222
-		}
223
-
224
-		reachable, err := gc.ConcurrentMark(ctx, roots, refs)
225
-		if rerr := <-errChan; rerr != nil {
226
-			return rerr
227
-		}
228
-		if err != nil {
229
-			return err
230
-		}
231
-		marked = reachable
232
-		return nil
233
-	}); err != nil {
201
+	marked, err := m.getMarked(ctx)
202
+	if err != nil {
234 203
 		return err
235 204
 	}
236 205
 
... ...
@@ -241,15 +211,11 @@ func (m *DB) GarbageCollect(ctx context.Context) error {
241 241
 		ctx, cancel := context.WithCancel(ctx)
242 242
 		defer cancel()
243 243
 
244
-		nodeC := make(chan gc.Node)
245
-		var scanErr error
246
-
247
-		go func() {
248
-			defer close(nodeC)
249
-			scanErr = scanAll(ctx, tx, nodeC)
250
-		}()
244
+		rm := func(ctx context.Context, n gc.Node) error {
245
+			if _, ok := marked[n]; ok {
246
+				return nil
247
+			}
251 248
 
252
-		rm := func(n gc.Node) error {
253 249
 			if n.Type == ResourceSnapshot {
254 250
 				if idx := strings.IndexRune(n.Key, '/'); idx > 0 {
255 251
 					m.dirtySS[n.Key[:idx]] = struct{}{}
... ...
@@ -260,12 +226,8 @@ func (m *DB) GarbageCollect(ctx context.Context) error {
260 260
 			return remove(ctx, tx, n)
261 261
 		}
262 262
 
263
-		if err := gc.Sweep(marked, nodeC, rm); err != nil {
264
-			return errors.Wrap(err, "failed to sweep")
265
-		}
266
-
267
-		if scanErr != nil {
268
-			return errors.Wrap(scanErr, "failed to scan all")
263
+		if err := scanAll(ctx, tx, rm); err != nil {
264
+			return errors.Wrap(err, "failed to scan and remove")
269 265
 		}
270 266
 
271 267
 		return nil
... ...
@@ -292,6 +254,54 @@ func (m *DB) GarbageCollect(ctx context.Context) error {
292 292
 	return nil
293 293
 }
294 294
 
295
+func (m *DB) getMarked(ctx context.Context) (map[gc.Node]struct{}, error) {
296
+	var marked map[gc.Node]struct{}
297
+	if err := m.db.View(func(tx *bolt.Tx) error {
298
+		ctx, cancel := context.WithCancel(ctx)
299
+		defer cancel()
300
+
301
+		var (
302
+			nodes []gc.Node
303
+			wg    sync.WaitGroup
304
+			roots = make(chan gc.Node)
305
+		)
306
+		wg.Add(1)
307
+		go func() {
308
+			defer wg.Done()
309
+			for n := range roots {
310
+				nodes = append(nodes, n)
311
+			}
312
+		}()
313
+		// Call roots
314
+		if err := scanRoots(ctx, tx, roots); err != nil {
315
+			cancel()
316
+			return err
317
+		}
318
+		close(roots)
319
+		wg.Wait()
320
+
321
+		refs := func(n gc.Node) ([]gc.Node, error) {
322
+			var sn []gc.Node
323
+			if err := references(ctx, tx, n, func(nn gc.Node) {
324
+				sn = append(sn, nn)
325
+			}); err != nil {
326
+				return nil, err
327
+			}
328
+			return sn, nil
329
+		}
330
+
331
+		reachable, err := gc.Tricolor(nodes, refs)
332
+		if err != nil {
333
+			return err
334
+		}
335
+		marked = reachable
336
+		return nil
337
+	}); err != nil {
338
+		return nil, err
339
+	}
340
+	return marked, nil
341
+}
342
+
295 343
 func (m *DB) cleanupSnapshotter(name string) {
296 344
 	ctx := context.Background()
297 345
 	sn, ok := m.ss[name]
... ...
@@ -12,10 +12,15 @@ import (
12 12
 )
13 13
 
14 14
 const (
15
+	// ResourceUnknown specifies an unknown resource
15 16
 	ResourceUnknown gc.ResourceType = iota
17
+	// ResourceContent specifies a content resource
16 18
 	ResourceContent
19
+	// ResourceSnapshot specifies a snapshot resource
17 20
 	ResourceSnapshot
21
+	// ResourceContainer specifies a container resource
18 22
 	ResourceContainer
23
+	// ResourceTask specifies a task resource
19 24
 	ResourceTask
20 25
 )
21 26
 
... ...
@@ -41,6 +46,55 @@ func scanRoots(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
41 41
 		nbkt := v1bkt.Bucket(k)
42 42
 		ns := string(k)
43 43
 
44
+		lbkt := nbkt.Bucket(bucketKeyObjectLeases)
45
+		if lbkt != nil {
46
+			if err := lbkt.ForEach(func(k, v []byte) error {
47
+				if v != nil {
48
+					return nil
49
+				}
50
+				libkt := lbkt.Bucket(k)
51
+
52
+				cbkt := libkt.Bucket(bucketKeyObjectContent)
53
+				if cbkt != nil {
54
+					if err := cbkt.ForEach(func(k, v []byte) error {
55
+						select {
56
+						case nc <- gcnode(ResourceContent, ns, string(k)):
57
+						case <-ctx.Done():
58
+							return ctx.Err()
59
+						}
60
+						return nil
61
+					}); err != nil {
62
+						return err
63
+					}
64
+				}
65
+
66
+				sbkt := libkt.Bucket(bucketKeyObjectSnapshots)
67
+				if sbkt != nil {
68
+					if err := sbkt.ForEach(func(sk, sv []byte) error {
69
+						if sv != nil {
70
+							return nil
71
+						}
72
+						snbkt := sbkt.Bucket(sk)
73
+
74
+						return snbkt.ForEach(func(k, v []byte) error {
75
+							select {
76
+							case nc <- gcnode(ResourceSnapshot, ns, fmt.Sprintf("%s/%s", sk, k)):
77
+							case <-ctx.Done():
78
+								return ctx.Err()
79
+							}
80
+							return nil
81
+						})
82
+					}); err != nil {
83
+						return err
84
+					}
85
+				}
86
+
87
+				return nil
88
+			}); err != nil {
89
+				return err
90
+			}
91
+		}
92
+
44 93
 		ibkt := nbkt.Bucket(bucketKeyObjectImages)
45 94
 		if ibkt != nil {
46 95
 			if err := ibkt.ForEach(func(k, v []byte) error {
... ...
@@ -174,7 +228,7 @@ func references(ctx context.Context, tx *bolt.Tx, node gc.Node, fn func(gc.Node)
174 174
 	return nil
175 175
 }
176 176
 
177
-func scanAll(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
177
+func scanAll(ctx context.Context, tx *bolt.Tx, fn func(ctx context.Context, n gc.Node) error) error {
178 178
 	v1bkt := tx.Bucket(bucketKeyVersion)
179 179
 	if v1bkt == nil {
180 180
 		return nil
... ...
@@ -201,12 +255,8 @@ func scanAll(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
201 201
 					if v != nil {
202 202
 						return nil
203 203
 					}
204
-					select {
205
-					case nc <- gcnode(ResourceSnapshot, ns, fmt.Sprintf("%s/%s", sk, k)):
206
-					case <-ctx.Done():
207
-						return ctx.Err()
208
-					}
209
-					return nil
204
+					node := gcnode(ResourceSnapshot, ns, fmt.Sprintf("%s/%s", sk, k))
205
+					return fn(ctx, node)
210 206
 				})
211 207
 			}); err != nil {
212 208
 				return err
... ...
@@ -222,12 +272,8 @@ func scanAll(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
222 222
 				if v != nil {
223 223
 					return nil
224 224
 				}
225
-				select {
226
-				case nc <- gcnode(ResourceContent, ns, string(k)):
227
-				case <-ctx.Done():
228
-					return ctx.Err()
229
-				}
230
-				return nil
225
+				node := gcnode(ResourceContent, ns, string(k))
226
+				return fn(ctx, node)
231 227
 			}); err != nil {
232 228
 				return err
233 229
 			}
234 230
new file mode 100644
... ...
@@ -0,0 +1,201 @@
0
+package metadata
1
+
2
+import (
3
+	"context"
4
+	"time"
5
+
6
+	"github.com/boltdb/bolt"
7
+	"github.com/containerd/containerd/errdefs"
8
+	"github.com/containerd/containerd/leases"
9
+	"github.com/containerd/containerd/metadata/boltutil"
10
+	"github.com/containerd/containerd/namespaces"
11
+	digest "github.com/opencontainers/go-digest"
12
+	"github.com/pkg/errors"
13
+)
14
+
15
+// Lease retains resources to prevent garbage collection before
16
+// the resources can be fully referenced.
17
+type Lease struct {
18
+	ID        string
19
+	CreatedAt time.Time
20
+	Labels    map[string]string
21
+
22
+	Content   []string
23
+	Snapshots map[string][]string
24
+}
25
+
26
+// LeaseManager manages the create/delete lifecyle of leases
27
+// and also returns existing leases
28
+type LeaseManager struct {
29
+	tx *bolt.Tx
30
+}
31
+
32
+// NewLeaseManager creates a new lease manager for managing leases using
33
+// the provided database transaction.
34
+func NewLeaseManager(tx *bolt.Tx) *LeaseManager {
35
+	return &LeaseManager{
36
+		tx: tx,
37
+	}
38
+}
39
+
40
+// Create creates a new lease using the provided lease
41
+func (lm *LeaseManager) Create(ctx context.Context, lid string, labels map[string]string) (Lease, error) {
42
+	namespace, err := namespaces.NamespaceRequired(ctx)
43
+	if err != nil {
44
+		return Lease{}, err
45
+	}
46
+
47
+	topbkt, err := createBucketIfNotExists(lm.tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases)
48
+	if err != nil {
49
+		return Lease{}, err
50
+	}
51
+
52
+	txbkt, err := topbkt.CreateBucket([]byte(lid))
53
+	if err != nil {
54
+		if err == bolt.ErrBucketExists {
55
+			err = errdefs.ErrAlreadyExists
56
+		}
57
+		return Lease{}, err
58
+	}
59
+
60
+	t := time.Now().UTC()
61
+	createdAt, err := t.MarshalBinary()
62
+	if err != nil {
63
+		return Lease{}, err
64
+	}
65
+	if err := txbkt.Put(bucketKeyCreatedAt, createdAt); err != nil {
66
+		return Lease{}, err
67
+	}
68
+
69
+	if labels != nil {
70
+		if err := boltutil.WriteLabels(txbkt, labels); err != nil {
71
+			return Lease{}, err
72
+		}
73
+	}
74
+
75
+	return Lease{
76
+		ID:        lid,
77
+		CreatedAt: t,
78
+		Labels:    labels,
79
+	}, nil
80
+}
81
+
82
+// Delete delets the lease with the provided lease ID
83
+func (lm *LeaseManager) Delete(ctx context.Context, lid string) error {
84
+	namespace, err := namespaces.NamespaceRequired(ctx)
85
+	if err != nil {
86
+		return err
87
+	}
88
+
89
+	topbkt := getBucket(lm.tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases)
90
+	if topbkt == nil {
91
+		return nil
92
+	}
93
+	if err := topbkt.DeleteBucket([]byte(lid)); err != nil && err != bolt.ErrBucketNotFound {
94
+		return err
95
+	}
96
+	return nil
97
+}
98
+
99
+// List lists all active leases
100
+func (lm *LeaseManager) List(ctx context.Context, includeResources bool, filter ...string) ([]Lease, error) {
101
+	namespace, err := namespaces.NamespaceRequired(ctx)
102
+	if err != nil {
103
+		return nil, err
104
+	}
105
+
106
+	var leases []Lease
107
+
108
+	topbkt := getBucket(lm.tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases)
109
+	if topbkt == nil {
110
+		return leases, nil
111
+	}
112
+
113
+	if err := topbkt.ForEach(func(k, v []byte) error {
114
+		if v != nil {
115
+			return nil
116
+		}
117
+		txbkt := topbkt.Bucket(k)
118
+
119
+		l := Lease{
120
+			ID: string(k),
121
+		}
122
+
123
+		if v := txbkt.Get(bucketKeyCreatedAt); v != nil {
124
+			t := &l.CreatedAt
125
+			if err := t.UnmarshalBinary(v); err != nil {
126
+				return err
127
+			}
128
+		}
129
+
130
+		labels, err := boltutil.ReadLabels(txbkt)
131
+		if err != nil {
132
+			return err
133
+		}
134
+		l.Labels = labels
135
+
136
+		// TODO: Read Snapshots
137
+		// TODO: Read Content
138
+
139
+		leases = append(leases, l)
140
+
141
+		return nil
142
+	}); err != nil {
143
+		return nil, err
144
+	}
145
+
146
+	return leases, nil
147
+}
148
+
149
+func addSnapshotLease(ctx context.Context, tx *bolt.Tx, snapshotter, key string) error {
150
+	lid, ok := leases.Lease(ctx)
151
+	if !ok {
152
+		return nil
153
+	}
154
+
155
+	namespace, ok := namespaces.Namespace(ctx)
156
+	if !ok {
157
+		panic("namespace must already be required")
158
+	}
159
+
160
+	bkt := getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases, []byte(lid))
161
+	if bkt == nil {
162
+		return errors.Wrap(errdefs.ErrNotFound, "lease does not exist")
163
+	}
164
+
165
+	bkt, err := bkt.CreateBucketIfNotExists(bucketKeyObjectSnapshots)
166
+	if err != nil {
167
+		return err
168
+	}
169
+
170
+	bkt, err = bkt.CreateBucketIfNotExists([]byte(snapshotter))
171
+	if err != nil {
172
+		return err
173
+	}
174
+
175
+	return bkt.Put([]byte(key), nil)
176
+}
177
+
178
+func addContentLease(ctx context.Context, tx *bolt.Tx, dgst digest.Digest) error {
179
+	lid, ok := leases.Lease(ctx)
180
+	if !ok {
181
+		return nil
182
+	}
183
+
184
+	namespace, ok := namespaces.Namespace(ctx)
185
+	if !ok {
186
+		panic("namespace must already be required")
187
+	}
188
+
189
+	bkt := getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases, []byte(lid))
190
+	if bkt == nil {
191
+		return errors.Wrap(errdefs.ErrNotFound, "lease does not exist")
192
+	}
193
+
194
+	bkt, err := bkt.CreateBucketIfNotExists(bucketKeyObjectContent)
195
+	if err != nil {
196
+		return err
197
+	}
198
+
199
+	return bkt.Put([]byte(dgst.String()), nil)
200
+}
... ...
@@ -326,6 +326,10 @@ func (s *snapshotter) createSnapshot(ctx context.Context, key, parent string, re
326 326
 			return err
327 327
 		}
328 328
 
329
+		if err := addSnapshotLease(ctx, tx, s.name, key); err != nil {
330
+			return err
331
+		}
332
+
329 333
 		// TODO: Consider doing this outside of transaction to lessen
330 334
 		// metadata lock time
331 335
 		if readonly {
332 336
deleted file mode 100644
... ...
@@ -1,83 +0,0 @@
1
-package mount
2
-
3
-// On Solaris we can't invoke the mount system call directly.  First,
4
-// the mount system call takes more than 6 arguments, and go doesn't
5
-// support invoking system calls that take more than 6 arguments.  Past
6
-// that, the mount system call is a private interfaces.  For example,
7
-// the arguments and data structures passed to the kernel to create an
8
-// nfs mount are private and can change at any time.  The only public
9
-// and stable interface for creating mounts on Solaris is the mount.8
10
-// command, so we'll invoke that here.
11
-
12
-import (
13
-	"bytes"
14
-	"errors"
15
-	"fmt"
16
-	"os/exec"
17
-	"strings"
18
-
19
-	"golang.org/x/sys/unix"
20
-)
21
-
22
-const (
23
-	mountCmd = "/usr/sbin/mount"
24
-)
25
-
26
-func doMount(arg ...string) error {
27
-	cmd := exec.Command(mountCmd, arg...)
28
-
29
-	/* Setup Stdin, Stdout, and Stderr */
30
-	stderr := new(bytes.Buffer)
31
-	cmd.Stdin = nil
32
-	cmd.Stdout = nil
33
-	cmd.Stderr = stderr
34
-
35
-	/*
36
-	 * Run the command.  If the command fails create a new error
37
-	 * object to return that includes stderr output.
38
-	 */
39
-	err := cmd.Start()
40
-	if err != nil {
41
-		return err
42
-	}
43
-	err = cmd.Wait()
44
-	if err != nil {
45
-		return errors.New(fmt.Sprintf("%v: %s", err, stderr.String()))
46
-	}
47
-	return nil
48
-}
49
-
50
-func (m *Mount) Mount(target string) error {
51
-	var err error
52
-
53
-	if len(m.Options) == 0 {
54
-		err = doMount("-F", m.Type, m.Source, target)
55
-	} else {
56
-		err = doMount("-F", m.Type, "-o", strings.Join(m.Options, ","),
57
-			m.Source, target)
58
-	}
59
-	return err
60
-}
61
-
62
-func Unmount(mount string, flags int) error {
63
-	return unix.Unmount(mount, flags)
64
-}
65
-
66
-// UnmountAll repeatedly unmounts the given mount point until there
67
-// are no mounts remaining (EINVAL is returned by mount), which is
68
-// useful for undoing a stack of mounts on the same mount point.
69
-func UnmountAll(mount string, flags int) error {
70
-	for {
71
-		if err := Unmount(mount, flags); err != nil {
72
-			// EINVAL is returned if the target is not a
73
-			// mount point, indicating that we are
74
-			// done. It can also indicate a few other
75
-			// things (such as invalid flags) which we
76
-			// unfortunately end up squelching here too.
77
-			if err == unix.EINVAL {
78
-				return nil
79
-			}
80
-			return err
81
-		}
82
-	}
83
-}
... ...
@@ -5,17 +5,21 @@ package mount
5 5
 import "github.com/pkg/errors"
6 6
 
7 7
 var (
8
+	// ErrNotImplementOnUnix is returned for methods that are not implemented
8 9
 	ErrNotImplementOnUnix = errors.New("not implemented under unix")
9 10
 )
10 11
 
12
+// Mount is not implemented on this platform
11 13
 func (m *Mount) Mount(target string) error {
12 14
 	return ErrNotImplementOnUnix
13 15
 }
14 16
 
17
+// Unmount is not implemented on this platform
15 18
 func Unmount(mount string, flags int) error {
16 19
 	return ErrNotImplementOnUnix
17 20
 }
18 21
 
22
+// UnmountAll is not implemented on this platform
19 23
 func UnmountAll(mount string, flags int) error {
20 24
 	return ErrNotImplementOnUnix
21 25
 }
... ...
@@ -3,17 +3,21 @@ package mount
3 3
 import "github.com/pkg/errors"
4 4
 
5 5
 var (
6
+	// ErrNotImplementOnWindows is returned when an action is not implemented for windows
6 7
 	ErrNotImplementOnWindows = errors.New("not implemented under windows")
7 8
 )
8 9
 
10
+// Mount to the provided target
9 11
 func (m *Mount) Mount(target string) error {
10 12
 	return ErrNotImplementOnWindows
11 13
 }
12 14
 
15
+// Unmount the mount at the provided path
13 16
 func Unmount(mount string, flags int) error {
14 17
 	return ErrNotImplementOnWindows
15 18
 }
16 19
 
20
+// UnmountAll mounts at the provided path
17 21
 func UnmountAll(mount string, flags int) error {
18 22
 	return ErrNotImplementOnWindows
19 23
 }
20 24
deleted file mode 100644
... ...
@@ -1,50 +0,0 @@
1
-// +build solaris,cgo
2
-
3
-package mount
4
-
5
-/*
6
-#include <stdio.h>
7
-#include <stdlib.h>
8
-#include <sys/mnttab.h>
9
-*/
10
-import "C"
11
-
12
-import (
13
-	"fmt"
14
-	"unsafe"
15
-)
16
-
17
-// Self retrieves a list of mounts for the current running process.
18
-func Self() ([]Info, error) {
19
-	path := C.CString(C.MNTTAB)
20
-	defer C.free(unsafe.Pointer(path))
21
-	mode := C.CString("r")
22
-	defer C.free(unsafe.Pointer(mode))
23
-
24
-	mnttab := C.fopen(path, mode)
25
-	if mnttab == nil {
26
-		return nil, fmt.Errorf("Failed to open %s", C.MNTTAB)
27
-	}
28
-
29
-	var out []Info
30
-	var mp C.struct_mnttab
31
-
32
-	ret := C.getmntent(mnttab, &mp)
33
-	for ret == 0 {
34
-		var mountinfo Info
35
-		mountinfo.Mountpoint = C.GoString(mp.mnt_mountp)
36
-		mountinfo.Source = C.GoString(mp.mnt_special)
37
-		mountinfo.FSType = C.GoString(mp.mnt_fstype)
38
-		mountinfo.Options = C.GoString(mp.mnt_mntopts)
39
-		out = append(out, mountinfo)
40
-		ret = C.getmntent(mnttab, &mp)
41
-	}
42
-
43
-	C.fclose(mnttab)
44
-	return out, nil
45
-}
46
-
47
-// PID collects the mounts for a specific process ID.
48
-func PID(pid int) ([]Info, error) {
49
-	return nil, fmt.Errorf("mountinfo.PID is not implemented on solaris")
50
-}
... ...
@@ -5,7 +5,7 @@ import (
5 5
 	"path/filepath"
6 6
 
7 7
 	"github.com/containerd/containerd/errdefs"
8
-	"github.com/containerd/containerd/events"
8
+	"github.com/containerd/containerd/events/exchange"
9 9
 	"github.com/containerd/containerd/log"
10 10
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
11 11
 	"github.com/pkg/errors"
... ...
@@ -18,15 +18,15 @@ type InitContext struct {
18 18
 	State   string
19 19
 	Config  interface{}
20 20
 	Address string
21
-	Events  *events.Exchange
21
+	Events  *exchange.Exchange
22 22
 
23 23
 	Meta *Meta // plugins can fill in metadata at init.
24 24
 
25
-	plugins *PluginSet
25
+	plugins *Set
26 26
 }
27 27
 
28 28
 // NewContext returns a new plugin InitContext
29
-func NewContext(ctx context.Context, r *Registration, plugins *PluginSet, root, state string) *InitContext {
29
+func NewContext(ctx context.Context, r *Registration, plugins *Set, root, state string) *InitContext {
30 30
 	return &InitContext{
31 31
 		Context: log.WithModule(ctx, r.URI()),
32 32
 		Root:    filepath.Join(root, r.URI()),
... ...
@@ -61,32 +61,37 @@ type Plugin struct {
61 61
 	err      error // will be set if there was an error initializing the plugin
62 62
 }
63 63
 
64
+// Err returns the errors during initialization.
65
+// returns nil if not error was encountered
64 66
 func (p *Plugin) Err() error {
65 67
 	return p.err
66 68
 }
67 69
 
70
+// Instance returns the instance and any initialization error of the plugin
68 71
 func (p *Plugin) Instance() (interface{}, error) {
69 72
 	return p.instance, p.err
70 73
 }
71 74
 
72
-// PluginSet defines a plugin collection, used with InitContext.
75
+// Set defines a plugin collection, used with InitContext.
73 76
 //
74 77
 // This maintains ordering and unique indexing over the set.
75 78
 //
76 79
 // After iteratively instantiating plugins, this set should represent, the
77 80
 // ordered, initialization set of plugins for a containerd instance.
78
-type PluginSet struct {
81
+type Set struct {
79 82
 	ordered     []*Plugin // order of initialization
80 83
 	byTypeAndID map[Type]map[string]*Plugin
81 84
 }
82 85
 
83
-func NewPluginSet() *PluginSet {
84
-	return &PluginSet{
86
+// NewPluginSet returns an initialized plugin set
87
+func NewPluginSet() *Set {
88
+	return &Set{
85 89
 		byTypeAndID: make(map[Type]map[string]*Plugin),
86 90
 	}
87 91
 }
88 92
 
89
-func (ps *PluginSet) Add(p *Plugin) error {
93
+// Add a plugin to the set
94
+func (ps *Set) Add(p *Plugin) error {
90 95
 	if byID, typeok := ps.byTypeAndID[p.Registration.Type]; !typeok {
91 96
 		ps.byTypeAndID[p.Registration.Type] = map[string]*Plugin{
92 97
 			p.Registration.ID: p,
... ...
@@ -102,13 +107,14 @@ func (ps *PluginSet) Add(p *Plugin) error {
102 102
 }
103 103
 
104 104
 // Get returns the first plugin by its type
105
-func (ps *PluginSet) Get(t Type) (interface{}, error) {
105
+func (ps *Set) Get(t Type) (interface{}, error) {
106 106
 	for _, v := range ps.byTypeAndID[t] {
107 107
 		return v.Instance()
108 108
 	}
109 109
 	return nil, errors.Wrapf(errdefs.ErrNotFound, "no plugins registered for %s", t)
110 110
 }
111 111
 
112
+// GetAll plugins in the set
112 113
 func (i *InitContext) GetAll() []*Plugin {
113 114
 	return i.plugins.ordered
114 115
 }
... ...
@@ -58,9 +58,13 @@ const (
58 58
 
59 59
 // Registration contains information for registering a plugin
60 60
 type Registration struct {
61
-	Type     Type
62
-	ID       string
63
-	Config   interface{}
61
+	// Type of the plugin
62
+	Type Type
63
+	// ID of the plugin
64
+	ID string
65
+	// Config specific to the plugin
66
+	Config interface{}
67
+	// Requires is a list of plugins that the registered plugin requires to be available
64 68
 	Requires []Type
65 69
 
66 70
 	// InitFn is called when initializing a plugin. The registration and
... ...
@@ -69,6 +73,7 @@ type Registration struct {
69 69
 	InitFn func(*InitContext) (interface{}, error)
70 70
 }
71 71
 
72
+// Init the registered plugin
72 73
 func (r *Registration) Init(ic *InitContext) *Plugin {
73 74
 	p, err := r.InitFn(ic)
74 75
 	return &Plugin{
... ...
@@ -9,6 +9,7 @@ import (
9 9
 	"fmt"
10 10
 	"io"
11 11
 	"io/ioutil"
12
+	"math/rand"
12 13
 	"strings"
13 14
 	"sync"
14 15
 	"time"
... ...
@@ -159,7 +160,6 @@ func (c *Converter) Convert(ctx context.Context) (ocispec.Descriptor, error) {
159 159
 	}
160 160
 
161 161
 	labels := map[string]string{}
162
-	labels["containerd.io/gc.root"] = time.Now().UTC().Format(time.RFC3339)
163 162
 	labels["containerd.io/gc.ref.content.0"] = manifest.Config.Digest.String()
164 163
 	for i, ch := range manifest.Layers {
165 164
 		labels[fmt.Sprintf("containerd.io/gc.ref.content.%d", i+1)] = ch.Digest.String()
... ...
@@ -175,12 +175,6 @@ func (c *Converter) Convert(ctx context.Context) (ocispec.Descriptor, error) {
175 175
 		return ocispec.Descriptor{}, errors.Wrap(err, "failed to write config")
176 176
 	}
177 177
 
178
-	for _, ch := range manifest.Layers {
179
-		if _, err := c.contentStore.Update(ctx, content.Info{Digest: ch.Digest}, "labels.containerd.io/gc.root"); err != nil {
180
-			return ocispec.Descriptor{}, errors.Wrap(err, "failed to remove blob root tag")
181
-		}
182
-	}
183
-
184 178
 	return desc, nil
185 179
 }
186 180
 
... ...
@@ -215,13 +209,26 @@ func (c *Converter) fetchManifest(ctx context.Context, desc ocispec.Descriptor)
215 215
 func (c *Converter) fetchBlob(ctx context.Context, desc ocispec.Descriptor) error {
216 216
 	log.G(ctx).Debug("fetch blob")
217 217
 
218
-	ref := remotes.MakeRefKey(ctx, desc)
219
-
220
-	calc := newBlobStateCalculator()
218
+	var (
219
+		ref   = remotes.MakeRefKey(ctx, desc)
220
+		calc  = newBlobStateCalculator()
221
+		retry = 16
222
+	)
221 223
 
224
+tryit:
222 225
 	cw, err := c.contentStore.Writer(ctx, ref, desc.Size, desc.Digest)
223 226
 	if err != nil {
224
-		if !errdefs.IsAlreadyExists(err) {
227
+		if errdefs.IsUnavailable(err) {
228
+			select {
229
+			case <-time.After(time.Millisecond * time.Duration(rand.Intn(retry))):
230
+				if retry < 2048 {
231
+					retry = retry << 1
232
+				}
233
+				goto tryit
234
+			case <-ctx.Done():
235
+				return err
236
+			}
237
+		} else if !errdefs.IsAlreadyExists(err) {
225 238
 			return err
226 239
 		}
227 240
 
... ...
@@ -270,10 +277,7 @@ func (c *Converter) fetchBlob(ctx context.Context, desc ocispec.Descriptor) erro
270 270
 
271 271
 		eg.Go(func() error {
272 272
 			defer pw.Close()
273
-			opt := content.WithLabels(map[string]string{
274
-				"containerd.io/gc.root": time.Now().UTC().Format(time.RFC3339),
275
-			})
276
-			return content.Copy(ctx, cw, io.TeeReader(rc, pw), desc.Size, desc.Digest, opt)
273
+			return content.Copy(ctx, cw, io.TeeReader(rc, pw), desc.Size, desc.Digest)
277 274
 		})
278 275
 
279 276
 		if err := eg.Wait(); err != nil {
... ...
@@ -5,6 +5,7 @@ import (
5 5
 	"encoding/json"
6 6
 	"fmt"
7 7
 	"io"
8
+	"math/rand"
8 9
 	"time"
9 10
 
10 11
 	"github.com/containerd/containerd/content"
... ...
@@ -44,7 +45,7 @@ func MakeRefKey(ctx context.Context, desc ocispec.Descriptor) string {
44 44
 // FetchHandler returns a handler that will fetch all content into the ingester
45 45
 // discovered in a call to Dispatch. Use with ChildrenHandler to do a full
46 46
 // recursive fetch.
47
-func FetchHandler(ingester content.Ingester, fetcher Fetcher, root ocispec.Descriptor) images.HandlerFunc {
47
+func FetchHandler(ingester content.Ingester, fetcher Fetcher) images.HandlerFunc {
48 48
 	return func(ctx context.Context, desc ocispec.Descriptor) (subdescs []ocispec.Descriptor, err error) {
49 49
 		ctx = log.WithLogger(ctx, log.G(ctx).WithFields(logrus.Fields{
50 50
 			"digest":    desc.Digest,
... ...
@@ -56,13 +57,13 @@ func FetchHandler(ingester content.Ingester, fetcher Fetcher, root ocispec.Descr
56 56
 		case images.MediaTypeDockerSchema1Manifest:
57 57
 			return nil, fmt.Errorf("%v not supported", desc.MediaType)
58 58
 		default:
59
-			err := fetch(ctx, ingester, fetcher, desc, desc.Digest == root.Digest)
59
+			err := fetch(ctx, ingester, fetcher, desc)
60 60
 			return nil, err
61 61
 		}
62 62
 	}
63 63
 }
64 64
 
65
-func fetch(ctx context.Context, ingester content.Ingester, fetcher Fetcher, desc ocispec.Descriptor, root bool) error {
65
+func fetch(ctx context.Context, ingester content.Ingester, fetcher Fetcher, desc ocispec.Descriptor) error {
66 66
 	log.G(ctx).Debug("fetch")
67 67
 
68 68
 	var (
... ...
@@ -84,7 +85,7 @@ func fetch(ctx context.Context, ingester content.Ingester, fetcher Fetcher, desc
84 84
 			// of writer and abort if not updated recently.
85 85
 
86 86
 			select {
87
-			case <-time.After(time.Millisecond * time.Duration(retry)):
87
+			case <-time.After(time.Millisecond * time.Duration(rand.Intn(retry))):
88 88
 				if retry < 2048 {
89 89
 					retry = retry << 1
90 90
 				}
... ...
@@ -104,13 +105,13 @@ func fetch(ctx context.Context, ingester content.Ingester, fetcher Fetcher, desc
104 104
 	}
105 105
 	defer rc.Close()
106 106
 
107
-	r, opts := commitOpts(desc, rc, root)
107
+	r, opts := commitOpts(desc, rc)
108 108
 	return content.Copy(ctx, cw, r, desc.Size, desc.Digest, opts...)
109 109
 }
110 110
 
111 111
 // commitOpts gets the appropriate content options to alter
112 112
 // the content info on commit based on media type.
113
-func commitOpts(desc ocispec.Descriptor, r io.Reader, root bool) (io.Reader, []content.Opt) {
113
+func commitOpts(desc ocispec.Descriptor, r io.Reader) (io.Reader, []content.Opt) {
114 114
 	var childrenF func(r io.Reader) ([]ocispec.Descriptor, error)
115 115
 
116 116
 	switch desc.MediaType {
... ...
@@ -162,13 +163,10 @@ func commitOpts(desc ocispec.Descriptor, r io.Reader, root bool) (io.Reader, []c
162 162
 			return errors.Wrap(err, "unable to get commit labels")
163 163
 		}
164 164
 
165
-		if len(children) > 0 || root {
165
+		if len(children) > 0 {
166 166
 			if info.Labels == nil {
167 167
 				info.Labels = map[string]string{}
168 168
 			}
169
-			if root {
170
-				info.Labels["containerd.io/gc.root"] = time.Now().UTC().Format(time.RFC3339)
171
-			}
172 169
 			for i, ch := range children {
173 170
 				info.Labels[fmt.Sprintf("containerd.io/gc.ref.content.%d", i)] = ch.Digest.String()
174 171
 			}
... ...
@@ -7,6 +7,7 @@ import (
7 7
 	"github.com/gogo/protobuf/types"
8 8
 )
9 9
 
10
+// TaskInfo provides task specific information
10 11
 type TaskInfo struct {
11 12
 	ID        string
12 13
 	Runtime   string
... ...
@@ -14,6 +15,7 @@ type TaskInfo struct {
14 14
 	Namespace string
15 15
 }
16 16
 
17
+// Process is a runtime object for an executing process inside a container
17 18
 type Process interface {
18 19
 	ID() string
19 20
 	// State returns the process state
... ...
@@ -30,6 +32,7 @@ type Process interface {
30 30
 	Wait(context.Context) (*Exit, error)
31 31
 }
32 32
 
33
+// Task is the runtime object for an executing container
33 34
 type Task interface {
34 35
 	Process
35 36
 
... ...
@@ -55,27 +58,37 @@ type Task interface {
55 55
 	Metrics(context.Context) (interface{}, error)
56 56
 }
57 57
 
58
+// ExecOpts provides additional options for additional processes running in a task
58 59
 type ExecOpts struct {
59 60
 	Spec *types.Any
60 61
 	IO   IO
61 62
 }
62 63
 
64
+// ConsoleSize of a pty or windows terminal
63 65
 type ConsoleSize struct {
64 66
 	Width  uint32
65 67
 	Height uint32
66 68
 }
67 69
 
70
+// Status is the runtime status of a task and/or process
68 71
 type Status int
69 72
 
70 73
 const (
74
+	// CreatedStatus when a process has been created
71 75
 	CreatedStatus Status = iota + 1
76
+	// RunningStatus when a process is running
72 77
 	RunningStatus
78
+	// StoppedStatus when a process has stopped
73 79
 	StoppedStatus
80
+	// DeletedStatus when a process has been deleted
74 81
 	DeletedStatus
82
+	// PausedStatus when a process is paused
75 83
 	PausedStatus
84
+	// PausingStatus when a process is currently pausing
76 85
 	PausingStatus
77 86
 )
78 87
 
88
+// State information for a process
79 89
 type State struct {
80 90
 	// Status is the current status of the container
81 91
 	Status Status
... ...
@@ -93,6 +106,7 @@ type State struct {
93 93
 	Terminal bool
94 94
 }
95 95
 
96
+// ProcessInfo holds platform specific process information
96 97
 type ProcessInfo struct {
97 98
 	// Pid is the process ID
98 99
 	Pid uint32
... ...
@@ -9,21 +9,26 @@ import (
9 9
 )
10 10
 
11 11
 var (
12
-	ErrTaskNotExists     = errors.New("task does not exist")
12
+	// ErrTaskNotExists is returned when a task does not exist
13
+	ErrTaskNotExists = errors.New("task does not exist")
14
+	// ErrTaskAlreadyExists is returned when a task already exists
13 15
 	ErrTaskAlreadyExists = errors.New("task already exists")
14 16
 )
15 17
 
18
+// NewTaskList returns a new TaskList
16 19
 func NewTaskList() *TaskList {
17 20
 	return &TaskList{
18 21
 		tasks: make(map[string]map[string]Task),
19 22
 	}
20 23
 }
21 24
 
25
+// TaskList holds and provides locking around tasks
22 26
 type TaskList struct {
23 27
 	mu    sync.Mutex
24 28
 	tasks map[string]map[string]Task
25 29
 }
26 30
 
31
+// Get a task
27 32
 func (l *TaskList) Get(ctx context.Context, id string) (Task, error) {
28 33
 	l.mu.Lock()
29 34
 	defer l.mu.Unlock()
... ...
@@ -42,6 +47,7 @@ func (l *TaskList) Get(ctx context.Context, id string) (Task, error) {
42 42
 	return t, nil
43 43
 }
44 44
 
45
+// GetAll tasks under a namespace
45 46
 func (l *TaskList) GetAll(ctx context.Context) ([]Task, error) {
46 47
 	namespace, err := namespaces.NamespaceRequired(ctx)
47 48
 	if err != nil {
... ...
@@ -58,6 +64,7 @@ func (l *TaskList) GetAll(ctx context.Context) ([]Task, error) {
58 58
 	return o, nil
59 59
 }
60 60
 
61
+// Add a task
61 62
 func (l *TaskList) Add(ctx context.Context, t Task) error {
62 63
 	namespace, err := namespaces.NamespaceRequired(ctx)
63 64
 	if err != nil {
... ...
@@ -66,6 +73,7 @@ func (l *TaskList) Add(ctx context.Context, t Task) error {
66 66
 	return l.AddWithNamespace(namespace, t)
67 67
 }
68 68
 
69
+// AddWithNamespace adds a task with the provided namespace
69 70
 func (l *TaskList) AddWithNamespace(namespace string, t Task) error {
70 71
 	l.mu.Lock()
71 72
 	defer l.mu.Unlock()
... ...
@@ -81,6 +89,7 @@ func (l *TaskList) AddWithNamespace(namespace string, t Task) error {
81 81
 	return nil
82 82
 }
83 83
 
84
+// Delete a task
84 85
 func (l *TaskList) Delete(ctx context.Context, t Task) {
85 86
 	l.mu.Lock()
86 87
 	defer l.mu.Unlock()
... ...
@@ -33,23 +33,27 @@ type Config struct {
33 33
 	md toml.MetaData
34 34
 }
35 35
 
36
+// GRPCConfig provides GRPC configuration for the socket
36 37
 type GRPCConfig struct {
37 38
 	Address string `toml:"address"`
38
-	Uid     int    `toml:"uid"`
39
-	Gid     int    `toml:"gid"`
39
+	UID     int    `toml:"uid"`
40
+	GID     int    `toml:"gid"`
40 41
 }
41 42
 
43
+// Debug provides debug configuration
42 44
 type Debug struct {
43 45
 	Address string `toml:"address"`
44
-	Uid     int    `toml:"uid"`
45
-	Gid     int    `toml:"gid"`
46
+	UID     int    `toml:"uid"`
47
+	GID     int    `toml:"gid"`
46 48
 	Level   string `toml:"level"`
47 49
 }
48 50
 
51
+// MetricsConfig provides metrics configuration
49 52
 type MetricsConfig struct {
50 53
 	Address string `toml:"address"`
51 54
 }
52 55
 
56
+// CgroupConfig provides cgroup configuration
53 57
 type CgroupConfig struct {
54 58
 	Path string `toml:"path"`
55 59
 }
... ...
@@ -16,13 +16,14 @@ import (
16 16
 	eventsapi "github.com/containerd/containerd/api/services/events/v1"
17 17
 	images "github.com/containerd/containerd/api/services/images/v1"
18 18
 	introspection "github.com/containerd/containerd/api/services/introspection/v1"
19
+	leasesapi "github.com/containerd/containerd/api/services/leases/v1"
19 20
 	namespaces "github.com/containerd/containerd/api/services/namespaces/v1"
20 21
 	snapshotapi "github.com/containerd/containerd/api/services/snapshot/v1"
21 22
 	tasks "github.com/containerd/containerd/api/services/tasks/v1"
22 23
 	version "github.com/containerd/containerd/api/services/version/v1"
23 24
 	"github.com/containerd/containerd/content"
24 25
 	"github.com/containerd/containerd/content/local"
25
-	"github.com/containerd/containerd/events"
26
+	"github.com/containerd/containerd/events/exchange"
26 27
 	"github.com/containerd/containerd/log"
27 28
 	"github.com/containerd/containerd/metadata"
28 29
 	"github.com/containerd/containerd/plugin"
... ...
@@ -65,7 +66,7 @@ func New(ctx context.Context, config *Config) (*Server, error) {
65 65
 		services []plugin.Service
66 66
 		s        = &Server{
67 67
 			rpc:    rpc,
68
-			events: events.NewExchange(),
68
+			events: exchange.NewExchange(),
69 69
 		}
70 70
 		initialized = plugin.NewPluginSet()
71 71
 	)
... ...
@@ -122,7 +123,7 @@ func New(ctx context.Context, config *Config) (*Server, error) {
122 122
 // Server is the containerd main daemon
123 123
 type Server struct {
124 124
 	rpc    *grpc.Server
125
-	events *events.Exchange
125
+	events *exchange.Exchange
126 126
 }
127 127
 
128 128
 // ServeGRPC provides the containerd grpc APIs on the provided listener
... ...
@@ -255,6 +256,8 @@ func interceptor(
255 255
 		ctx = log.WithModule(ctx, "events")
256 256
 	case introspection.IntrospectionServer:
257 257
 		ctx = log.WithModule(ctx, "introspection")
258
+	case leasesapi.LeasesServer:
259
+		ctx = log.WithModule(ctx, "leases")
258 260
 	default:
259 261
 		log.G(ctx).Warnf("unknown GRPC server type: %#v\n", info.Server)
260 262
 	}
... ...
@@ -10,19 +10,6 @@ import (
10 10
 	specs "github.com/opencontainers/runtime-spec/specs-go"
11 11
 )
12 12
 
13
-const (
14
-	// DefaultRootDir is the default location used by containerd to store
15
-	// persistent data
16
-	DefaultRootDir = "/var/lib/containerd"
17
-	// DefaultStateDir is the default location used by containerd to store
18
-	// transient data
19
-	DefaultStateDir = "/run/containerd"
20
-	// DefaultAddress is the default unix socket address
21
-	DefaultAddress = "/run/containerd/containerd.sock"
22
-	// DefaultDebugAddress is the default unix socket address for pprof data
23
-	DefaultDebugAddress = "/run/containerd/debug.sock"
24
-)
25
-
26 13
 // apply sets config settings on the server process
27 14
 func apply(ctx context.Context, config *Config) error {
28 15
 	if config.Subreaper {
... ...
@@ -44,6 +44,6 @@ func (ra *remoteReaderAt) ReadAt(p []byte, off int64) (n int, err error) {
44 44
 	return n, nil
45 45
 }
46 46
 
47
-func (rr *remoteReaderAt) Close() error {
47
+func (ra *remoteReaderAt) Close() error {
48 48
 	return nil
49 49
 }
... ...
@@ -21,7 +21,7 @@ import (
21 21
 	"google.golang.org/grpc/codes"
22 22
 )
23 23
 
24
-type Service struct {
24
+type service struct {
25 25
 	store     content.Store
26 26
 	publisher events.Publisher
27 27
 }
... ...
@@ -32,7 +32,7 @@ var bufPool = sync.Pool{
32 32
 	},
33 33
 }
34 34
 
35
-var _ api.ContentServer = &Service{}
35
+var _ api.ContentServer = &service{}
36 36
 
37 37
 func init() {
38 38
 	plugin.Register(&plugin.Registration{
... ...
@@ -53,19 +53,20 @@ func init() {
53 53
 	})
54 54
 }
55 55
 
56
-func NewService(cs content.Store, publisher events.Publisher) (*Service, error) {
57
-	return &Service{
56
+// NewService returns the content GRPC server
57
+func NewService(cs content.Store, publisher events.Publisher) (api.ContentServer, error) {
58
+	return &service{
58 59
 		store:     cs,
59 60
 		publisher: publisher,
60 61
 	}, nil
61 62
 }
62 63
 
63
-func (s *Service) Register(server *grpc.Server) error {
64
+func (s *service) Register(server *grpc.Server) error {
64 65
 	api.RegisterContentServer(server, s)
65 66
 	return nil
66 67
 }
67 68
 
68
-func (s *Service) Info(ctx context.Context, req *api.InfoRequest) (*api.InfoResponse, error) {
69
+func (s *service) Info(ctx context.Context, req *api.InfoRequest) (*api.InfoResponse, error) {
69 70
 	if err := req.Digest.Validate(); err != nil {
70 71
 		return nil, grpc.Errorf(codes.InvalidArgument, "%q failed validation", req.Digest)
71 72
 	}
... ...
@@ -80,7 +81,7 @@ func (s *Service) Info(ctx context.Context, req *api.InfoRequest) (*api.InfoResp
80 80
 	}, nil
81 81
 }
82 82
 
83
-func (s *Service) Update(ctx context.Context, req *api.UpdateRequest) (*api.UpdateResponse, error) {
83
+func (s *service) Update(ctx context.Context, req *api.UpdateRequest) (*api.UpdateResponse, error) {
84 84
 	if err := req.Info.Digest.Validate(); err != nil {
85 85
 		return nil, grpc.Errorf(codes.InvalidArgument, "%q failed validation", req.Info.Digest)
86 86
 	}
... ...
@@ -95,7 +96,7 @@ func (s *Service) Update(ctx context.Context, req *api.UpdateRequest) (*api.Upda
95 95
 	}, nil
96 96
 }
97 97
 
98
-func (s *Service) List(req *api.ListContentRequest, session api.Content_ListServer) error {
98
+func (s *service) List(req *api.ListContentRequest, session api.Content_ListServer) error {
99 99
 	var (
100 100
 		buffer    []api.Info
101 101
 		sendBlock = func(block []api.Info) error {
... ...
@@ -137,7 +138,7 @@ func (s *Service) List(req *api.ListContentRequest, session api.Content_ListServ
137 137
 	return nil
138 138
 }
139 139
 
140
-func (s *Service) Delete(ctx context.Context, req *api.DeleteContentRequest) (*empty.Empty, error) {
140
+func (s *service) Delete(ctx context.Context, req *api.DeleteContentRequest) (*empty.Empty, error) {
141 141
 	if err := req.Digest.Validate(); err != nil {
142 142
 		return nil, grpc.Errorf(codes.InvalidArgument, err.Error())
143 143
 	}
... ...
@@ -155,7 +156,7 @@ func (s *Service) Delete(ctx context.Context, req *api.DeleteContentRequest) (*e
155 155
 	return &empty.Empty{}, nil
156 156
 }
157 157
 
158
-func (s *Service) Read(req *api.ReadContentRequest, session api.Content_ReadServer) error {
158
+func (s *service) Read(req *api.ReadContentRequest, session api.Content_ReadServer) error {
159 159
 	if err := req.Digest.Validate(); err != nil {
160 160
 		return grpc.Errorf(codes.InvalidArgument, "%v: %v", req.Digest, err)
161 161
 	}
... ...
@@ -223,7 +224,7 @@ func (rw *readResponseWriter) Write(p []byte) (n int, err error) {
223 223
 	return len(p), nil
224 224
 }
225 225
 
226
-func (s *Service) Status(ctx context.Context, req *api.StatusRequest) (*api.StatusResponse, error) {
226
+func (s *service) Status(ctx context.Context, req *api.StatusRequest) (*api.StatusResponse, error) {
227 227
 	status, err := s.store.Status(ctx, req.Ref)
228 228
 	if err != nil {
229 229
 		return nil, errdefs.ToGRPCf(err, "could not get status for ref %q", req.Ref)
... ...
@@ -242,7 +243,7 @@ func (s *Service) Status(ctx context.Context, req *api.StatusRequest) (*api.Stat
242 242
 	return &resp, nil
243 243
 }
244 244
 
245
-func (s *Service) ListStatuses(ctx context.Context, req *api.ListStatusesRequest) (*api.ListStatusesResponse, error) {
245
+func (s *service) ListStatuses(ctx context.Context, req *api.ListStatusesRequest) (*api.ListStatusesResponse, error) {
246 246
 	statuses, err := s.store.ListStatuses(ctx, req.Filters...)
247 247
 	if err != nil {
248 248
 		return nil, errdefs.ToGRPC(err)
... ...
@@ -263,7 +264,7 @@ func (s *Service) ListStatuses(ctx context.Context, req *api.ListStatusesRequest
263 263
 	return &resp, nil
264 264
 }
265 265
 
266
-func (s *Service) Write(session api.Content_WriteServer) (err error) {
266
+func (s *service) Write(session api.Content_WriteServer) (err error) {
267 267
 	var (
268 268
 		ctx      = session.Context()
269 269
 		msg      api.WriteContentResponse
... ...
@@ -283,7 +284,7 @@ func (s *Service) Write(session api.Content_WriteServer) (err error) {
283 283
 				// identically across all GRPC methods.
284 284
 				//
285 285
 				// This is pretty noisy, so we can remove it but leave it for now.
286
-				log.G(ctx).WithError(err).Error("(*Service).Write failed")
286
+				log.G(ctx).WithError(err).Error("(*service).Write failed")
287 287
 			}
288 288
 
289 289
 			return
... ...
@@ -319,7 +320,7 @@ func (s *Service) Write(session api.Content_WriteServer) (err error) {
319 319
 
320 320
 	ctx = log.WithLogger(ctx, log.G(ctx).WithFields(fields))
321 321
 
322
-	log.G(ctx).Debug("(*Service).Write started")
322
+	log.G(ctx).Debug("(*service).Write started")
323 323
 	// this action locks the writer for the session.
324 324
 	wr, err := s.store.Writer(ctx, ref, total, expected)
325 325
 	if err != nil {
... ...
@@ -444,7 +445,7 @@ func (s *Service) Write(session api.Content_WriteServer) (err error) {
444 444
 	}
445 445
 }
446 446
 
447
-func (s *Service) Abort(ctx context.Context, req *api.AbortRequest) (*empty.Empty, error) {
447
+func (s *service) Abort(ctx context.Context, req *api.AbortRequest) (*empty.Empty, error) {
448 448
 	if err := s.store.Abort(ctx, req.Ref); err != nil {
449 449
 		return nil, errdefs.ToGRPC(err)
450 450
 	}
... ...
@@ -15,6 +15,7 @@ type remoteStore struct {
15 15
 	client contentapi.ContentClient
16 16
 }
17 17
 
18
+// NewStoreFromClient returns a new content store
18 19
 func NewStoreFromClient(client contentapi.ContentClient) content.Store {
19 20
 	return &remoteStore{
20 21
 		client: client,
... ...
@@ -9,7 +9,7 @@ import (
9 9
 	"golang.org/x/net/context"
10 10
 )
11 11
 
12
-// NewApplierFromClient returns a new Applier which communicates
12
+// NewDiffServiceFromClient returns a new diff service which communicates
13 13
 // over a GRPC connection.
14 14
 func NewDiffServiceFromClient(client diffapi.DiffClient) diff.Differ {
15 15
 	return &remote{
... ...
@@ -13,6 +13,7 @@ type remoteStore struct {
13 13
 	client imagesapi.ImagesClient
14 14
 }
15 15
 
16
+// NewStoreFromClient returns a new image store client
16 17
 func NewStoreFromClient(client imagesapi.ImagesClient) images.Store {
17 18
 	return &remoteStore{
18 19
 		client: client,
... ...
@@ -34,24 +34,25 @@ func init() {
34 34
 	})
35 35
 }
36 36
 
37
-type Service struct {
37
+type service struct {
38 38
 	db        *metadata.DB
39 39
 	publisher events.Publisher
40 40
 }
41 41
 
42
+// NewService returns the GRPC image server
42 43
 func NewService(db *metadata.DB, publisher events.Publisher) imagesapi.ImagesServer {
43
-	return &Service{
44
+	return &service{
44 45
 		db:        db,
45 46
 		publisher: publisher,
46 47
 	}
47 48
 }
48 49
 
49
-func (s *Service) Register(server *grpc.Server) error {
50
+func (s *service) Register(server *grpc.Server) error {
50 51
 	imagesapi.RegisterImagesServer(server, s)
51 52
 	return nil
52 53
 }
53 54
 
54
-func (s *Service) Get(ctx context.Context, req *imagesapi.GetImageRequest) (*imagesapi.GetImageResponse, error) {
55
+func (s *service) Get(ctx context.Context, req *imagesapi.GetImageRequest) (*imagesapi.GetImageResponse, error) {
55 56
 	var resp imagesapi.GetImageResponse
56 57
 
57 58
 	return &resp, errdefs.ToGRPC(s.withStoreView(ctx, func(ctx context.Context, store images.Store) error {
... ...
@@ -65,7 +66,7 @@ func (s *Service) Get(ctx context.Context, req *imagesapi.GetImageRequest) (*ima
65 65
 	}))
66 66
 }
67 67
 
68
-func (s *Service) List(ctx context.Context, req *imagesapi.ListImagesRequest) (*imagesapi.ListImagesResponse, error) {
68
+func (s *service) List(ctx context.Context, req *imagesapi.ListImagesRequest) (*imagesapi.ListImagesResponse, error) {
69 69
 	var resp imagesapi.ListImagesResponse
70 70
 
71 71
 	return &resp, errdefs.ToGRPC(s.withStoreView(ctx, func(ctx context.Context, store images.Store) error {
... ...
@@ -79,7 +80,7 @@ func (s *Service) List(ctx context.Context, req *imagesapi.ListImagesRequest) (*
79 79
 	}))
80 80
 }
81 81
 
82
-func (s *Service) Create(ctx context.Context, req *imagesapi.CreateImageRequest) (*imagesapi.CreateImageResponse, error) {
82
+func (s *service) Create(ctx context.Context, req *imagesapi.CreateImageRequest) (*imagesapi.CreateImageResponse, error) {
83 83
 	if req.Image.Name == "" {
84 84
 		return nil, status.Errorf(codes.InvalidArgument, "Image.Name required")
85 85
 	}
... ...
@@ -111,7 +112,7 @@ func (s *Service) Create(ctx context.Context, req *imagesapi.CreateImageRequest)
111 111
 
112 112
 }
113 113
 
114
-func (s *Service) Update(ctx context.Context, req *imagesapi.UpdateImageRequest) (*imagesapi.UpdateImageResponse, error) {
114
+func (s *service) Update(ctx context.Context, req *imagesapi.UpdateImageRequest) (*imagesapi.UpdateImageResponse, error) {
115 115
 	if req.Image.Name == "" {
116 116
 		return nil, status.Errorf(codes.InvalidArgument, "Image.Name required")
117 117
 	}
... ...
@@ -149,7 +150,7 @@ func (s *Service) Update(ctx context.Context, req *imagesapi.UpdateImageRequest)
149 149
 	return &resp, nil
150 150
 }
151 151
 
152
-func (s *Service) Delete(ctx context.Context, req *imagesapi.DeleteImageRequest) (*empty.Empty, error) {
152
+func (s *service) Delete(ctx context.Context, req *imagesapi.DeleteImageRequest) (*empty.Empty, error) {
153 153
 	if err := s.withStoreUpdate(ctx, func(ctx context.Context, store images.Store) error {
154 154
 		return errdefs.ToGRPC(store.Delete(ctx, req.Name))
155 155
 	}); err != nil {
... ...
@@ -169,14 +170,14 @@ func (s *Service) Delete(ctx context.Context, req *imagesapi.DeleteImageRequest)
169 169
 	return &empty.Empty{}, nil
170 170
 }
171 171
 
172
-func (s *Service) withStore(ctx context.Context, fn func(ctx context.Context, store images.Store) error) func(tx *bolt.Tx) error {
172
+func (s *service) withStore(ctx context.Context, fn func(ctx context.Context, store images.Store) error) func(tx *bolt.Tx) error {
173 173
 	return func(tx *bolt.Tx) error { return fn(ctx, metadata.NewImageStore(tx)) }
174 174
 }
175 175
 
176
-func (s *Service) withStoreView(ctx context.Context, fn func(ctx context.Context, store images.Store) error) error {
176
+func (s *service) withStoreView(ctx context.Context, fn func(ctx context.Context, store images.Store) error) error {
177 177
 	return s.db.View(s.withStore(ctx, fn))
178 178
 }
179 179
 
180
-func (s *Service) withStoreUpdate(ctx context.Context, fn func(ctx context.Context, store images.Store) error) error {
180
+func (s *service) withStoreUpdate(ctx context.Context, fn func(ctx context.Context, store images.Store) error) error {
181 181
 	return s.db.Update(s.withStore(ctx, fn))
182 182
 }
183 183
new file mode 100644
... ...
@@ -0,0 +1,97 @@
0
+package namespaces
1
+
2
+import (
3
+	"context"
4
+	"strings"
5
+
6
+	api "github.com/containerd/containerd/api/services/namespaces/v1"
7
+	"github.com/containerd/containerd/errdefs"
8
+	"github.com/containerd/containerd/namespaces"
9
+	"github.com/gogo/protobuf/types"
10
+)
11
+
12
+// NewStoreFromClient returns a new namespace store
13
+func NewStoreFromClient(client api.NamespacesClient) namespaces.Store {
14
+	return &remote{client: client}
15
+}
16
+
17
+type remote struct {
18
+	client api.NamespacesClient
19
+}
20
+
21
+func (r *remote) Create(ctx context.Context, namespace string, labels map[string]string) error {
22
+	var req api.CreateNamespaceRequest
23
+
24
+	req.Namespace = api.Namespace{
25
+		Name:   namespace,
26
+		Labels: labels,
27
+	}
28
+
29
+	_, err := r.client.Create(ctx, &req)
30
+	if err != nil {
31
+		return errdefs.FromGRPC(err)
32
+	}
33
+
34
+	return nil
35
+}
36
+
37
+func (r *remote) Labels(ctx context.Context, namespace string) (map[string]string, error) {
38
+	var req api.GetNamespaceRequest
39
+	req.Name = namespace
40
+
41
+	resp, err := r.client.Get(ctx, &req)
42
+	if err != nil {
43
+		return nil, errdefs.FromGRPC(err)
44
+	}
45
+
46
+	return resp.Namespace.Labels, nil
47
+}
48
+
49
+func (r *remote) SetLabel(ctx context.Context, namespace, key, value string) error {
50
+	var req api.UpdateNamespaceRequest
51
+
52
+	req.Namespace = api.Namespace{
53
+		Name:   namespace,
54
+		Labels: map[string]string{key: value},
55
+	}
56
+
57
+	req.UpdateMask = &types.FieldMask{
58
+		Paths: []string{strings.Join([]string{"labels", key}, ".")},
59
+	}
60
+
61
+	_, err := r.client.Update(ctx, &req)
62
+	if err != nil {
63
+		return errdefs.FromGRPC(err)
64
+	}
65
+
66
+	return nil
67
+}
68
+
69
+func (r *remote) List(ctx context.Context) ([]string, error) {
70
+	var req api.ListNamespacesRequest
71
+
72
+	resp, err := r.client.List(ctx, &req)
73
+	if err != nil {
74
+		return nil, errdefs.FromGRPC(err)
75
+	}
76
+
77
+	var namespaces []string
78
+
79
+	for _, ns := range resp.Namespaces {
80
+		namespaces = append(namespaces, ns.Name)
81
+	}
82
+
83
+	return namespaces, nil
84
+}
85
+
86
+func (r *remote) Delete(ctx context.Context, namespace string) error {
87
+	var req api.DeleteNamespaceRequest
88
+
89
+	req.Name = namespace
90
+	_, err := r.client.Delete(ctx, &req)
91
+	if err != nil {
92
+		return errdefs.FromGRPC(err)
93
+	}
94
+
95
+	return nil
96
+}
0 97
new file mode 100644
... ...
@@ -0,0 +1,212 @@
0
+package namespaces
1
+
2
+import (
3
+	"strings"
4
+
5
+	"github.com/boltdb/bolt"
6
+	eventsapi "github.com/containerd/containerd/api/services/events/v1"
7
+	api "github.com/containerd/containerd/api/services/namespaces/v1"
8
+	"github.com/containerd/containerd/errdefs"
9
+	"github.com/containerd/containerd/events"
10
+	"github.com/containerd/containerd/metadata"
11
+	"github.com/containerd/containerd/namespaces"
12
+	"github.com/containerd/containerd/plugin"
13
+	"github.com/golang/protobuf/ptypes/empty"
14
+	"golang.org/x/net/context"
15
+	"google.golang.org/grpc"
16
+	"google.golang.org/grpc/codes"
17
+)
18
+
19
+func init() {
20
+	plugin.Register(&plugin.Registration{
21
+		Type: plugin.GRPCPlugin,
22
+		ID:   "namespaces",
23
+		Requires: []plugin.Type{
24
+			plugin.MetadataPlugin,
25
+		},
26
+		InitFn: func(ic *plugin.InitContext) (interface{}, error) {
27
+			m, err := ic.Get(plugin.MetadataPlugin)
28
+			if err != nil {
29
+				return nil, err
30
+			}
31
+			return NewService(m.(*metadata.DB), ic.Events), nil
32
+		},
33
+	})
34
+}
35
+
36
+type service struct {
37
+	db        *metadata.DB
38
+	publisher events.Publisher
39
+}
40
+
41
+var _ api.NamespacesServer = &service{}
42
+
43
+// NewService returns the GRPC namespaces server
44
+func NewService(db *metadata.DB, publisher events.Publisher) api.NamespacesServer {
45
+	return &service{
46
+		db:        db,
47
+		publisher: publisher,
48
+	}
49
+}
50
+
51
+func (s *service) Register(server *grpc.Server) error {
52
+	api.RegisterNamespacesServer(server, s)
53
+	return nil
54
+}
55
+
56
+func (s *service) Get(ctx context.Context, req *api.GetNamespaceRequest) (*api.GetNamespaceResponse, error) {
57
+	var resp api.GetNamespaceResponse
58
+
59
+	return &resp, s.withStoreView(ctx, func(ctx context.Context, store namespaces.Store) error {
60
+		labels, err := store.Labels(ctx, req.Name)
61
+		if err != nil {
62
+			return errdefs.ToGRPC(err)
63
+		}
64
+
65
+		resp.Namespace = api.Namespace{
66
+			Name:   req.Name,
67
+			Labels: labels,
68
+		}
69
+
70
+		return nil
71
+	})
72
+}
73
+
74
+func (s *service) List(ctx context.Context, req *api.ListNamespacesRequest) (*api.ListNamespacesResponse, error) {
75
+	var resp api.ListNamespacesResponse
76
+
77
+	return &resp, s.withStoreView(ctx, func(ctx context.Context, store namespaces.Store) error {
78
+		namespaces, err := store.List(ctx)
79
+		if err != nil {
80
+			return err
81
+		}
82
+
83
+		for _, namespace := range namespaces {
84
+			labels, err := store.Labels(ctx, namespace)
85
+			if err != nil {
86
+				// In general, this should be unlikely, since we are holding a
87
+				// transaction to service this request.
88
+				return errdefs.ToGRPC(err)
89
+			}
90
+
91
+			resp.Namespaces = append(resp.Namespaces, api.Namespace{
92
+				Name:   namespace,
93
+				Labels: labels,
94
+			})
95
+		}
96
+
97
+		return nil
98
+	})
99
+}
100
+
101
+func (s *service) Create(ctx context.Context, req *api.CreateNamespaceRequest) (*api.CreateNamespaceResponse, error) {
102
+	var resp api.CreateNamespaceResponse
103
+
104
+	if err := s.withStoreUpdate(ctx, func(ctx context.Context, store namespaces.Store) error {
105
+		if err := store.Create(ctx, req.Namespace.Name, req.Namespace.Labels); err != nil {
106
+			return errdefs.ToGRPC(err)
107
+		}
108
+
109
+		for k, v := range req.Namespace.Labels {
110
+			if err := store.SetLabel(ctx, req.Namespace.Name, k, v); err != nil {
111
+				return err
112
+			}
113
+		}
114
+
115
+		resp.Namespace = req.Namespace
116
+		return nil
117
+	}); err != nil {
118
+		return &resp, err
119
+	}
120
+
121
+	if err := s.publisher.Publish(ctx, "/namespaces/create", &eventsapi.NamespaceCreate{
122
+		Name:   req.Namespace.Name,
123
+		Labels: req.Namespace.Labels,
124
+	}); err != nil {
125
+		return &resp, err
126
+	}
127
+
128
+	return &resp, nil
129
+
130
+}
131
+
132
+func (s *service) Update(ctx context.Context, req *api.UpdateNamespaceRequest) (*api.UpdateNamespaceResponse, error) {
133
+	var resp api.UpdateNamespaceResponse
134
+	if err := s.withStoreUpdate(ctx, func(ctx context.Context, store namespaces.Store) error {
135
+		if req.UpdateMask != nil && len(req.UpdateMask.Paths) > 0 {
136
+			for _, path := range req.UpdateMask.Paths {
137
+				switch {
138
+				case strings.HasPrefix(path, "labels."):
139
+					key := strings.TrimPrefix(path, "labels.")
140
+					if err := store.SetLabel(ctx, req.Namespace.Name, key, req.Namespace.Labels[key]); err != nil {
141
+						return err
142
+					}
143
+				default:
144
+					return grpc.Errorf(codes.InvalidArgument, "cannot update %q field", path)
145
+				}
146
+			}
147
+		} else {
148
+			// clear out the existing labels and then set them to the incoming request.
149
+			// get current set of labels
150
+			labels, err := store.Labels(ctx, req.Namespace.Name)
151
+			if err != nil {
152
+				return errdefs.ToGRPC(err)
153
+			}
154
+
155
+			for k := range labels {
156
+				if err := store.SetLabel(ctx, req.Namespace.Name, k, ""); err != nil {
157
+					return err
158
+				}
159
+			}
160
+
161
+			for k, v := range req.Namespace.Labels {
162
+				if err := store.SetLabel(ctx, req.Namespace.Name, k, v); err != nil {
163
+					return err
164
+				}
165
+
166
+			}
167
+		}
168
+
169
+		return nil
170
+	}); err != nil {
171
+		return &resp, err
172
+	}
173
+
174
+	if err := s.publisher.Publish(ctx, "/namespaces/update", &eventsapi.NamespaceUpdate{
175
+		Name:   req.Namespace.Name,
176
+		Labels: req.Namespace.Labels,
177
+	}); err != nil {
178
+		return &resp, err
179
+	}
180
+
181
+	return &resp, nil
182
+}
183
+
184
+func (s *service) Delete(ctx context.Context, req *api.DeleteNamespaceRequest) (*empty.Empty, error) {
185
+	if err := s.withStoreUpdate(ctx, func(ctx context.Context, store namespaces.Store) error {
186
+		return errdefs.ToGRPC(store.Delete(ctx, req.Name))
187
+	}); err != nil {
188
+		return &empty.Empty{}, err
189
+	}
190
+	// set the namespace in the context before publishing the event
191
+	ctx = namespaces.WithNamespace(ctx, req.Name)
192
+	if err := s.publisher.Publish(ctx, "/namespaces/delete", &eventsapi.NamespaceDelete{
193
+		Name: req.Name,
194
+	}); err != nil {
195
+		return &empty.Empty{}, err
196
+	}
197
+
198
+	return &empty.Empty{}, nil
199
+}
200
+
201
+func (s *service) withStore(ctx context.Context, fn func(ctx context.Context, store namespaces.Store) error) func(tx *bolt.Tx) error {
202
+	return func(tx *bolt.Tx) error { return fn(ctx, metadata.NewNamespaceStore(tx)) }
203
+}
204
+
205
+func (s *service) withStoreView(ctx context.Context, fn func(ctx context.Context, store namespaces.Store) error) error {
206
+	return s.db.View(s.withStore(ctx, fn))
207
+}
208
+
209
+func (s *service) withStoreUpdate(ctx context.Context, fn func(ctx context.Context, store namespaces.Store) error) error {
210
+	return s.db.Update(s.withStore(ctx, fn))
211
+}
... ...
@@ -20,6 +20,9 @@ const (
20 20
 	KindCommitted
21 21
 )
22 22
 
23
+// ParseKind parses the provided string into a Kind
24
+//
25
+// If the string cannot be parsed KindUnknown is returned
23 26
 func ParseKind(s string) Kind {
24 27
 	s = strings.ToLower(s)
25 28
 	switch s {
... ...
@@ -34,6 +37,7 @@ func ParseKind(s string) Kind {
34 34
 	return KindUnknown
35 35
 }
36 36
 
37
+// String returns the string representation of the Kind
37 38
 func (k Kind) String() string {
38 39
 	switch k {
39 40
 	case KindView:
... ...
@@ -47,10 +51,12 @@ func (k Kind) String() string {
47 47
 	return "Unknown"
48 48
 }
49 49
 
50
+// MarshalJSON the Kind to JSON
50 51
 func (k Kind) MarshalJSON() ([]byte, error) {
51 52
 	return json.Marshal(k.String())
52 53
 }
53 54
 
55
+// UnmarshalJSON the Kind from JSON
54 56
 func (k *Kind) UnmarshalJSON(b []byte) error {
55 57
 	var s string
56 58
 	if err := json.Unmarshal(b, &s); err != nil {
... ...
@@ -81,6 +87,7 @@ type Usage struct {
81 81
 	Size   int64 // provides usage, in bytes, of snapshot
82 82
 }
83 83
 
84
+// Add the provided usage to the current usage
84 85
 func (u *Usage) Add(other Usage) {
85 86
 	u.Size += other.Size
86 87
 
... ...
@@ -11,17 +11,16 @@ import (
11 11
 	"path/filepath"
12 12
 	"strconv"
13 13
 	"strings"
14
-	"time"
15 14
 
16 15
 	"golang.org/x/sys/unix"
17 16
 
18 17
 	"github.com/containerd/containerd/containers"
19 18
 	"github.com/containerd/containerd/content"
19
+	"github.com/containerd/containerd/errdefs"
20 20
 	"github.com/containerd/containerd/fs"
21 21
 	"github.com/containerd/containerd/images"
22 22
 	"github.com/containerd/containerd/namespaces"
23 23
 	"github.com/containerd/containerd/platforms"
24
-	"github.com/containerd/containerd/snapshot"
25 24
 	"github.com/opencontainers/image-spec/identity"
26 25
 	"github.com/opencontainers/image-spec/specs-go/v1"
27 26
 	"github.com/opencontainers/runc/libcontainer/user"
... ...
@@ -260,19 +259,17 @@ func withRemappedSnapshotBase(id string, i Image, uid, gid uint32, readonly bool
260 260
 			snapshotter = client.SnapshotService(c.Snapshotter)
261 261
 			parent      = identity.ChainID(diffIDs).String()
262 262
 			usernsID    = fmt.Sprintf("%s-%d-%d", parent, uid, gid)
263
-			opt         = snapshot.WithLabels(map[string]string{
264
-				"containerd.io/gc.root": time.Now().UTC().Format(time.RFC3339),
265
-			})
266 263
 		)
267 264
 		if _, err := snapshotter.Stat(ctx, usernsID); err == nil {
268
-			if _, err := snapshotter.Prepare(ctx, id, usernsID, opt); err != nil {
265
+			if _, err := snapshotter.Prepare(ctx, id, usernsID); err == nil {
266
+				c.SnapshotKey = id
267
+				c.Image = i.Name()
268
+				return nil
269
+			} else if !errdefs.IsNotFound(err) {
269 270
 				return err
270 271
 			}
271
-			c.SnapshotKey = id
272
-			c.Image = i.Name()
273
-			return nil
274 272
 		}
275
-		mounts, err := snapshotter.Prepare(ctx, usernsID+"-remap", parent, opt)
273
+		mounts, err := snapshotter.Prepare(ctx, usernsID+"-remap", parent)
276 274
 		if err != nil {
277 275
 			return err
278 276
 		}
... ...
@@ -280,13 +277,13 @@ func withRemappedSnapshotBase(id string, i Image, uid, gid uint32, readonly bool
280 280
 			snapshotter.Remove(ctx, usernsID)
281 281
 			return err
282 282
 		}
283
-		if err := snapshotter.Commit(ctx, usernsID, usernsID+"-remap", opt); err != nil {
283
+		if err := snapshotter.Commit(ctx, usernsID, usernsID+"-remap"); err != nil {
284 284
 			return err
285 285
 		}
286 286
 		if readonly {
287
-			_, err = snapshotter.View(ctx, id, usernsID, opt)
287
+			_, err = snapshotter.View(ctx, id, usernsID)
288 288
 		} else {
289
-			_, err = snapshotter.Prepare(ctx, id, usernsID, opt)
289
+			_, err = snapshotter.Prepare(ctx, id, usernsID)
290 290
 		}
291 291
 		if err != nil {
292 292
 			return err
... ...
@@ -15,6 +15,7 @@ import (
15 15
 	specs "github.com/opencontainers/runtime-spec/specs-go"
16 16
 )
17 17
 
18
+// WithImageConfig configures the spec to from the configuration of an Image
18 19
 func WithImageConfig(i Image) SpecOpts {
19 20
 	return func(ctx context.Context, client *Client, _ *containers.Container, s *specs.Spec) error {
20 21
 		var (
... ...
@@ -51,6 +52,8 @@ func WithImageConfig(i Image) SpecOpts {
51 51
 	}
52 52
 }
53 53
 
54
+// WithTTY sets the information on the spec as well as the environment variables for
55
+// using a TTY
54 56
 func WithTTY(width, height int) SpecOpts {
55 57
 	return func(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
56 58
 		s.Process.Terminal = true
... ...
@@ -63,6 +66,7 @@ func WithTTY(width, height int) SpecOpts {
63 63
 	}
64 64
 }
65 65
 
66
+// WithResources sets the provided resources on the spec for task updates
66 67
 func WithResources(resources *specs.WindowsResources) UpdateTaskOpts {
67 68
 	return func(ctx context.Context, client *Client, r *UpdateTaskInfo) error {
68 69
 		r.Resources = resources
... ...
@@ -151,6 +151,7 @@ func createDefaultSpec(ctx context.Context, id string) (*specs.Spec, error) {
151 151
 				"/proc/timer_stats",
152 152
 				"/proc/sched_debug",
153 153
 				"/sys/firmware",
154
+				"/proc/scsi",
154 155
 			},
155 156
 			ReadonlyPaths: []string{
156 157
 				"/proc/asound",
... ...
@@ -1,5 +1,8 @@
1 1
 package sys
2 2
 
3
+// SetOOMScore sets the oom score for the process
4
+//
5
+// Not implemented on Windows
3 6
 func SetOOMScore(pid, score int) error {
4 7
 	return nil
5 8
 }
6 9
deleted file mode 100644
... ...
@@ -1,19 +0,0 @@
1
-// +build solaris
2
-
3
-package sys
4
-
5
-import (
6
-	"errors"
7
-)
8
-
9
-//Solaris TODO
10
-
11
-// GetSubreaper returns the subreaper setting for the calling process
12
-func GetSubreaper() (int, error) {
13
-	return 0, errors.New("osutils GetSubreaper not implemented on Solaris")
14
-}
15
-
16
-// SetSubreaper sets the value i as the subreaper setting for the calling process
17
-func SetSubreaper(i int) error {
18
-	return errors.New("osutils SetSubreaper not implemented on Solaris")
19
-}
... ...
@@ -6,14 +6,17 @@ import (
6 6
 	"syscall"
7 7
 )
8 8
 
9
+// StatAtime returns the access time from a stat struct
9 10
 func StatAtime(st *syscall.Stat_t) syscall.Timespec {
10 11
 	return st.Atimespec
11 12
 }
12 13
 
14
+// StatCtime returns the created time from a stat struct
13 15
 func StatCtime(st *syscall.Stat_t) syscall.Timespec {
14 16
 	return st.Ctimespec
15 17
 }
16 18
 
19
+// StatMtime returns the modified time from a stat struct
17 20
 func StatMtime(st *syscall.Stat_t) syscall.Timespec {
18 21
 	return st.Mtimespec
19 22
 }
... ...
@@ -6,14 +6,17 @@ import (
6 6
 	"syscall"
7 7
 )
8 8
 
9
+// StatAtime returns the Atim
9 10
 func StatAtime(st *syscall.Stat_t) syscall.Timespec {
10 11
 	return st.Atim
11 12
 }
12 13
 
14
+// StatCtime returns the Ctim
13 15
 func StatCtime(st *syscall.Stat_t) syscall.Timespec {
14 16
 	return st.Ctim
15 17
 }
16 18
 
19
+// StatMtime returns the Mtim
17 20
 func StatMtime(st *syscall.Stat_t) syscall.Timespec {
18 21
 	return st.Mtim
19 22
 }
... ...
@@ -18,7 +18,6 @@ import (
18 18
 	"github.com/containerd/containerd/diff"
19 19
 	"github.com/containerd/containerd/errdefs"
20 20
 	"github.com/containerd/containerd/images"
21
-	"github.com/containerd/containerd/log"
22 21
 	"github.com/containerd/containerd/mount"
23 22
 	"github.com/containerd/containerd/plugin"
24 23
 	"github.com/containerd/containerd/rootfs"
... ...
@@ -26,7 +25,6 @@ import (
26 26
 	google_protobuf "github.com/gogo/protobuf/types"
27 27
 	digest "github.com/opencontainers/go-digest"
28 28
 	"github.com/opencontainers/image-spec/specs-go/v1"
29
-	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
30 29
 	specs "github.com/opencontainers/runtime-spec/specs-go"
31 30
 	"github.com/pkg/errors"
32 31
 )
... ...
@@ -51,6 +49,7 @@ type Status struct {
51 51
 	ExitTime time.Time
52 52
 }
53 53
 
54
+// ProcessInfo provides platform specific process information
54 55
 type ProcessInfo struct {
55 56
 	// Pid is the process ID
56 57
 	Pid uint32
... ...
@@ -358,6 +357,12 @@ func (t *task) Resize(ctx context.Context, w, h uint32) error {
358 358
 }
359 359
 
360 360
 func (t *task) Checkpoint(ctx context.Context, opts ...CheckpointTaskOpts) (Image, error) {
361
+	ctx, done, err := t.client.withLease(ctx)
362
+	if err != nil {
363
+		return nil, err
364
+	}
365
+	defer done()
366
+
361 367
 	request := &tasks.CheckpointTaskRequest{
362 368
 		ContainerID: t.id,
363 369
 	}
... ...
@@ -391,15 +396,6 @@ func (t *task) Checkpoint(ctx context.Context, opts ...CheckpointTaskOpts) (Imag
391 391
 	index := v1.Index{
392 392
 		Annotations: make(map[string]string),
393 393
 	}
394
-	// make sure we clear the gc root labels reguardless of success
395
-	var clearRoots []ocispec.Descriptor
396
-	defer func() {
397
-		for _, r := range append(index.Manifests, clearRoots...) {
398
-			if err := clearRootGCLabel(ctx, t.client, r); err != nil {
399
-				log.G(ctx).WithError(err).WithField("dgst", r.Digest).Warnf("failed to remove root marker")
400
-			}
401
-		}
402
-	}()
403 394
 	if err := t.checkpointTask(ctx, &index, request); err != nil {
404 395
 		return nil, err
405 396
 	}
... ...
@@ -418,7 +414,6 @@ func (t *task) Checkpoint(ctx context.Context, opts ...CheckpointTaskOpts) (Imag
418 418
 	if err != nil {
419 419
 		return nil, err
420 420
 	}
421
-	clearRoots = append(clearRoots, desc)
422 421
 	im := images.Image{
423 422
 		Name:   i.Name,
424 423
 		Target: desc,
... ...
@@ -534,9 +529,6 @@ func (t *task) checkpointTask(ctx context.Context, index *v1.Index, request *tas
534 534
 func (t *task) checkpointRWSnapshot(ctx context.Context, index *v1.Index, snapshotterName string, id string) error {
535 535
 	opts := []diff.Opt{
536 536
 		diff.WithReference(fmt.Sprintf("checkpoint-rw-%s", id)),
537
-		diff.WithLabels(map[string]string{
538
-			"containerd.io/gc.root": time.Now().UTC().Format(time.RFC3339),
539
-		}),
540 537
 	}
541 538
 	rw, err := rootfs.Diff(ctx, id, t.client.SnapshotService(snapshotterName), t.client.DiffService(), opts...)
542 539
 	if err != nil {
... ...
@@ -563,9 +555,7 @@ func (t *task) checkpointImage(ctx context.Context, index *v1.Index, image strin
563 563
 }
564 564
 
565 565
 func (t *task) writeIndex(ctx context.Context, index *v1.Index) (d v1.Descriptor, err error) {
566
-	labels := map[string]string{
567
-		"containerd.io/gc.root": time.Now().UTC().Format(time.RFC3339),
568
-	}
566
+	labels := map[string]string{}
569 567
 	for i, m := range index.Manifests {
570 568
 		labels[fmt.Sprintf("containerd.io/gc.ref.content.%d", i)] = m.Digest.String()
571 569
 	}
... ...
@@ -595,9 +585,3 @@ func writeContent(ctx context.Context, store content.Store, mediaType, ref strin
595 595
 		Size:      size,
596 596
 	}, nil
597 597
 }
598
-
599
-func clearRootGCLabel(ctx context.Context, client *Client, desc ocispec.Descriptor) error {
600
-	info := content.Info{Digest: desc.Digest}
601
-	_, err := client.ContentStore().Update(ctx, info, "labels.containerd.io/gc.root")
602
-	return err
603
-}
... ...
@@ -16,14 +16,14 @@ github.com/docker/go-units v0.3.1
16 16
 github.com/gogo/protobuf d2e1ade2d719b78fe5b061b4c18a9f7111b5bdc8
17 17
 github.com/golang/protobuf 5a0f697c9ed9d68fef0116532c6e05cfeae00e55
18 18
 github.com/opencontainers/runtime-spec v1.0.0
19
-github.com/opencontainers/runc 0351df1c5a66838d0c392b4ac4cf9450de844e2d
19
+github.com/opencontainers/runc 74a17296470088de3805e138d3d87c62e613dfc4
20 20
 github.com/sirupsen/logrus v1.0.0
21 21
 github.com/containerd/btrfs cc52c4dea2ce11a44e6639e561bb5c2af9ada9e3
22 22
 github.com/stretchr/testify v1.1.4
23 23
 github.com/davecgh/go-spew v1.1.0
24 24
 github.com/pmezard/go-difflib v1.0.0
25 25
 github.com/containerd/fifo fbfb6a11ec671efbe94ad1c12c2e98773f19e1e6
26
-github.com/urfave/cli 8ba6f23b6e36d03666a14bd9421f5e3efcb59aca
26
+github.com/urfave/cli 7bc6a0acffa589f415f88aca16cc1de5ffd66f9c
27 27
 golang.org/x/net 7dcfb8076726a3fdd9353b6b8a1f1b6be6811bd6
28 28
 google.golang.org/grpc v1.3.0
29 29
 github.com/pkg/errors v0.8.0
... ...
@@ -1,2 +1,2 @@
1
-// hcsshimtypes holds the windows runtime specific types
1
+// Package hcsshimtypes holds the windows runtime specific types
2 2
 package hcsshimtypes