Refactor differ into separate package

Add differ options and package with interface.
Update optional values on diff interface to use options.

Signed-off-by: Derek McGowan <derek@mcgstyle.net>
This commit is contained in:
Derek McGowan 2017-10-10 12:06:15 -07:00
parent 60960e1c17
commit d9db1d112d
No known key found for this signature in database
GPG Key ID: F58C5D0A4405ACDB
14 changed files with 381 additions and 96 deletions

View File

@ -1120,6 +1120,34 @@ file {
type: TYPE_STRING type: TYPE_STRING
json_name: "ref" json_name: "ref"
} }
field {
name: "labels"
number: 5
label: LABEL_REPEATED
type: TYPE_MESSAGE
type_name: ".containerd.services.diff.v1.DiffRequest.LabelsEntry"
json_name: "labels"
}
nested_type {
name: "LabelsEntry"
field {
name: "key"
number: 1
label: LABEL_OPTIONAL
type: TYPE_STRING
json_name: "key"
}
field {
name: "value"
number: 2
label: LABEL_OPTIONAL
type: TYPE_STRING
json_name: "value"
}
options {
map_entry: true
}
}
} }
message_type { message_type {
name: "DiffResponse" name: "DiffResponse"

View File

@ -30,6 +30,7 @@ import (
import strings "strings" import strings "strings"
import reflect "reflect" import reflect "reflect"
import github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys"
import io "io" import io "io"
@ -78,6 +79,9 @@ type DiffRequest struct {
// Ref identifies the pre-commit content store object. This // Ref identifies the pre-commit content store object. This
// reference can be used to get the status from the content store. // reference can be used to get the status from the content store.
Ref string `protobuf:"bytes,4,opt,name=ref,proto3" json:"ref,omitempty"` Ref string `protobuf:"bytes,4,opt,name=ref,proto3" json:"ref,omitempty"`
// Labels are the labels to apply to the generated content
// on content store commit.
Labels map[string]string `protobuf:"bytes,5,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
} }
func (m *DiffRequest) Reset() { *m = DiffRequest{} } func (m *DiffRequest) Reset() { *m = DiffRequest{} }
@ -334,6 +338,23 @@ func (m *DiffRequest) MarshalTo(dAtA []byte) (int, error) {
i = encodeVarintDiff(dAtA, i, uint64(len(m.Ref))) i = encodeVarintDiff(dAtA, i, uint64(len(m.Ref)))
i += copy(dAtA[i:], m.Ref) i += copy(dAtA[i:], m.Ref)
} }
if len(m.Labels) > 0 {
for k, _ := range m.Labels {
dAtA[i] = 0x2a
i++
v := m.Labels[k]
mapSize := 1 + len(k) + sovDiff(uint64(len(k))) + 1 + len(v) + sovDiff(uint64(len(v)))
i = encodeVarintDiff(dAtA, i, uint64(mapSize))
dAtA[i] = 0xa
i++
i = encodeVarintDiff(dAtA, i, uint64(len(k)))
i += copy(dAtA[i:], k)
dAtA[i] = 0x12
i++
i = encodeVarintDiff(dAtA, i, uint64(len(v)))
i += copy(dAtA[i:], v)
}
}
return i, nil return i, nil
} }
@ -441,6 +462,14 @@ func (m *DiffRequest) Size() (n int) {
if l > 0 { if l > 0 {
n += 1 + l + sovDiff(uint64(l)) n += 1 + l + sovDiff(uint64(l))
} }
if len(m.Labels) > 0 {
for k, v := range m.Labels {
_ = k
_ = v
mapEntrySize := 1 + len(k) + sovDiff(uint64(len(k))) + 1 + len(v) + sovDiff(uint64(len(v)))
n += mapEntrySize + 1 + sovDiff(uint64(mapEntrySize))
}
}
return n return n
} }
@ -492,11 +521,22 @@ func (this *DiffRequest) String() string {
if this == nil { if this == nil {
return "nil" return "nil"
} }
keysForLabels := make([]string, 0, len(this.Labels))
for k, _ := range this.Labels {
keysForLabels = append(keysForLabels, k)
}
github_com_gogo_protobuf_sortkeys.Strings(keysForLabels)
mapStringForLabels := "map[string]string{"
for _, k := range keysForLabels {
mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k])
}
mapStringForLabels += "}"
s := strings.Join([]string{`&DiffRequest{`, s := strings.Join([]string{`&DiffRequest{`,
`Left:` + strings.Replace(fmt.Sprintf("%v", this.Left), "Mount", "containerd_types.Mount", 1) + `,`, `Left:` + strings.Replace(fmt.Sprintf("%v", this.Left), "Mount", "containerd_types.Mount", 1) + `,`,
`Right:` + strings.Replace(fmt.Sprintf("%v", this.Right), "Mount", "containerd_types.Mount", 1) + `,`, `Right:` + strings.Replace(fmt.Sprintf("%v", this.Right), "Mount", "containerd_types.Mount", 1) + `,`,
`MediaType:` + fmt.Sprintf("%v", this.MediaType) + `,`, `MediaType:` + fmt.Sprintf("%v", this.MediaType) + `,`,
`Ref:` + fmt.Sprintf("%v", this.Ref) + `,`, `Ref:` + fmt.Sprintf("%v", this.Ref) + `,`,
`Labels:` + mapStringForLabels + `,`,
`}`, `}`,
}, "") }, "")
return s return s
@ -865,6 +905,122 @@ func (m *DiffRequest) Unmarshal(dAtA []byte) error {
} }
m.Ref = string(dAtA[iNdEx:postIndex]) m.Ref = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex iNdEx = postIndex
case 5:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowDiff
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthDiff
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
var keykey uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowDiff
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
keykey |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
var stringLenmapkey uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowDiff
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLenmapkey |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLenmapkey := int(stringLenmapkey)
if intStringLenmapkey < 0 {
return ErrInvalidLengthDiff
}
postStringIndexmapkey := iNdEx + intStringLenmapkey
if postStringIndexmapkey > l {
return io.ErrUnexpectedEOF
}
mapkey := string(dAtA[iNdEx:postStringIndexmapkey])
iNdEx = postStringIndexmapkey
if m.Labels == nil {
m.Labels = make(map[string]string)
}
if iNdEx < postIndex {
var valuekey uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowDiff
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
valuekey |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
var stringLenmapvalue uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowDiff
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLenmapvalue |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLenmapvalue := int(stringLenmapvalue)
if intStringLenmapvalue < 0 {
return ErrInvalidLengthDiff
}
postStringIndexmapvalue := iNdEx + intStringLenmapvalue
if postStringIndexmapvalue > l {
return io.ErrUnexpectedEOF
}
mapvalue := string(dAtA[iNdEx:postStringIndexmapvalue])
iNdEx = postStringIndexmapvalue
m.Labels[mapkey] = mapvalue
} else {
var mapvalue string
m.Labels[mapkey] = mapvalue
}
iNdEx = postIndex
default: default:
iNdEx = preIndex iNdEx = preIndex
skippy, err := skipDiff(dAtA[iNdEx:]) skippy, err := skipDiff(dAtA[iNdEx:])
@ -1079,31 +1235,34 @@ func init() {
} }
var fileDescriptorDiff = []byte{ var fileDescriptorDiff = []byte{
// 401 bytes of a gzipped FileDescriptorProto // 454 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x93, 0x41, 0x8b, 0xda, 0x40, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x53, 0x4f, 0x6f, 0xd3, 0x30,
0x14, 0xc7, 0x9d, 0x26, 0x5a, 0x1c, 0x2d, 0x94, 0xa1, 0xd0, 0x90, 0xb6, 0x41, 0x72, 0x8a, 0x2d, 0x14, 0x9f, 0xfb, 0x0f, 0xf5, 0x75, 0x48, 0xc8, 0x9a, 0x44, 0x14, 0x20, 0xaa, 0x7a, 0xea, 0x40,
0x9d, 0x54, 0x0b, 0x1e, 0xea, 0xc5, 0x16, 0xa1, 0xa7, 0x5e, 0x82, 0xa7, 0x16, 0x5a, 0x62, 0x32, 0x38, 0xac, 0xa0, 0x09, 0xb6, 0xcb, 0x40, 0x43, 0x5c, 0xc6, 0x25, 0xda, 0x09, 0x24, 0x50, 0xda,
0x89, 0x03, 0x9a, 0x19, 0x33, 0xa3, 0xe0, 0xad, 0x9f, 0x63, 0xbf, 0xce, 0x5e, 0x3c, 0xee, 0x71, 0xbc, 0x74, 0x16, 0x69, 0xec, 0xd9, 0x6e, 0xa5, 0xdc, 0xf8, 0x2e, 0x7c, 0x14, 0x2e, 0x3b, 0x72,
0x8f, 0x6b, 0x3e, 0xc9, 0x92, 0x49, 0xb2, 0x1b, 0x58, 0x70, 0xb3, 0x7b, 0x9a, 0xc7, 0xbc, 0xdf, 0xe4, 0x48, 0xfb, 0x49, 0x90, 0x9d, 0x14, 0x22, 0x21, 0x95, 0xc0, 0x29, 0x2f, 0xcf, 0xbf, 0x7f,
0xff, 0xbd, 0xff, 0xbc, 0xbc, 0xc0, 0x59, 0x4c, 0xe5, 0x6a, 0xb7, 0xc4, 0x01, 0xdb, 0xb8, 0x01, 0xf6, 0xb3, 0xe1, 0x6c, 0xce, 0xcd, 0xd5, 0x72, 0xca, 0x66, 0x62, 0x11, 0xce, 0x44, 0x6e, 0x62,
0x4b, 0xa4, 0x4f, 0x13, 0x92, 0x86, 0xf5, 0xd0, 0xe7, 0xd4, 0x15, 0x24, 0xdd, 0xd3, 0x80, 0x08, 0x9e, 0xa3, 0x4a, 0xea, 0x65, 0x2c, 0x79, 0xa8, 0x51, 0xad, 0xf8, 0x0c, 0x75, 0x98, 0xf0, 0x34,
0x37, 0xa4, 0x51, 0xe4, 0xee, 0x47, 0xea, 0xc4, 0x3c, 0x65, 0x92, 0xa1, 0x77, 0xf7, 0x2c, 0xae, 0x0d, 0x57, 0x47, 0xee, 0xcb, 0xa4, 0x12, 0x46, 0xd0, 0x7b, 0xbf, 0xb1, 0x6c, 0x8b, 0x63, 0x6e,
0x38, 0xac, 0xf2, 0xfb, 0x91, 0xf9, 0x26, 0x66, 0x31, 0x53, 0x9c, 0x9b, 0x47, 0x85, 0xc4, 0x9c, 0x7d, 0x75, 0xe4, 0x1f, 0xcc, 0xc5, 0x5c, 0x38, 0x5c, 0x68, 0xab, 0x92, 0xe2, 0x1f, 0x37, 0x32,
0x34, 0x6a, 0x2a, 0x0f, 0x9c, 0x08, 0x77, 0xc3, 0x76, 0x89, 0x2c, 0x75, 0xd3, 0x27, 0xe8, 0x42, 0x35, 0x85, 0x44, 0x1d, 0x2e, 0xc4, 0x32, 0x37, 0x15, 0xef, 0xf4, 0x1f, 0x78, 0x09, 0xea, 0x99,
0x22, 0x82, 0x94, 0x72, 0xc9, 0xd2, 0x42, 0x6c, 0x6f, 0x61, 0xff, 0x3b, 0xe7, 0xeb, 0x83, 0x47, 0xe2, 0xd2, 0x08, 0x55, 0x92, 0x47, 0xd7, 0xb0, 0xff, 0x52, 0xca, 0xac, 0x88, 0xf0, 0x7a, 0x89,
0xb6, 0x3b, 0x22, 0x24, 0xfa, 0x02, 0xf5, 0xdc, 0xa5, 0x01, 0x06, 0xc0, 0xe9, 0x8d, 0xdf, 0xe3, 0xda, 0xd0, 0x27, 0xd0, 0xb1, 0x29, 0x3d, 0x32, 0x24, 0xe3, 0xc1, 0xe4, 0x3e, 0xab, 0x6d, 0xc3,
0xda, 0x33, 0x54, 0x05, 0x3c, 0xbf, 0xab, 0xe0, 0x29, 0x12, 0xb9, 0xb0, 0xa3, 0xdc, 0x08, 0xe3, 0x29, 0xb0, 0xf3, 0x5f, 0x0a, 0x91, 0x43, 0xd2, 0x10, 0x7a, 0x2e, 0x8d, 0xf6, 0x5a, 0xc3, 0xf6,
0xc5, 0x40, 0x73, 0x7a, 0xe3, 0xb7, 0x0f, 0x35, 0xbf, 0xf2, 0xbc, 0x57, 0x62, 0xf6, 0x4f, 0xf8, 0x78, 0x30, 0xb9, 0xfb, 0x27, 0xe7, 0xad, 0x5d, 0x8f, 0x2a, 0xd8, 0xe8, 0x0d, 0xdc, 0xae, 0x2c,
0xaa, 0x6c, 0x29, 0x38, 0x4b, 0x04, 0x41, 0x13, 0xf8, 0xd2, 0xe7, 0x7c, 0x4d, 0x49, 0xd8, 0xa8, 0xb5, 0x14, 0xb9, 0x46, 0x7a, 0x0c, 0xb7, 0x62, 0x29, 0x33, 0x8e, 0x49, 0x23, 0xdb, 0x2d, 0x78,
0x6d, 0x05, 0xdb, 0x17, 0x00, 0xf6, 0xe6, 0x34, 0x8a, 0x2a, 0xef, 0x9f, 0xa0, 0xbe, 0x26, 0x91, 0xf4, 0xa5, 0x05, 0x83, 0x73, 0x9e, 0xa6, 0xdb, 0xec, 0x8f, 0xa0, 0x93, 0x61, 0x6a, 0x3c, 0xb2,
0x34, 0xc0, 0x79, 0x1f, 0x0a, 0x42, 0x9f, 0x61, 0x3b, 0xa5, 0xf1, 0x4a, 0x3e, 0xe6, 0xba, 0xa0, 0x3b, 0x87, 0x03, 0xd1, 0xc7, 0xd0, 0x55, 0x7c, 0x7e, 0x65, 0xfe, 0x96, 0xba, 0x44, 0xd1, 0x07,
0xd0, 0x07, 0x08, 0x37, 0x24, 0xa4, 0xfe, 0xbf, 0x3c, 0x67, 0x68, 0x03, 0xe0, 0x74, 0xbd, 0xae, 0x00, 0x0b, 0x4c, 0x78, 0xfc, 0xd1, 0xae, 0x79, 0xed, 0x21, 0x19, 0xf7, 0xa3, 0xbe, 0xeb, 0x5c,
0xba, 0x59, 0x1c, 0x38, 0x41, 0xaf, 0xa1, 0x96, 0x92, 0xc8, 0xd0, 0xd5, 0x7d, 0x1e, 0xda, 0x33, 0x16, 0x12, 0xe9, 0x1d, 0x68, 0x2b, 0x4c, 0xbd, 0x8e, 0xeb, 0xdb, 0x92, 0x5e, 0x40, 0x2f, 0x8b,
0xd8, 0x2f, 0xbc, 0x95, 0x8f, 0xac, 0x06, 0xab, 0x35, 0x1d, 0xec, 0xf8, 0x12, 0x40, 0x3d, 0x2f, 0xa7, 0x98, 0x69, 0xaf, 0xeb, 0x0c, 0x9e, 0xb1, 0x1d, 0x37, 0x82, 0xd5, 0xb6, 0xc1, 0x2e, 0x1c,
0x81, 0xfe, 0xc2, 0xb6, 0x1a, 0x18, 0x1a, 0xe2, 0x33, 0x5b, 0x85, 0xeb, 0xdf, 0xd1, 0xfc, 0xd8, 0xed, 0x75, 0x6e, 0x54, 0x11, 0x55, 0x1a, 0xfe, 0x0b, 0x18, 0xd4, 0xda, 0xd6, 0xee, 0x13, 0x16,
0x04, 0x2d, 0xad, 0xfd, 0x29, 0xfb, 0x38, 0x67, 0x35, 0xb5, 0x49, 0x9b, 0xc3, 0x06, 0x64, 0x51, 0xee, 0xb4, 0xfa, 0x91, 0x2d, 0xe9, 0x01, 0x74, 0x57, 0x71, 0xb6, 0x44, 0xaf, 0xe5, 0x7a, 0xe5,
0xfc, 0xc7, 0xe2, 0x78, 0xb2, 0x5a, 0xd7, 0x27, 0xab, 0xf5, 0x3f, 0xb3, 0xc0, 0x31, 0xb3, 0xc0, 0xcf, 0x49, 0xeb, 0x39, 0x19, 0x9d, 0xc1, 0x7e, 0xa9, 0x5e, 0x9d, 0xf6, 0x76, 0xc2, 0xed, 0xa6,
0x55, 0x66, 0x81, 0x9b, 0xcc, 0x02, 0xbf, 0xbf, 0x3d, 0xeb, 0x27, 0x9b, 0xe6, 0xe7, 0xb2, 0xa3, 0x13, 0x9e, 0x7c, 0x25, 0xd0, 0xb1, 0x12, 0xf4, 0x03, 0x74, 0xdd, 0xe4, 0xe8, 0xe1, 0xce, 0xcd,
0xb6, 0xf7, 0xeb, 0x6d, 0x00, 0x00, 0x00, 0xff, 0xff, 0x6e, 0x16, 0x1d, 0x04, 0xa9, 0x03, 0x00, 0xd4, 0x2f, 0x94, 0xff, 0xb0, 0x09, 0xb4, 0x8a, 0xf6, 0xbe, 0xf2, 0x19, 0x37, 0x3d, 0x2b, 0xff,
0x00, 0xb0, 0x01, 0xb2, 0x14, 0x7f, 0x75, 0x79, 0xb3, 0x0e, 0xf6, 0xbe, 0xaf, 0x83, 0xbd, 0xcf, 0x9b,
0x80, 0xdc, 0x6c, 0x02, 0xf2, 0x6d, 0x13, 0x90, 0x1f, 0x9b, 0x80, 0xbc, 0x3b, 0xf9, 0xaf, 0xd7,
0x7e, 0x6a, 0xbf, 0xd3, 0x9e, 0x7b, 0x46, 0x4f, 0x7f, 0x06, 0x00, 0x00, 0xff, 0xff, 0xd6, 0x01,
0x51, 0xf0, 0x32, 0x04, 0x00, 0x00,
} }

View File

@ -50,6 +50,10 @@ message DiffRequest {
// Ref identifies the pre-commit content store object. This // Ref identifies the pre-commit content store object. This
// reference can be used to get the status from the content store. // reference can be used to get the status from the content store.
string ref = 4; string ref = 4;
// Labels are the labels to apply to the generated content
// on content store commit.
map<string, string> labels = 5;
} }
message DiffResponse { message DiffResponse {

View File

@ -22,6 +22,7 @@ import (
versionservice "github.com/containerd/containerd/api/services/version/v1" versionservice "github.com/containerd/containerd/api/services/version/v1"
"github.com/containerd/containerd/containers" "github.com/containerd/containerd/containers"
"github.com/containerd/containerd/content" "github.com/containerd/containerd/content"
"github.com/containerd/containerd/diff"
"github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/images" "github.com/containerd/containerd/images"
"github.com/containerd/containerd/platforms" "github.com/containerd/containerd/platforms"
@ -31,7 +32,6 @@ import (
"github.com/containerd/containerd/remotes/docker" "github.com/containerd/containerd/remotes/docker"
"github.com/containerd/containerd/remotes/docker/schema1" "github.com/containerd/containerd/remotes/docker/schema1"
contentservice "github.com/containerd/containerd/services/content" contentservice "github.com/containerd/containerd/services/content"
"github.com/containerd/containerd/services/diff"
diffservice "github.com/containerd/containerd/services/diff" diffservice "github.com/containerd/containerd/services/diff"
imagesservice "github.com/containerd/containerd/services/images" imagesservice "github.com/containerd/containerd/services/images"
snapshotservice "github.com/containerd/containerd/services/snapshot" snapshotservice "github.com/containerd/containerd/services/snapshot"
@ -439,8 +439,8 @@ func (c *Client) ImageService() images.Store {
return imagesservice.NewStoreFromClient(imagesapi.NewImagesClient(c.conn)) return imagesservice.NewStoreFromClient(imagesapi.NewImagesClient(c.conn))
} }
// DiffService returns the underlying DiffService // DiffService returns the underlying Differ
func (c *Client) DiffService() diff.DiffService { func (c *Client) DiffService() diff.Differ {
return diffservice.NewDiffServiceFromClient(diffapi.NewDiffClient(c.conn)) return diffservice.NewDiffServiceFromClient(diffapi.NewDiffClient(c.conn))
} }

View File

@ -2,7 +2,7 @@ package main
// register containerd builtins here // register containerd builtins here
import ( import (
_ "github.com/containerd/containerd/differ" _ "github.com/containerd/containerd/diff/walking"
_ "github.com/containerd/containerd/services/containers" _ "github.com/containerd/containerd/services/containers"
_ "github.com/containerd/containerd/services/content" _ "github.com/containerd/containerd/services/content"
_ "github.com/containerd/containerd/services/diff" _ "github.com/containerd/containerd/services/diff"

View File

@ -28,6 +28,7 @@ import (
"github.com/containerd/containerd/api/services/tasks/v1" "github.com/containerd/containerd/api/services/tasks/v1"
versionservice "github.com/containerd/containerd/api/services/version/v1" versionservice "github.com/containerd/containerd/api/services/version/v1"
"github.com/containerd/containerd/content" "github.com/containerd/containerd/content"
"github.com/containerd/containerd/diff"
"github.com/containerd/containerd/images" "github.com/containerd/containerd/images"
"github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/platforms" "github.com/containerd/containerd/platforms"
@ -35,7 +36,7 @@ import (
"github.com/containerd/containerd/remotes/docker" "github.com/containerd/containerd/remotes/docker"
"github.com/containerd/containerd/rootfs" "github.com/containerd/containerd/rootfs"
contentservice "github.com/containerd/containerd/services/content" contentservice "github.com/containerd/containerd/services/content"
"github.com/containerd/containerd/services/diff" diffservice "github.com/containerd/containerd/services/diff"
imagesservice "github.com/containerd/containerd/services/images" imagesservice "github.com/containerd/containerd/services/images"
namespacesservice "github.com/containerd/containerd/services/namespaces" namespacesservice "github.com/containerd/containerd/services/namespaces"
snapshotservice "github.com/containerd/containerd/services/snapshot" snapshotservice "github.com/containerd/containerd/services/snapshot"
@ -169,12 +170,12 @@ func getImageStore(clicontext *cli.Context) (images.Store, error) {
return imagesservice.NewStoreFromClient(imagesapi.NewImagesClient(conn)), nil return imagesservice.NewStoreFromClient(imagesapi.NewImagesClient(conn)), nil
} }
func getDiffService(context *cli.Context) (diff.DiffService, error) { func getDiffService(context *cli.Context) (diff.Differ, error) {
conn, err := getGRPCConnection(context) conn, err := getGRPCConnection(context)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return diff.NewDiffServiceFromClient(diffapi.NewDiffClient(conn)), nil return diffservice.NewDiffServiceFromClient(diffapi.NewDiffClient(conn)), nil
} }
func getVersionService(context *cli.Context) (versionservice.VersionClient, error) { func getVersionService(context *cli.Context) (versionservice.VersionClient, error) {

69
diff/diff.go Normal file
View File

@ -0,0 +1,69 @@
package diff
import (
"github.com/containerd/containerd/mount"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"golang.org/x/net/context"
)
// Config is used to hold parameters needed for a diff operation
type Config struct {
// MediaType is the type of diff to generate
// Default depends on the differ,
// i.e. application/vnd.oci.image.layer.v1.tar+gzip
MediaType string
// Reference is the content upload reference
// Default will use a random reference string
Reference string
// Labels are the labels to apply to the generated content
Labels map[string]string
}
// Opt is used to configure a diff operation
type Opt func(*Config) error
// Differ allows the apply and creation of filesystem diffs between mounts
type Differ interface {
// Apply applies the content referred to by the given descriptor to
// the provided mount. The method of applying is based on the
// implementation and content descriptor. For example, in the common
// case the descriptor is a file system difference in tar format,
// that tar would be applied on top of the mounts.
Apply(ctx context.Context, desc ocispec.Descriptor, mount []mount.Mount) (ocispec.Descriptor, error)
// DiffMounts computes the difference between two mounts and returns a
// descriptor for the computed diff. The options can provide
// a ref which can be used to track the content creation of the diff.
// The media type which is used to determine the format of the created
// content can also be provided as an option.
DiffMounts(ctx context.Context, lower, upper []mount.Mount, opts ...Opt) (ocispec.Descriptor, error)
}
// WithMediaType sets the media type to use for creating the diff, without
// specifying the differ will choose a default.
func WithMediaType(m string) Opt {
return func(c *Config) error {
c.MediaType = m
return nil
}
}
// WithReference is used to set the content upload reference used by
// the diff operation. This allows the caller to track the upload through
// the content store.
func WithReference(ref string) Opt {
return func(c *Config) error {
c.Reference = ref
return nil
}
}
// WithLabels is used to set content labels on the created diff content.
func WithLabels(labels map[string]string) Opt {
return func(c *Config) error {
c.Labels = labels
return nil
}
}

View File

@ -1,14 +1,19 @@
package differ package walking
import ( import (
"crypto/rand"
"encoding/base64"
"fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
"strings" "strings"
"time"
"github.com/containerd/containerd/archive" "github.com/containerd/containerd/archive"
"github.com/containerd/containerd/archive/compression" "github.com/containerd/containerd/archive/compression"
"github.com/containerd/containerd/content" "github.com/containerd/containerd/content"
"github.com/containerd/containerd/diff"
"github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/images" "github.com/containerd/containerd/images"
"github.com/containerd/containerd/metadata" "github.com/containerd/containerd/metadata"
@ -46,9 +51,9 @@ type walkingDiff struct {
var emptyDesc = ocispec.Descriptor{} var emptyDesc = ocispec.Descriptor{}
// NewWalkingDiff is a generic implementation of plugin.Differ. // NewWalkingDiff is a generic implementation of diff.Differ.
// NewWalkingDiff is expected to work with any filesystem. // NewWalkingDiff is expected to work with any filesystem.
func NewWalkingDiff(store content.Store) (plugin.Differ, error) { func NewWalkingDiff(store content.Store) (diff.Differ, error) {
return &walkingDiff{ return &walkingDiff{
store: store, store: store,
}, nil }, nil
@ -122,17 +127,25 @@ func (s *walkingDiff) Apply(ctx context.Context, desc ocispec.Descriptor, mounts
// DiffMounts creates a diff between the given mounts and uploads the result // DiffMounts creates a diff between the given mounts and uploads the result
// to the content store. // to the content store.
func (s *walkingDiff) DiffMounts(ctx context.Context, lower, upper []mount.Mount, media, ref string) (ocispec.Descriptor, error) { func (s *walkingDiff) DiffMounts(ctx context.Context, lower, upper []mount.Mount, opts ...diff.Opt) (ocispec.Descriptor, error) {
var config diff.Config
for _, opt := range opts {
if err := opt(&config); err != nil {
return emptyDesc, err
}
}
if config.MediaType == "" {
config.MediaType = ocispec.MediaTypeImageLayerGzip
}
var isCompressed bool var isCompressed bool
switch media { switch config.MediaType {
case ocispec.MediaTypeImageLayer: case ocispec.MediaTypeImageLayer:
case ocispec.MediaTypeImageLayerGzip: case ocispec.MediaTypeImageLayerGzip:
isCompressed = true isCompressed = true
case "":
media = ocispec.MediaTypeImageLayerGzip
isCompressed = true
default: default:
return emptyDesc, errors.Wrapf(errdefs.ErrNotImplemented, "unsupported diff media type: %v", media) return emptyDesc, errors.Wrapf(errdefs.ErrNotImplemented, "unsupported diff media type: %v", config.MediaType)
} }
aDir, err := ioutil.TempDir("", "left-") aDir, err := ioutil.TempDir("", "left-")
if err != nil { if err != nil {
@ -156,34 +169,47 @@ func (s *walkingDiff) DiffMounts(ctx context.Context, lower, upper []mount.Mount
} }
defer mount.Unmount(bDir, 0) defer mount.Unmount(bDir, 0)
cw, err := s.store.Writer(ctx, ref, 0, "") if config.Reference == "" {
config.Reference = uniqueRef()
}
cw, err := s.store.Writer(ctx, config.Reference, 0, "")
if err != nil { if err != nil {
return emptyDesc, errors.Wrap(err, "failed to open writer") return emptyDesc, errors.Wrap(err, "failed to open writer")
} }
var opts []content.Opt
if isCompressed { if isCompressed {
dgstr := digest.SHA256.Digester() dgstr := digest.SHA256.Digester()
compressed, err := compression.CompressStream(cw, compression.Gzip) compressed, err := compression.CompressStream(cw, compression.Gzip)
if err != nil { if err != nil {
cw.Close()
return emptyDesc, errors.Wrap(err, "failed to get compressed stream") return emptyDesc, errors.Wrap(err, "failed to get compressed stream")
} }
err = archive.WriteDiff(ctx, io.MultiWriter(compressed, dgstr.Hash()), aDir, bDir) err = archive.WriteDiff(ctx, io.MultiWriter(compressed, dgstr.Hash()), aDir, bDir)
compressed.Close() compressed.Close()
if err != nil { if err != nil {
cw.Close()
return emptyDesc, errors.Wrap(err, "failed to write compressed diff") return emptyDesc, errors.Wrap(err, "failed to write compressed diff")
} }
opts = append(opts, content.WithLabels(map[string]string{
"containerd.io/uncompressed": dgstr.Digest().String(), if config.Labels == nil {
})) config.Labels = map[string]string{}
}
config.Labels["containerd.io/uncompressed"] = dgstr.Digest().String()
} else { } else {
if err = archive.WriteDiff(ctx, cw, aDir, bDir); err != nil { if err = archive.WriteDiff(ctx, cw, aDir, bDir); err != nil {
cw.Close()
return emptyDesc, errors.Wrap(err, "failed to write diff") return emptyDesc, errors.Wrap(err, "failed to write diff")
} }
} }
var commitopts []content.Opt
if config.Labels != nil {
commitopts = append(commitopts, content.WithLabels(config.Labels))
}
dgst := cw.Digest() dgst := cw.Digest()
if err := cw.Commit(ctx, 0, dgst, opts...); err != nil { if err := cw.Commit(ctx, 0, dgst, commitopts...); err != nil {
return emptyDesc, errors.Wrap(err, "failed to commit") return emptyDesc, errors.Wrap(err, "failed to commit")
} }
@ -193,7 +219,7 @@ func (s *walkingDiff) DiffMounts(ctx context.Context, lower, upper []mount.Mount
} }
return ocispec.Descriptor{ return ocispec.Descriptor{
MediaType: media, MediaType: config.MediaType,
Size: info.Size, Size: info.Size,
Digest: info.Digest, Digest: info.Digest,
}, nil }, nil
@ -209,3 +235,11 @@ func (rc *readCounter) Read(p []byte) (n int, err error) {
rc.c += int64(n) rc.c += int64(n)
return return
} }
func uniqueRef() string {
t := time.Now()
var b [3]byte
// Ignore read failures, just decreases uniqueness
rand.Read(b[:])
return fmt.Sprintf("%d-%s", t.UnixNano(), base64.URLEncoding.EncodeToString(b[:]))
}

View File

@ -1,13 +0,0 @@
package plugin
import (
"github.com/containerd/containerd/mount"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"golang.org/x/net/context"
)
// Differ allows the apply and creation of filesystem diffs between mounts
type Differ interface {
Apply(ctx context.Context, desc ocispec.Descriptor, mount []mount.Mount) (ocispec.Descriptor, error)
DiffMounts(ctx context.Context, lower, upper []mount.Mount, media, ref string) (ocispec.Descriptor, error)
}

View File

@ -6,9 +6,9 @@ import (
"fmt" "fmt"
"time" "time"
"github.com/containerd/containerd/diff"
"github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/log" "github.com/containerd/containerd/log"
"github.com/containerd/containerd/mount"
"github.com/containerd/containerd/snapshot" "github.com/containerd/containerd/snapshot"
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
"github.com/opencontainers/image-spec/identity" "github.com/opencontainers/image-spec/identity"
@ -17,11 +17,6 @@ import (
"golang.org/x/net/context" "golang.org/x/net/context"
) )
// Applier is used to apply a descriptor of a layer diff on top of mounts.
type Applier interface {
Apply(context.Context, ocispec.Descriptor, []mount.Mount) (ocispec.Descriptor, error)
}
// Layer represents the descriptors for a layer diff. These descriptions // Layer represents the descriptors for a layer diff. These descriptions
// include the descriptor for the uncompressed tar diff as well as a blob // include the descriptor for the uncompressed tar diff as well as a blob
// used to transport that tar. The blob descriptor may or may not describe // used to transport that tar. The blob descriptor may or may not describe
@ -35,7 +30,7 @@ type Layer struct {
// The returned result is a chain id digest representing all the applied layers. // The returned result is a chain id digest representing all the applied layers.
// Layers are applied in order they are given, making the first layer the // Layers are applied in order they are given, making the first layer the
// bottom-most layer in the layer chain. // bottom-most layer in the layer chain.
func ApplyLayers(ctx context.Context, layers []Layer, sn snapshot.Snapshotter, a Applier) (digest.Digest, error) { func ApplyLayers(ctx context.Context, layers []Layer, sn snapshot.Snapshotter, a diff.Differ) (digest.Digest, error) {
var chain []digest.Digest var chain []digest.Digest
for _, layer := range layers { for _, layer := range layers {
if _, err := ApplyLayer(ctx, layer, chain, sn, a); err != nil { if _, err := ApplyLayer(ctx, layer, chain, sn, a); err != nil {
@ -51,7 +46,7 @@ func ApplyLayers(ctx context.Context, layers []Layer, sn snapshot.Snapshotter, a
// ApplyLayer applies a single layer on top of the given provided layer chain, // ApplyLayer applies a single layer on top of the given provided layer chain,
// using the provided snapshotter and applier. If the layer was unpacked true // using the provided snapshotter and applier. If the layer was unpacked true
// is returned, if the layer already exists false is returned. // is returned, if the layer already exists false is returned.
func ApplyLayer(ctx context.Context, layer Layer, chain []digest.Digest, sn snapshot.Snapshotter, a Applier) (bool, error) { func ApplyLayer(ctx context.Context, layer Layer, chain []digest.Digest, sn snapshot.Snapshotter, a diff.Differ, opts ...snapshot.Opt) (bool, error) {
var ( var (
parent = identity.ChainID(chain) parent = identity.ChainID(chain)
chainID = identity.ChainID(append(chain, layer.Diff.Digest)) chainID = identity.ChainID(append(chain, layer.Diff.Digest))

View File

@ -3,25 +3,18 @@ package rootfs
import ( import (
"fmt" "fmt"
"github.com/containerd/containerd/diff"
"github.com/containerd/containerd/mount" "github.com/containerd/containerd/mount"
"github.com/containerd/containerd/snapshot" "github.com/containerd/containerd/snapshot"
ocispec "github.com/opencontainers/image-spec/specs-go/v1" ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"golang.org/x/net/context" "golang.org/x/net/context"
) )
// MountDiffer computes the difference between two mounts and returns a
// descriptor for the computed diff. The provided ref can be used to track
// the content creation of the diff and media type is used to determine the
// format of the created content.
type MountDiffer interface {
DiffMounts(ctx context.Context, lower, upper []mount.Mount, media, ref string) (ocispec.Descriptor, error)
}
// Diff creates a layer diff for the given snapshot identifier from the parent // Diff creates a layer diff for the given snapshot identifier from the parent
// of the snapshot. A content ref is provided to track the progress of the // of the snapshot. A content ref is provided to track the progress of the
// content creation and the provided snapshotter and mount differ are used // content creation and the provided snapshotter and mount differ are used
// for calculating the diff. The descriptor for the layer diff is returned. // for calculating the diff. The descriptor for the layer diff is returned.
func Diff(ctx context.Context, snapshotID, contentRef string, sn snapshot.Snapshotter, md MountDiffer) (ocispec.Descriptor, error) { func Diff(ctx context.Context, snapshotID string, sn snapshot.Snapshotter, d diff.Differ, opts ...diff.Opt) (ocispec.Descriptor, error) {
info, err := sn.Stat(ctx, snapshotID) info, err := sn.Stat(ctx, snapshotID)
if err != nil { if err != nil {
return ocispec.Descriptor{}, err return ocispec.Descriptor{}, err
@ -49,5 +42,5 @@ func Diff(ctx context.Context, snapshotID, contentRef string, sn snapshot.Snapsh
defer sn.Remove(ctx, lowerKey) defer sn.Remove(ctx, lowerKey)
} }
return md.DiffMounts(ctx, lower, upper, ocispec.MediaTypeImageLayerGzip, contentRef) return d.DiffMounts(ctx, lower, upper, opts...)
} }

View File

@ -3,20 +3,15 @@ package diff
import ( import (
diffapi "github.com/containerd/containerd/api/services/diff/v1" diffapi "github.com/containerd/containerd/api/services/diff/v1"
"github.com/containerd/containerd/api/types" "github.com/containerd/containerd/api/types"
"github.com/containerd/containerd/diff"
"github.com/containerd/containerd/mount" "github.com/containerd/containerd/mount"
"github.com/containerd/containerd/rootfs"
ocispec "github.com/opencontainers/image-spec/specs-go/v1" ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"golang.org/x/net/context" "golang.org/x/net/context"
) )
type DiffService interface {
rootfs.Applier
rootfs.MountDiffer
}
// NewApplierFromClient returns a new Applier which communicates // NewApplierFromClient returns a new Applier which communicates
// over a GRPC connection. // over a GRPC connection.
func NewDiffServiceFromClient(client diffapi.DiffClient) DiffService { func NewDiffServiceFromClient(client diffapi.DiffClient) diff.Differ {
return &remote{ return &remote{
client: client, client: client,
} }
@ -38,12 +33,19 @@ func (r *remote) Apply(ctx context.Context, diff ocispec.Descriptor, mounts []mo
return toDescriptor(resp.Applied), nil return toDescriptor(resp.Applied), nil
} }
func (r *remote) DiffMounts(ctx context.Context, a, b []mount.Mount, media, ref string) (ocispec.Descriptor, error) { func (r *remote) DiffMounts(ctx context.Context, a, b []mount.Mount, opts ...diff.Opt) (ocispec.Descriptor, error) {
var config diff.Config
for _, opt := range opts {
if err := opt(&config); err != nil {
return ocispec.Descriptor{}, err
}
}
req := &diffapi.DiffRequest{ req := &diffapi.DiffRequest{
Left: fromMounts(a), Left: fromMounts(a),
Right: fromMounts(b), Right: fromMounts(b),
MediaType: media, MediaType: config.MediaType,
Ref: ref, Ref: config.Reference,
Labels: config.Labels,
} }
resp, err := r.client.Diff(ctx, req) resp, err := r.client.Diff(ctx, req)
if err != nil { if err != nil {

View File

@ -3,6 +3,7 @@ package diff
import ( import (
diffapi "github.com/containerd/containerd/api/services/diff/v1" diffapi "github.com/containerd/containerd/api/services/diff/v1"
"github.com/containerd/containerd/api/types" "github.com/containerd/containerd/api/types"
"github.com/containerd/containerd/diff"
"github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/mount" "github.com/containerd/containerd/mount"
"github.com/containerd/containerd/plugin" "github.com/containerd/containerd/plugin"
@ -39,7 +40,7 @@ func init() {
} }
orderedNames := ic.Config.(*config).Order orderedNames := ic.Config.(*config).Order
ordered := make([]plugin.Differ, len(orderedNames)) ordered := make([]diff.Differ, len(orderedNames))
for i, n := range orderedNames { for i, n := range orderedNames {
differp, ok := differs[n] differp, ok := differs[n]
if !ok { if !ok {
@ -50,7 +51,7 @@ func init() {
return nil, errors.Wrapf(err, "could not load required differ due plugin init error: %s", n) return nil, errors.Wrapf(err, "could not load required differ due plugin init error: %s", n)
} }
ordered[i] = differ.(plugin.Differ) ordered[i] = differ.(diff.Differ)
} }
return &service{ return &service{
@ -61,7 +62,7 @@ func init() {
} }
type service struct { type service struct {
differs []plugin.Differ differs []diff.Differ
} }
func (s *service) Register(gs *grpc.Server) error { func (s *service) Register(gs *grpc.Server) error {
@ -102,8 +103,19 @@ func (s *service) Diff(ctx context.Context, dr *diffapi.DiffRequest) (*diffapi.D
bMounts = toMounts(dr.Right) bMounts = toMounts(dr.Right)
) )
var opts []diff.Opt
if dr.MediaType != "" {
opts = append(opts, diff.WithMediaType(dr.MediaType))
}
if dr.Ref != "" {
opts = append(opts, diff.WithReference(dr.Ref))
}
if dr.Labels != nil {
opts = append(opts, diff.WithLabels(dr.Labels))
}
for _, differ := range s.differs { for _, differ := range s.differs {
ocidesc, err = differ.DiffMounts(ctx, aMounts, bMounts, dr.MediaType, dr.Ref) ocidesc, err = differ.DiffMounts(ctx, aMounts, bMounts, opts...)
if !errdefs.IsNotImplemented(err) { if !errdefs.IsNotImplemented(err) {
break break
} }

View File

@ -15,6 +15,7 @@ import (
"github.com/containerd/containerd/api/services/tasks/v1" "github.com/containerd/containerd/api/services/tasks/v1"
"github.com/containerd/containerd/api/types" "github.com/containerd/containerd/api/types"
"github.com/containerd/containerd/content" "github.com/containerd/containerd/content"
"github.com/containerd/containerd/diff"
"github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/mount" "github.com/containerd/containerd/mount"
"github.com/containerd/containerd/plugin" "github.com/containerd/containerd/plugin"
@ -482,7 +483,7 @@ func (t *task) checkpointTask(ctx context.Context, index *v1.Index, request *tas
} }
func (t *task) checkpointRWSnapshot(ctx context.Context, index *v1.Index, snapshotterName string, id string) error { func (t *task) checkpointRWSnapshot(ctx context.Context, index *v1.Index, snapshotterName string, id string) error {
rw, err := rootfs.Diff(ctx, id, fmt.Sprintf("checkpoint-rw-%s", id), t.client.SnapshotService(snapshotterName), t.client.DiffService()) rw, err := rootfs.Diff(ctx, id, t.client.SnapshotService(snapshotterName), t.client.DiffService(), diff.WithReference(fmt.Sprintf("checkpoint-rw-%s", id)))
if err != nil { if err != nil {
return err return err
} }