Merge pull request #559 from stevvooe/content-service-cleanup
content: cleanup service and interfaces
This commit is contained in:
commit
4bce28a4a5
15 changed files with 568 additions and 337 deletions
|
@ -165,25 +165,26 @@ type WriteRequest struct {
|
|||
Action WriteAction `protobuf:"varint,1,opt,name=action,proto3,enum=containerd.v1.WriteAction" json:"action,omitempty"`
|
||||
// Ref identifies the pre-commit object to write to.
|
||||
Ref string `protobuf:"bytes,2,opt,name=ref,proto3" json:"ref,omitempty"`
|
||||
// ExpectedSize can be set to have the service validate the total size of
|
||||
// the of committed content.
|
||||
// Total can be set to have the service validate the total size of the
|
||||
// committed content.
|
||||
//
|
||||
// The latest value before or with the commit action message will be use to
|
||||
// validate the content. It is only required on one message for the write.
|
||||
// validate the content. If the offset overflows total, the service may
|
||||
// report an error. It is only required on one message for the write.
|
||||
//
|
||||
// If the value is zero or less, no validation of the final content will be
|
||||
// performed.
|
||||
ExpectedSize int64 `protobuf:"varint,3,opt,name=expected_size,json=expectedSize,proto3" json:"expected_size,omitempty"`
|
||||
// ExpectedDigest can be set to have the service validate the final content
|
||||
// against the provided digest.
|
||||
Total int64 `protobuf:"varint,3,opt,name=total,proto3" json:"total,omitempty"`
|
||||
// Expected can be set to have the service validate the final content against
|
||||
// the provided digest.
|
||||
//
|
||||
// If the digest is already present in the object store, an AlreadyPresent
|
||||
// If the digest is already present in the object store, an AlreadyExists
|
||||
// error will be returned.
|
||||
//
|
||||
// Only the latest version will be used to check the content against the
|
||||
// digest. It is only required to include it on a single message, before or
|
||||
// with the commit action message.
|
||||
ExpectedDigest github_com_opencontainers_go_digest.Digest `protobuf:"bytes,4,opt,name=expected_digest,json=expectedDigest,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"expected_digest"`
|
||||
Expected github_com_opencontainers_go_digest.Digest `protobuf:"bytes,4,opt,name=expected,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"expected"`
|
||||
// Offset specifies the number of bytes from the start at which to begin
|
||||
// the write. If zero or less, the write will be from the start. This uses
|
||||
// standard zero-indexed semantics.
|
||||
|
@ -204,17 +205,30 @@ type WriteResponse struct {
|
|||
// Action contains the action for the final message of the stream. A writer
|
||||
// should confirm that they match the intended result.
|
||||
Action WriteAction `protobuf:"varint,1,opt,name=action,proto3,enum=containerd.v1.WriteAction" json:"action,omitempty"`
|
||||
// Offset provides the current "committed" size for the Write.
|
||||
Offset int64 `protobuf:"varint,2,opt,name=offset,proto3" json:"offset,omitempty"`
|
||||
// StartedAt provides the time at which the write began.
|
||||
//
|
||||
// This must be set for stat and commit write actions. All other write
|
||||
// actions may omit this.
|
||||
StartedAt time.Time `protobuf:"bytes,2,opt,name=started_at,json=startedAt,stdtime" json:"started_at"`
|
||||
// UpdatedAt provides the last time of a successful write.
|
||||
//
|
||||
// This must be set for stat and commit write actions. All other write
|
||||
// actions may omit this.
|
||||
UpdatedAt time.Time `protobuf:"bytes,3,opt,name=updated_at,json=updatedAt,stdtime" json:"updated_at"`
|
||||
// Offset is the current committed size for the write.
|
||||
Offset int64 `protobuf:"varint,4,opt,name=offset,proto3" json:"offset,omitempty"`
|
||||
// Total provides the current, expected total size of the write.
|
||||
//
|
||||
// We include this to provide consistency with the Status structure on the
|
||||
// client writer.
|
||||
//
|
||||
// This is only valid on the Stat and Commit response.
|
||||
Total int64 `protobuf:"varint,5,opt,name=total,proto3" json:"total,omitempty"`
|
||||
// Digest, if present, includes the digest up to the currently committed
|
||||
// bytes. If action is commit, this field will be set. It is implementation
|
||||
// defined if this is set for other actions, except abort. On abort, this
|
||||
// will be empty.
|
||||
Digest github_com_opencontainers_go_digest.Digest `protobuf:"bytes,3,opt,name=digest,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"digest"`
|
||||
// StartedAt is the time at which the write first started.
|
||||
StartedAt time.Time `protobuf:"bytes,4,opt,name=started_at,json=startedAt,stdtime" json:"started_at"`
|
||||
// UpdatedAt is the time the write was last updated.
|
||||
UpdatedAt time.Time `protobuf:"bytes,5,opt,name=updated_at,json=updatedAt,stdtime" json:"updated_at"`
|
||||
Digest github_com_opencontainers_go_digest.Digest `protobuf:"bytes,6,opt,name=digest,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"digest"`
|
||||
}
|
||||
|
||||
func (m *WriteResponse) Reset() { *m = WriteResponse{} }
|
||||
|
@ -231,10 +245,11 @@ func (*StatusRequest) ProtoMessage() {}
|
|||
func (*StatusRequest) Descriptor() ([]byte, []int) { return fileDescriptorContent, []int{6} }
|
||||
|
||||
type StatusResponse struct {
|
||||
Ref string `protobuf:"bytes,1,opt,name=ref,proto3" json:"ref,omitempty"`
|
||||
Offset int64 `protobuf:"varint,2,opt,name=offset,proto3" json:"offset,omitempty"`
|
||||
StartedAt time.Time `protobuf:"bytes,3,opt,name=started_at,json=startedAt,stdtime" json:"started_at"`
|
||||
UpdatedAt time.Time `protobuf:"bytes,4,opt,name=updated_at,json=updatedAt,stdtime" json:"updated_at"`
|
||||
StartedAt time.Time `protobuf:"bytes,1,opt,name=started_at,json=startedAt,stdtime" json:"started_at"`
|
||||
UpdatedAt time.Time `protobuf:"bytes,2,opt,name=updated_at,json=updatedAt,stdtime" json:"updated_at"`
|
||||
Ref string `protobuf:"bytes,3,opt,name=ref,proto3" json:"ref,omitempty"`
|
||||
Offset int64 `protobuf:"varint,4,opt,name=offset,proto3" json:"offset,omitempty"`
|
||||
Total int64 `protobuf:"varint,5,opt,name=total,proto3" json:"total,omitempty"`
|
||||
}
|
||||
|
||||
func (m *StatusResponse) Reset() { *m = StatusResponse{} }
|
||||
|
@ -717,16 +732,16 @@ func (m *WriteRequest) MarshalTo(dAtA []byte) (int, error) {
|
|||
i = encodeVarintContent(dAtA, i, uint64(len(m.Ref)))
|
||||
i += copy(dAtA[i:], m.Ref)
|
||||
}
|
||||
if m.ExpectedSize != 0 {
|
||||
if m.Total != 0 {
|
||||
dAtA[i] = 0x18
|
||||
i++
|
||||
i = encodeVarintContent(dAtA, i, uint64(m.ExpectedSize))
|
||||
i = encodeVarintContent(dAtA, i, uint64(m.Total))
|
||||
}
|
||||
if len(m.ExpectedDigest) > 0 {
|
||||
if len(m.Expected) > 0 {
|
||||
dAtA[i] = 0x22
|
||||
i++
|
||||
i = encodeVarintContent(dAtA, i, uint64(len(m.ExpectedDigest)))
|
||||
i += copy(dAtA[i:], m.ExpectedDigest)
|
||||
i = encodeVarintContent(dAtA, i, uint64(len(m.Expected)))
|
||||
i += copy(dAtA[i:], m.Expected)
|
||||
}
|
||||
if m.Offset != 0 {
|
||||
dAtA[i] = 0x28
|
||||
|
@ -762,18 +777,7 @@ func (m *WriteResponse) MarshalTo(dAtA []byte) (int, error) {
|
|||
i++
|
||||
i = encodeVarintContent(dAtA, i, uint64(m.Action))
|
||||
}
|
||||
if m.Offset != 0 {
|
||||
dAtA[i] = 0x10
|
||||
i++
|
||||
i = encodeVarintContent(dAtA, i, uint64(m.Offset))
|
||||
}
|
||||
if len(m.Digest) > 0 {
|
||||
dAtA[i] = 0x1a
|
||||
i++
|
||||
i = encodeVarintContent(dAtA, i, uint64(len(m.Digest)))
|
||||
i += copy(dAtA[i:], m.Digest)
|
||||
}
|
||||
dAtA[i] = 0x22
|
||||
dAtA[i] = 0x12
|
||||
i++
|
||||
i = encodeVarintContent(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.StartedAt)))
|
||||
n2, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.StartedAt, dAtA[i:])
|
||||
|
@ -781,7 +785,7 @@ func (m *WriteResponse) MarshalTo(dAtA []byte) (int, error) {
|
|||
return 0, err
|
||||
}
|
||||
i += n2
|
||||
dAtA[i] = 0x2a
|
||||
dAtA[i] = 0x1a
|
||||
i++
|
||||
i = encodeVarintContent(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt)))
|
||||
n3, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i:])
|
||||
|
@ -789,6 +793,22 @@ func (m *WriteResponse) MarshalTo(dAtA []byte) (int, error) {
|
|||
return 0, err
|
||||
}
|
||||
i += n3
|
||||
if m.Offset != 0 {
|
||||
dAtA[i] = 0x20
|
||||
i++
|
||||
i = encodeVarintContent(dAtA, i, uint64(m.Offset))
|
||||
}
|
||||
if m.Total != 0 {
|
||||
dAtA[i] = 0x28
|
||||
i++
|
||||
i = encodeVarintContent(dAtA, i, uint64(m.Total))
|
||||
}
|
||||
if len(m.Digest) > 0 {
|
||||
dAtA[i] = 0x32
|
||||
i++
|
||||
i = encodeVarintContent(dAtA, i, uint64(len(m.Digest)))
|
||||
i += copy(dAtA[i:], m.Digest)
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
|
@ -855,18 +875,7 @@ func (m *StatusResponse) MarshalTo(dAtA []byte) (int, error) {
|
|||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.Ref) > 0 {
|
||||
dAtA[i] = 0xa
|
||||
i++
|
||||
i = encodeVarintContent(dAtA, i, uint64(len(m.Ref)))
|
||||
i += copy(dAtA[i:], m.Ref)
|
||||
}
|
||||
if m.Offset != 0 {
|
||||
dAtA[i] = 0x10
|
||||
i++
|
||||
i = encodeVarintContent(dAtA, i, uint64(m.Offset))
|
||||
}
|
||||
dAtA[i] = 0x1a
|
||||
dAtA[i] = 0xa
|
||||
i++
|
||||
i = encodeVarintContent(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.StartedAt)))
|
||||
n4, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.StartedAt, dAtA[i:])
|
||||
|
@ -874,7 +883,7 @@ func (m *StatusResponse) MarshalTo(dAtA []byte) (int, error) {
|
|||
return 0, err
|
||||
}
|
||||
i += n4
|
||||
dAtA[i] = 0x22
|
||||
dAtA[i] = 0x12
|
||||
i++
|
||||
i = encodeVarintContent(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt)))
|
||||
n5, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i:])
|
||||
|
@ -882,6 +891,22 @@ func (m *StatusResponse) MarshalTo(dAtA []byte) (int, error) {
|
|||
return 0, err
|
||||
}
|
||||
i += n5
|
||||
if len(m.Ref) > 0 {
|
||||
dAtA[i] = 0x1a
|
||||
i++
|
||||
i = encodeVarintContent(dAtA, i, uint64(len(m.Ref)))
|
||||
i += copy(dAtA[i:], m.Ref)
|
||||
}
|
||||
if m.Offset != 0 {
|
||||
dAtA[i] = 0x20
|
||||
i++
|
||||
i = encodeVarintContent(dAtA, i, uint64(m.Offset))
|
||||
}
|
||||
if m.Total != 0 {
|
||||
dAtA[i] = 0x28
|
||||
i++
|
||||
i = encodeVarintContent(dAtA, i, uint64(m.Total))
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
|
@ -976,10 +1001,10 @@ func (m *WriteRequest) Size() (n int) {
|
|||
if l > 0 {
|
||||
n += 1 + l + sovContent(uint64(l))
|
||||
}
|
||||
if m.ExpectedSize != 0 {
|
||||
n += 1 + sovContent(uint64(m.ExpectedSize))
|
||||
if m.Total != 0 {
|
||||
n += 1 + sovContent(uint64(m.Total))
|
||||
}
|
||||
l = len(m.ExpectedDigest)
|
||||
l = len(m.Expected)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovContent(uint64(l))
|
||||
}
|
||||
|
@ -999,17 +1024,20 @@ func (m *WriteResponse) Size() (n int) {
|
|||
if m.Action != 0 {
|
||||
n += 1 + sovContent(uint64(m.Action))
|
||||
}
|
||||
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.StartedAt)
|
||||
n += 1 + l + sovContent(uint64(l))
|
||||
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt)
|
||||
n += 1 + l + sovContent(uint64(l))
|
||||
if m.Offset != 0 {
|
||||
n += 1 + sovContent(uint64(m.Offset))
|
||||
}
|
||||
if m.Total != 0 {
|
||||
n += 1 + sovContent(uint64(m.Total))
|
||||
}
|
||||
l = len(m.Digest)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovContent(uint64(l))
|
||||
}
|
||||
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.StartedAt)
|
||||
n += 1 + l + sovContent(uint64(l))
|
||||
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt)
|
||||
n += 1 + l + sovContent(uint64(l))
|
||||
return n
|
||||
}
|
||||
|
||||
|
@ -1034,6 +1062,10 @@ func (m *StatusRequest) Size() (n int) {
|
|||
func (m *StatusResponse) Size() (n int) {
|
||||
var l int
|
||||
_ = l
|
||||
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.StartedAt)
|
||||
n += 1 + l + sovContent(uint64(l))
|
||||
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt)
|
||||
n += 1 + l + sovContent(uint64(l))
|
||||
l = len(m.Ref)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovContent(uint64(l))
|
||||
|
@ -1041,10 +1073,9 @@ func (m *StatusResponse) Size() (n int) {
|
|||
if m.Offset != 0 {
|
||||
n += 1 + sovContent(uint64(m.Offset))
|
||||
}
|
||||
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.StartedAt)
|
||||
n += 1 + l + sovContent(uint64(l))
|
||||
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt)
|
||||
n += 1 + l + sovContent(uint64(l))
|
||||
if m.Total != 0 {
|
||||
n += 1 + sovContent(uint64(m.Total))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
|
@ -1113,8 +1144,8 @@ func (this *WriteRequest) String() string {
|
|||
s := strings.Join([]string{`&WriteRequest{`,
|
||||
`Action:` + fmt.Sprintf("%v", this.Action) + `,`,
|
||||
`Ref:` + fmt.Sprintf("%v", this.Ref) + `,`,
|
||||
`ExpectedSize:` + fmt.Sprintf("%v", this.ExpectedSize) + `,`,
|
||||
`ExpectedDigest:` + fmt.Sprintf("%v", this.ExpectedDigest) + `,`,
|
||||
`Total:` + fmt.Sprintf("%v", this.Total) + `,`,
|
||||
`Expected:` + fmt.Sprintf("%v", this.Expected) + `,`,
|
||||
`Offset:` + fmt.Sprintf("%v", this.Offset) + `,`,
|
||||
`Data:` + fmt.Sprintf("%v", this.Data) + `,`,
|
||||
`}`,
|
||||
|
@ -1127,10 +1158,11 @@ func (this *WriteResponse) String() string {
|
|||
}
|
||||
s := strings.Join([]string{`&WriteResponse{`,
|
||||
`Action:` + fmt.Sprintf("%v", this.Action) + `,`,
|
||||
`Offset:` + fmt.Sprintf("%v", this.Offset) + `,`,
|
||||
`Digest:` + fmt.Sprintf("%v", this.Digest) + `,`,
|
||||
`StartedAt:` + strings.Replace(strings.Replace(this.StartedAt.String(), "Timestamp", "google_protobuf1.Timestamp", 1), `&`, ``, 1) + `,`,
|
||||
`UpdatedAt:` + strings.Replace(strings.Replace(this.UpdatedAt.String(), "Timestamp", "google_protobuf1.Timestamp", 1), `&`, ``, 1) + `,`,
|
||||
`Offset:` + fmt.Sprintf("%v", this.Offset) + `,`,
|
||||
`Total:` + fmt.Sprintf("%v", this.Total) + `,`,
|
||||
`Digest:` + fmt.Sprintf("%v", this.Digest) + `,`,
|
||||
`}`,
|
||||
}, "")
|
||||
return s
|
||||
|
@ -1151,10 +1183,11 @@ func (this *StatusResponse) String() string {
|
|||
return "nil"
|
||||
}
|
||||
s := strings.Join([]string{`&StatusResponse{`,
|
||||
`Ref:` + fmt.Sprintf("%v", this.Ref) + `,`,
|
||||
`Offset:` + fmt.Sprintf("%v", this.Offset) + `,`,
|
||||
`StartedAt:` + strings.Replace(strings.Replace(this.StartedAt.String(), "Timestamp", "google_protobuf1.Timestamp", 1), `&`, ``, 1) + `,`,
|
||||
`UpdatedAt:` + strings.Replace(strings.Replace(this.UpdatedAt.String(), "Timestamp", "google_protobuf1.Timestamp", 1), `&`, ``, 1) + `,`,
|
||||
`Ref:` + fmt.Sprintf("%v", this.Ref) + `,`,
|
||||
`Offset:` + fmt.Sprintf("%v", this.Offset) + `,`,
|
||||
`Total:` + fmt.Sprintf("%v", this.Total) + `,`,
|
||||
`}`,
|
||||
}, "")
|
||||
return s
|
||||
|
@ -1670,9 +1703,9 @@ func (m *WriteRequest) Unmarshal(dAtA []byte) error {
|
|||
iNdEx = postIndex
|
||||
case 3:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field ExpectedSize", wireType)
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Total", wireType)
|
||||
}
|
||||
m.ExpectedSize = 0
|
||||
m.Total = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowContent
|
||||
|
@ -1682,14 +1715,14 @@ func (m *WriteRequest) Unmarshal(dAtA []byte) error {
|
|||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.ExpectedSize |= (int64(b) & 0x7F) << shift
|
||||
m.Total |= (int64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 4:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field ExpectedDigest", wireType)
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Expected", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
|
@ -1714,7 +1747,7 @@ func (m *WriteRequest) Unmarshal(dAtA []byte) error {
|
|||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.ExpectedDigest = github_com_opencontainers_go_digest.Digest(dAtA[iNdEx:postIndex])
|
||||
m.Expected = github_com_opencontainers_go_digest.Digest(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 5:
|
||||
if wireType != 0 {
|
||||
|
@ -1836,54 +1869,6 @@ func (m *WriteResponse) Unmarshal(dAtA []byte) error {
|
|||
}
|
||||
}
|
||||
case 2:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Offset", wireType)
|
||||
}
|
||||
m.Offset = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowContent
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.Offset |= (int64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 3:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Digest", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowContent
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthContent
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Digest = github_com_opencontainers_go_digest.Digest(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 4:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field StartedAt", wireType)
|
||||
}
|
||||
|
@ -1913,7 +1898,7 @@ func (m *WriteResponse) Unmarshal(dAtA []byte) error {
|
|||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 5:
|
||||
case 3:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field UpdatedAt", wireType)
|
||||
}
|
||||
|
@ -1943,6 +1928,73 @@ func (m *WriteResponse) Unmarshal(dAtA []byte) error {
|
|||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 4:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Offset", wireType)
|
||||
}
|
||||
m.Offset = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowContent
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.Offset |= (int64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 5:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Total", wireType)
|
||||
}
|
||||
m.Total = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowContent
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.Total |= (int64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 6:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Digest", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowContent
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthContent
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Digest = github_com_opencontainers_go_digest.Digest(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipContent(dAtA[iNdEx:])
|
||||
|
@ -2102,54 +2154,6 @@ func (m *StatusResponse) Unmarshal(dAtA []byte) error {
|
|||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Ref", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowContent
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthContent
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Ref = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 2:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Offset", wireType)
|
||||
}
|
||||
m.Offset = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowContent
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.Offset |= (int64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 3:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field StartedAt", wireType)
|
||||
}
|
||||
|
@ -2179,7 +2183,7 @@ func (m *StatusResponse) Unmarshal(dAtA []byte) error {
|
|||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 4:
|
||||
case 2:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field UpdatedAt", wireType)
|
||||
}
|
||||
|
@ -2209,6 +2213,73 @@ func (m *StatusResponse) Unmarshal(dAtA []byte) error {
|
|||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 3:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Ref", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowContent
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthContent
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Ref = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 4:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Offset", wireType)
|
||||
}
|
||||
m.Offset = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowContent
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.Offset |= (int64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 5:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Total", wireType)
|
||||
}
|
||||
m.Total = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowContent
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.Total |= (int64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipContent(dAtA[iNdEx:])
|
||||
|
@ -2340,51 +2411,51 @@ func init() {
|
|||
}
|
||||
|
||||
var fileDescriptorContent = []byte{
|
||||
// 733 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x95, 0xb1, 0x6f, 0xd3, 0x4e,
|
||||
0x14, 0xc7, 0x73, 0x89, 0x93, 0xdf, 0x2f, 0x2f, 0x49, 0x1b, 0xae, 0x05, 0x45, 0x6e, 0xeb, 0x84,
|
||||
0xb0, 0x44, 0x95, 0xb0, 0x4b, 0xd8, 0x60, 0xa8, 0x9c, 0x14, 0xaa, 0x22, 0x55, 0x95, 0xdc, 0x48,
|
||||
0x15, 0x62, 0x40, 0x4e, 0x72, 0x31, 0x16, 0xc4, 0x67, 0xec, 0x4b, 0x55, 0x31, 0x21, 0x24, 0x24,
|
||||
0xd4, 0x89, 0x7f, 0xa0, 0x2c, 0xb0, 0x23, 0x26, 0x24, 0x66, 0x86, 0x8e, 0x8c, 0x88, 0xa1, 0xd0,
|
||||
0xfc, 0x23, 0x20, 0x9f, 0xcf, 0x89, 0x9b, 0xa6, 0x43, 0x4b, 0xc9, 0xe2, 0x67, 0xbf, 0xf7, 0xbe,
|
||||
0x79, 0xf7, 0xf1, 0x37, 0x2f, 0xb0, 0x6a, 0xd9, 0xec, 0xc9, 0xa0, 0xad, 0x76, 0x68, 0x5f, 0xeb,
|
||||
0xd2, 0xce, 0x53, 0xe2, 0x69, 0x1d, 0xea, 0x30, 0xd3, 0x76, 0x88, 0xd7, 0xd5, 0x4c, 0xd7, 0xd6,
|
||||
0x7c, 0xe2, 0xed, 0xda, 0x1d, 0xe2, 0xf3, 0xe7, 0xc4, 0x61, 0xd1, 0x55, 0x75, 0x3d, 0xca, 0x28,
|
||||
0x2e, 0x8c, 0xcb, 0xd5, 0xdd, 0x5b, 0xf2, 0xbc, 0x45, 0x2d, 0xca, 0x33, 0x5a, 0x10, 0x85, 0x45,
|
||||
0x72, 0xd9, 0xa2, 0xd4, 0x7a, 0x46, 0x34, 0x7e, 0xd7, 0x1e, 0xf4, 0x34, 0x66, 0xf7, 0x89, 0xcf,
|
||||
0xcc, 0xbe, 0x1b, 0x16, 0x54, 0x1f, 0x42, 0x6e, 0xc3, 0xe9, 0x51, 0x83, 0x3c, 0x1f, 0x10, 0x9f,
|
||||
0xe1, 0x07, 0x90, 0xe9, 0xda, 0x16, 0xf1, 0x59, 0x09, 0x55, 0x50, 0x2d, 0xdb, 0xa8, 0x1f, 0x1e,
|
||||
0x95, 0x13, 0x3f, 0x8e, 0xca, 0xcb, 0xb1, 0x69, 0xa9, 0x4b, 0x9c, 0xd1, 0x77, 0xfb, 0x9a, 0x45,
|
||||
0x6f, 0x86, 0x2d, 0xea, 0x1a, 0xbf, 0x18, 0x42, 0xa1, 0xfa, 0x19, 0x41, 0x3e, 0xd4, 0xf6, 0x5d,
|
||||
0xea, 0xf8, 0xe4, 0x32, 0xc5, 0x31, 0x06, 0xc9, 0xb7, 0x5f, 0x90, 0x52, 0xb2, 0x82, 0x6a, 0x29,
|
||||
0x83, 0xc7, 0x78, 0x1d, 0xf2, 0x1d, 0xda, 0xef, 0xdb, 0x8c, 0x91, 0xee, 0x63, 0x93, 0x95, 0x52,
|
||||
0x15, 0x54, 0xcb, 0xd5, 0x65, 0x35, 0x64, 0xa0, 0x46, 0x0c, 0xd4, 0x56, 0xc4, 0xa0, 0xf1, 0x7f,
|
||||
0x30, 0xc1, 0xdb, 0x9f, 0x65, 0x64, 0xe4, 0x46, 0x9d, 0x3a, 0xab, 0xbe, 0x46, 0x90, 0x33, 0x88,
|
||||
0xd9, 0xfd, 0x07, 0x54, 0xf0, 0x35, 0xc8, 0xd0, 0x5e, 0xcf, 0x27, 0x4c, 0x8c, 0x2e, 0xee, 0x46,
|
||||
0x07, 0x4a, 0x8d, 0x0f, 0x54, 0xbd, 0x03, 0xf9, 0x70, 0x0c, 0x01, 0x70, 0xdc, 0x8b, 0x26, 0x7b,
|
||||
0xbb, 0x26, 0x33, 0xb9, 0x62, 0xde, 0xe0, 0x71, 0xf5, 0x55, 0x12, 0xf2, 0x3b, 0x9e, 0xcd, 0x48,
|
||||
0x74, 0x88, 0x3a, 0x64, 0xcc, 0x0e, 0xb3, 0xa9, 0xc3, 0x9b, 0x67, 0xea, 0xb2, 0x7a, 0xc2, 0x40,
|
||||
0x2a, 0x2f, 0xd6, 0x79, 0x85, 0x21, 0x2a, 0x71, 0x11, 0x52, 0x1e, 0xe9, 0x71, 0xdd, 0xac, 0x11,
|
||||
0x84, 0xf8, 0x06, 0x14, 0xc8, 0x9e, 0x4b, 0x3a, 0x01, 0xe2, 0xd8, 0xbc, 0xf9, 0xe8, 0xe1, 0x76,
|
||||
0xf0, 0x22, 0x1e, 0xc1, 0xec, 0xa8, 0x48, 0x80, 0x93, 0x2e, 0x0c, 0x6e, 0x26, 0x92, 0x5a, 0x9b,
|
||||
0x04, 0x98, 0x9e, 0x0a, 0x21, 0x13, 0x83, 0xf0, 0x29, 0x09, 0x05, 0x01, 0x41, 0x20, 0xbc, 0x08,
|
||||
0x85, 0xb3, 0x5e, 0xd9, 0xd8, 0x16, 0xa9, 0xbf, 0xb6, 0x45, 0x13, 0xc0, 0x67, 0xa6, 0x27, 0x9c,
|
||||
0x2b, 0x9d, 0xc3, 0xb9, 0x59, 0xd1, 0xa7, 0x73, 0x91, 0x81, 0xdb, 0x35, 0x85, 0x48, 0xfa, 0x3c,
|
||||
0x22, 0xa2, 0x4f, 0x67, 0xd5, 0xbb, 0x50, 0xd8, 0x66, 0x26, 0x1b, 0xf8, 0x91, 0x71, 0x30, 0x48,
|
||||
0x1e, 0xe9, 0xf9, 0x25, 0x54, 0x49, 0xd5, 0xb2, 0x06, 0x8f, 0x03, 0x24, 0xae, 0x47, 0x7a, 0xf6,
|
||||
0x5e, 0x29, 0xc9, 0x9f, 0x8a, 0xbb, 0xea, 0x57, 0x04, 0x33, 0x51, 0xb7, 0x20, 0x2e, 0x3c, 0x84,
|
||||
0xc6, 0x1e, 0x3a, 0x8b, 0xe7, 0x49, 0x06, 0xa9, 0xcb, 0x60, 0x20, 0x5d, 0x88, 0xc1, 0xf2, 0x47,
|
||||
0x04, 0xb9, 0x98, 0x13, 0xf0, 0x12, 0x48, 0xdb, 0x2d, 0xbd, 0x55, 0x4c, 0xc8, 0x73, 0xfb, 0x07,
|
||||
0x95, 0xd9, 0x58, 0x2a, 0x38, 0x2c, 0x2e, 0x43, 0x7a, 0xc7, 0xd8, 0x68, 0xdd, 0x2b, 0x22, 0x79,
|
||||
0x7e, 0xff, 0xa0, 0x52, 0x8c, 0xe5, 0x79, 0x88, 0xaf, 0x43, 0xa6, 0xb9, 0xb5, 0xb9, 0xb9, 0xd1,
|
||||
0x2a, 0x26, 0xe5, 0xab, 0xfb, 0x07, 0x95, 0x2b, 0xb1, 0x8a, 0x26, 0x5f, 0x3c, 0xb8, 0x06, 0x69,
|
||||
0xbd, 0xb1, 0x65, 0xb4, 0x8a, 0xbf, 0xa3, 0xcf, 0x69, 0x31, 0xbd, 0x4d, 0x3d, 0x26, 0xcf, 0xbd,
|
||||
0x79, 0xaf, 0x24, 0xbe, 0x7c, 0x50, 0xe2, 0x13, 0xd6, 0xdf, 0x25, 0xe1, 0xbf, 0x66, 0xf8, 0xff,
|
||||
0x80, 0x57, 0x41, 0x0a, 0xf6, 0x2e, 0x9e, 0xf4, 0x76, 0x6c, 0xd1, 0xcb, 0x0b, 0x53, 0x73, 0xe2,
|
||||
0x95, 0xe9, 0x20, 0x05, 0x7b, 0xe7, 0x94, 0x40, 0x6c, 0x27, 0x9e, 0x12, 0x88, 0x2f, 0xaa, 0x15,
|
||||
0x84, 0xd7, 0x21, 0x13, 0xfa, 0x00, 0x2f, 0x4e, 0x14, 0x9e, 0x30, 0x97, 0xbc, 0x74, 0x46, 0x76,
|
||||
0x24, 0x74, 0x1f, 0xd2, 0x21, 0xc3, 0x85, 0x69, 0xbf, 0xd4, 0x48, 0x66, 0x71, 0x7a, 0x32, 0x54,
|
||||
0xa9, 0xa1, 0x15, 0xd4, 0x28, 0x1d, 0x1e, 0x2b, 0x89, 0xef, 0xc7, 0x4a, 0xe2, 0xe5, 0x50, 0x41,
|
||||
0x87, 0x43, 0x05, 0x7d, 0x1b, 0x2a, 0xe8, 0xd7, 0x50, 0x41, 0xed, 0x0c, 0x77, 0xc5, 0xed, 0x3f,
|
||||
0x01, 0x00, 0x00, 0xff, 0xff, 0x6f, 0xe6, 0x59, 0x92, 0x92, 0x07, 0x00, 0x00,
|
||||
// 734 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0x4d, 0x6f, 0xd3, 0x4a,
|
||||
0x14, 0xcd, 0xe4, 0xc3, 0xaf, 0xb9, 0x49, 0xfb, 0xf2, 0xa6, 0x7d, 0x4f, 0x91, 0xdb, 0x3a, 0x79,
|
||||
0x59, 0x45, 0x95, 0xb0, 0x4b, 0xd8, 0xc1, 0xa2, 0x72, 0x02, 0x54, 0x45, 0x2a, 0x95, 0xdc, 0x48,
|
||||
0x15, 0x2b, 0xe4, 0xc4, 0x13, 0x63, 0xd1, 0x78, 0x8c, 0x3d, 0xa9, 0x2a, 0x56, 0x6c, 0x90, 0x50,
|
||||
0x57, 0xfc, 0x81, 0xb2, 0x81, 0x3d, 0x4b, 0x24, 0xfe, 0x00, 0x5d, 0xb2, 0x44, 0x5d, 0x14, 0x9a,
|
||||
0x05, 0x7f, 0x03, 0xe4, 0xf1, 0x38, 0x71, 0xda, 0xb0, 0x68, 0x28, 0xdd, 0xf8, 0x8e, 0xef, 0xbd,
|
||||
0xa7, 0xf7, 0x1c, 0x9f, 0xb9, 0x81, 0x0d, 0xdb, 0x61, 0x4f, 0x06, 0x1d, 0xb5, 0x4b, 0xfb, 0x9a,
|
||||
0x45, 0xbb, 0x4f, 0x89, 0xaf, 0x75, 0xa9, 0xcb, 0x4c, 0xc7, 0x25, 0xbe, 0xa5, 0x99, 0x9e, 0xa3,
|
||||
0x05, 0xc4, 0x3f, 0x70, 0xba, 0x24, 0xe0, 0xef, 0x89, 0xcb, 0xe2, 0xa7, 0xea, 0xf9, 0x94, 0x51,
|
||||
0x3c, 0x3f, 0x2e, 0x57, 0x0f, 0x6e, 0xca, 0x4b, 0x36, 0xb5, 0x29, 0xcf, 0x68, 0x61, 0x14, 0x15,
|
||||
0xc9, 0x15, 0x9b, 0x52, 0x7b, 0x9f, 0x68, 0xfc, 0xd4, 0x19, 0xf4, 0x34, 0xe6, 0xf4, 0x49, 0xc0,
|
||||
0xcc, 0xbe, 0x17, 0x15, 0xd4, 0x1e, 0x41, 0x61, 0xcb, 0xed, 0x51, 0x83, 0x3c, 0x1b, 0x90, 0x80,
|
||||
0xe1, 0x07, 0x20, 0x59, 0x8e, 0x4d, 0x02, 0x56, 0x46, 0x55, 0x54, 0xcf, 0x37, 0x1b, 0x27, 0x67,
|
||||
0x95, 0xd4, 0xe9, 0x59, 0x65, 0x2d, 0x31, 0x2d, 0xf5, 0x88, 0x3b, 0xfa, 0xdf, 0x81, 0x66, 0xd3,
|
||||
0x1b, 0x51, 0x8b, 0x7a, 0x97, 0x3f, 0x0c, 0x81, 0x50, 0xfb, 0x80, 0xa0, 0x18, 0x61, 0x07, 0x1e,
|
||||
0x75, 0x03, 0x72, 0x9d, 0xe0, 0x18, 0x43, 0x36, 0x70, 0x9e, 0x93, 0x72, 0xba, 0x8a, 0xea, 0x19,
|
||||
0x83, 0xc7, 0x78, 0x13, 0x8a, 0x5d, 0xda, 0xef, 0x3b, 0x8c, 0x11, 0xeb, 0xb1, 0xc9, 0xca, 0x99,
|
||||
0x2a, 0xaa, 0x17, 0x1a, 0xb2, 0x1a, 0x69, 0xa0, 0xc6, 0x1a, 0xa8, 0xed, 0x58, 0x83, 0xe6, 0x5c,
|
||||
0x38, 0xc1, 0xeb, 0xaf, 0x15, 0x64, 0x14, 0x46, 0x9d, 0x3a, 0xab, 0xbd, 0x44, 0x50, 0x30, 0x88,
|
||||
0x69, 0xfd, 0x01, 0x55, 0xf0, 0x7f, 0x20, 0xd1, 0x5e, 0x2f, 0x20, 0x4c, 0x8c, 0x2e, 0x4e, 0x23,
|
||||
0x42, 0x99, 0x31, 0xa1, 0xda, 0x6d, 0x28, 0x46, 0x63, 0x08, 0x01, 0xc7, 0xbd, 0xe8, 0x62, 0xaf,
|
||||
0x65, 0x32, 0x93, 0x23, 0x16, 0x0d, 0x1e, 0xd7, 0xbe, 0x23, 0x28, 0xee, 0xf9, 0x0e, 0x23, 0x31,
|
||||
0x89, 0x06, 0x48, 0x66, 0x97, 0x39, 0xd4, 0xe5, 0xcd, 0x0b, 0x0d, 0x59, 0x9d, 0x30, 0x90, 0xca,
|
||||
0x8b, 0x75, 0x5e, 0x61, 0x88, 0x4a, 0x5c, 0x82, 0x8c, 0x4f, 0x7a, 0x1c, 0x37, 0x6f, 0x84, 0x21,
|
||||
0x5e, 0x82, 0x1c, 0xa3, 0xcc, 0xdc, 0x17, 0x73, 0x46, 0x07, 0xfc, 0x10, 0xe6, 0xc8, 0xa1, 0x47,
|
||||
0xba, 0x8c, 0x58, 0xe5, 0xec, 0xcc, 0x12, 0x8d, 0x30, 0x12, 0x44, 0x73, 0x53, 0x89, 0x4a, 0x09,
|
||||
0xa2, 0x9f, 0xd2, 0x30, 0x2f, 0x88, 0x0a, 0x99, 0x66, 0x61, 0xda, 0x02, 0x08, 0x98, 0xe9, 0x0b,
|
||||
0xe7, 0xa4, 0xaf, 0xe0, 0x9c, 0xbc, 0xe8, 0xd3, 0x59, 0x08, 0x32, 0xf0, 0x2c, 0x73, 0x06, 0xfb,
|
||||
0xe5, 0x45, 0x9f, 0x9e, 0x34, 0x48, 0x76, 0x82, 0xfb, 0x48, 0xf9, 0x5c, 0x52, 0xf9, 0xb1, 0x35,
|
||||
0xa5, 0xdf, 0xbe, 0xb0, 0x77, 0x60, 0x7e, 0x97, 0x99, 0x6c, 0x10, 0xc4, 0x96, 0xc1, 0x90, 0xf5,
|
||||
0x49, 0x2f, 0x28, 0xa3, 0x6a, 0xa6, 0x9e, 0x37, 0x78, 0x1c, 0x8e, 0xe7, 0xf9, 0xa4, 0xe7, 0x1c,
|
||||
0x96, 0xd3, 0xfc, 0xad, 0x38, 0xd5, 0x4e, 0x11, 0x2c, 0xc4, 0xdd, 0xe2, 0x3b, 0x4c, 0x6a, 0x8a,
|
||||
0xae, 0x43, 0xd3, 0xf4, 0x6c, 0x9a, 0x0a, 0x1f, 0x67, 0xc6, 0x3e, 0xbe, 0x92, 0xca, 0x6b, 0xef,
|
||||
0x11, 0x14, 0x12, 0xae, 0xc1, 0xab, 0x90, 0xdd, 0x6d, 0xeb, 0xed, 0x52, 0x4a, 0x5e, 0x3c, 0x3a,
|
||||
0xae, 0xfe, 0x9d, 0x48, 0x85, 0x12, 0xe0, 0x0a, 0xe4, 0xf6, 0x8c, 0xad, 0xf6, 0xbd, 0x12, 0x92,
|
||||
0x97, 0x8e, 0x8e, 0xab, 0xa5, 0x44, 0x9e, 0x87, 0xf8, 0x7f, 0x90, 0x5a, 0x3b, 0xdb, 0xdb, 0x5b,
|
||||
0xed, 0x52, 0x5a, 0xfe, 0xf7, 0xe8, 0xb8, 0xfa, 0x4f, 0xa2, 0xa2, 0xc5, 0x17, 0x11, 0xae, 0x43,
|
||||
0x4e, 0x6f, 0xee, 0x18, 0xed, 0xd2, 0x8f, 0xf8, 0xef, 0x32, 0x98, 0xde, 0xa1, 0x3e, 0x93, 0x17,
|
||||
0x5f, 0xbd, 0x55, 0x52, 0x1f, 0xdf, 0x29, 0xc9, 0x09, 0x1b, 0x6f, 0xd2, 0xf0, 0x57, 0x2b, 0xfa,
|
||||
0xbd, 0xc0, 0x1b, 0x90, 0x0d, 0xf7, 0x30, 0xbe, 0x78, 0x0f, 0x12, 0x8b, 0x5f, 0x5e, 0x9e, 0x9a,
|
||||
0x13, 0x1f, 0x52, 0x87, 0x6c, 0xb8, 0x87, 0x2e, 0x01, 0x24, 0x76, 0xe4, 0x25, 0x80, 0xe4, 0xe2,
|
||||
0x5a, 0x47, 0x78, 0x13, 0xa4, 0xc8, 0x1d, 0x78, 0xe5, 0x42, 0xe1, 0x84, 0xe5, 0xe4, 0xd5, 0x5f,
|
||||
0x64, 0x47, 0x40, 0xf7, 0x21, 0x17, 0x69, 0xb8, 0x3c, 0xed, 0x56, 0xc7, 0x30, 0x2b, 0xd3, 0x93,
|
||||
0x11, 0x4a, 0x1d, 0xad, 0xa3, 0x66, 0xf9, 0xe4, 0x5c, 0x49, 0x7d, 0x39, 0x57, 0x52, 0x2f, 0x86,
|
||||
0x0a, 0x3a, 0x19, 0x2a, 0xe8, 0xf3, 0x50, 0x41, 0xdf, 0x86, 0x0a, 0xea, 0x48, 0xdc, 0x55, 0xb7,
|
||||
0x7e, 0x06, 0x00, 0x00, 0xff, 0xff, 0x8d, 0x7a, 0xfb, 0xa8, 0xa2, 0x07, 0x00, 0x00,
|
||||
}
|
||||
|
|
|
@ -133,26 +133,27 @@ message WriteRequest {
|
|||
// Ref identifies the pre-commit object to write to.
|
||||
string ref = 2;
|
||||
|
||||
// ExpectedSize can be set to have the service validate the total size of
|
||||
// the of committed content.
|
||||
// Total can be set to have the service validate the total size of the
|
||||
// committed content.
|
||||
//
|
||||
// The latest value before or with the commit action message will be use to
|
||||
// validate the content. It is only required on one message for the write.
|
||||
// validate the content. If the offset overflows total, the service may
|
||||
// report an error. It is only required on one message for the write.
|
||||
//
|
||||
// If the value is zero or less, no validation of the final content will be
|
||||
// performed.
|
||||
int64 expected_size = 3;
|
||||
int64 total = 3;
|
||||
|
||||
// ExpectedDigest can be set to have the service validate the final content
|
||||
// against the provided digest.
|
||||
// Expected can be set to have the service validate the final content against
|
||||
// the provided digest.
|
||||
//
|
||||
// If the digest is already present in the object store, an AlreadyPresent
|
||||
// If the digest is already present in the object store, an AlreadyExists
|
||||
// error will be returned.
|
||||
//
|
||||
// Only the latest version will be used to check the content against the
|
||||
// digest. It is only required to include it on a single message, before or
|
||||
// with the commit action message.
|
||||
string expected_digest = 4 [(gogoproto.customtype) = "github.com/opencontainers/go-digest.Digest", (gogoproto.nullable) = false];
|
||||
string expected = 4 [(gogoproto.customtype) = "github.com/opencontainers/go-digest.Digest", (gogoproto.nullable) = false];
|
||||
|
||||
// Offset specifies the number of bytes from the start at which to begin
|
||||
// the write. If zero or less, the write will be from the start. This uses
|
||||
|
@ -172,20 +173,34 @@ message WriteResponse {
|
|||
// should confirm that they match the intended result.
|
||||
WriteAction action = 1;
|
||||
|
||||
// Offset provides the current "committed" size for the Write.
|
||||
int64 offset = 2;
|
||||
// StartedAt provides the time at which the write began.
|
||||
//
|
||||
// This must be set for stat and commit write actions. All other write
|
||||
// actions may omit this.
|
||||
google.protobuf.Timestamp started_at = 2 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
|
||||
|
||||
// UpdatedAt provides the last time of a successful write.
|
||||
//
|
||||
// This must be set for stat and commit write actions. All other write
|
||||
// actions may omit this.
|
||||
google.protobuf.Timestamp updated_at = 3 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
|
||||
|
||||
// Offset is the current committed size for the write.
|
||||
int64 offset = 4;
|
||||
|
||||
// Total provides the current, expected total size of the write.
|
||||
//
|
||||
// We include this to provide consistency with the Status structure on the
|
||||
// client writer.
|
||||
//
|
||||
// This is only valid on the Stat and Commit response.
|
||||
int64 total = 5;
|
||||
|
||||
// Digest, if present, includes the digest up to the currently committed
|
||||
// bytes. If action is commit, this field will be set. It is implementation
|
||||
// defined if this is set for other actions, except abort. On abort, this
|
||||
// will be empty.
|
||||
string digest = 3 [(gogoproto.customtype) = "github.com/opencontainers/go-digest.Digest", (gogoproto.nullable) = false];
|
||||
|
||||
// StartedAt is the time at which the write first started.
|
||||
google.protobuf.Timestamp started_at = 4 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
|
||||
|
||||
// UpdatedAt is the time the write was last updated.
|
||||
google.protobuf.Timestamp updated_at = 5 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
|
||||
string digest = 6 [(gogoproto.customtype) = "github.com/opencontainers/go-digest.Digest", (gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
message StatusRequest {
|
||||
|
@ -194,8 +209,9 @@ message StatusRequest {
|
|||
}
|
||||
|
||||
message StatusResponse {
|
||||
string ref = 1;
|
||||
int64 offset = 2;
|
||||
google.protobuf.Timestamp started_at = 3 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
|
||||
google.protobuf.Timestamp updated_at = 4 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
|
||||
google.protobuf.Timestamp started_at = 1 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
|
||||
google.protobuf.Timestamp updated_at = 2 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
|
||||
string ref = 3;
|
||||
int64 offset = 4;
|
||||
int64 total = 5;
|
||||
}
|
||||
|
|
2
cmd/dist/common.go
vendored
2
cmd/dist/common.go
vendored
|
@ -11,7 +11,7 @@ import (
|
|||
)
|
||||
|
||||
func resolveContentStore(context *cli.Context) (*content.Store, error) {
|
||||
root := context.GlobalString("root")
|
||||
root := filepath.Join(context.GlobalString("root"), "content")
|
||||
if !filepath.IsAbs(root) {
|
||||
var err error
|
||||
root, err = filepath.Abs(root)
|
||||
|
|
12
cmd/dist/fetch.go
vendored
12
cmd/dist/fetch.go
vendored
|
@ -100,8 +100,8 @@ var fetchCommand = cli.Command{
|
|||
|
||||
// getResolver prepares the resolver from the environment and options.
|
||||
func getResolver(ctx contextpkg.Context) (remotes.Resolver, error) {
|
||||
return remotes.ResolverFunc(func(ctx contextpkg.Context, locator string) (remotes.Remote, error) {
|
||||
if !strings.HasPrefix(locator, "docker.io") {
|
||||
return remotes.ResolverFunc(func(ctx contextpkg.Context, locator string) (remotes.Fetcher, error) {
|
||||
if !strings.HasPrefix(locator, "docker.io") && !strings.HasPrefix(locator, "localhost:5000") {
|
||||
return nil, errors.Errorf("unsupported locator: %q", locator)
|
||||
}
|
||||
|
||||
|
@ -113,12 +113,18 @@ func getResolver(ctx contextpkg.Context) (remotes.Resolver, error) {
|
|||
prefix = strings.TrimPrefix(locator, "docker.io/")
|
||||
)
|
||||
|
||||
if strings.HasPrefix(locator, "localhost:5000") {
|
||||
base.Scheme = "http"
|
||||
base.Host = "localhost:5000"
|
||||
prefix = strings.TrimPrefix(locator, "localhost:5000/")
|
||||
}
|
||||
|
||||
token, err := getToken(ctx, "repository:"+prefix+":pull")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return remotes.RemoteFunc(func(ctx contextpkg.Context, object string, hints ...string) (io.ReadCloser, error) {
|
||||
return remotes.FetcherFunc(func(ctx contextpkg.Context, object string, hints ...string) (io.ReadCloser, error) {
|
||||
ctx = log.WithLogger(ctx, log.G(ctx).WithFields(
|
||||
logrus.Fields{
|
||||
"prefix": prefix, // or repo?
|
||||
|
|
2
cmd/dist/ingest.go
vendored
2
cmd/dist/ingest.go
vendored
|
@ -56,6 +56,6 @@ var ingestCommand = cli.Command{
|
|||
// TODO(stevvooe): Allow ingest to be reentrant. Currently, we expect
|
||||
// all data to be written in a single invocation. Allow multiple writes
|
||||
// to the same transaction key followed by a commit.
|
||||
return content.WriteBlob(ctx, ingester, os.Stdin, ref, expectedSize, expectedDigest)
|
||||
return content.WriteBlob(ctx, ingester, ref, os.Stdin, expectedSize, expectedDigest)
|
||||
},
|
||||
}
|
||||
|
|
4
cmd/dist/main.go
vendored
4
cmd/dist/main.go
vendored
|
@ -38,9 +38,11 @@ distribution tool
|
|||
EnvVar: "CONTAINERD_FETCH_TIMEOUT",
|
||||
},
|
||||
cli.StringFlag{
|
||||
// TODO(stevvooe): for now, we allow circumventing the GRPC. Once
|
||||
// we have clear separation, this will likely go away.
|
||||
Name: "root",
|
||||
Usage: "path to content store root",
|
||||
Value: "/tmp/content", // TODO(stevvooe): for now, just use the PWD/.content
|
||||
Value: "/var/lib/containerd",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "socket, s",
|
||||
|
|
|
@ -4,6 +4,9 @@ import (
|
|||
"context"
|
||||
"io"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
|
||||
contentapi "github.com/docker/containerd/api/services/content"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -83,10 +86,10 @@ type remoteIngester struct {
|
|||
client contentapi.ContentClient
|
||||
}
|
||||
|
||||
func (ri *remoteIngester) Writer(ctx context.Context, ref string) (Writer, error) {
|
||||
wrclient, offset, err := ri.negotiate(ctx, ref)
|
||||
func (ri *remoteIngester) Writer(ctx context.Context, ref string, size int64, expected digest.Digest) (Writer, error) {
|
||||
wrclient, offset, err := ri.negotiate(ctx, ref, size, expected)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, rewriteGRPCError(err)
|
||||
}
|
||||
|
||||
return &remoteWriter{
|
||||
|
@ -95,15 +98,17 @@ func (ri *remoteIngester) Writer(ctx context.Context, ref string) (Writer, error
|
|||
}, nil
|
||||
}
|
||||
|
||||
func (ri *remoteIngester) negotiate(ctx context.Context, ref string) (contentapi.Content_WriteClient, int64, error) {
|
||||
func (ri *remoteIngester) negotiate(ctx context.Context, ref string, size int64, expected digest.Digest) (contentapi.Content_WriteClient, int64, error) {
|
||||
wrclient, err := ri.client.Write(ctx)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if err := wrclient.Send(&contentapi.WriteRequest{
|
||||
Action: contentapi.WriteActionStat,
|
||||
Ref: ref,
|
||||
Action: contentapi.WriteActionStat,
|
||||
Ref: ref,
|
||||
Total: size,
|
||||
Expected: expected,
|
||||
}); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
@ -192,12 +197,12 @@ func (rw *remoteWriter) Write(p []byte) (n int, err error) {
|
|||
|
||||
func (rw *remoteWriter) Commit(size int64, expected digest.Digest) error {
|
||||
resp, err := rw.send(&contentapi.WriteRequest{
|
||||
Action: contentapi.WriteActionCommit,
|
||||
ExpectedSize: size,
|
||||
ExpectedDigest: expected,
|
||||
Action: contentapi.WriteActionCommit,
|
||||
Total: size,
|
||||
Expected: expected,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
return rewriteGRPCError(err)
|
||||
}
|
||||
|
||||
if size != 0 && resp.Offset != size {
|
||||
|
@ -205,7 +210,7 @@ func (rw *remoteWriter) Commit(size int64, expected digest.Digest) error {
|
|||
}
|
||||
|
||||
if expected != "" && resp.Digest != expected {
|
||||
return errors.New("unexpected digest")
|
||||
return errors.Errorf("unexpected digest: %v != %v", resp.Digest, expected)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -214,3 +219,14 @@ func (rw *remoteWriter) Commit(size int64, expected digest.Digest) error {
|
|||
func (rw *remoteWriter) Close() error {
|
||||
return rw.client.CloseSend()
|
||||
}
|
||||
|
||||
func rewriteGRPCError(err error) error {
|
||||
switch grpc.Code(errors.Cause(err)) {
|
||||
case codes.AlreadyExists:
|
||||
return errExists
|
||||
case codes.NotFound:
|
||||
return errNotFound
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
|
||||
var (
|
||||
errNotFound = errors.New("content: not found")
|
||||
errExists = errors.New("content: exists")
|
||||
|
||||
BufPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
|
@ -33,6 +34,7 @@ type Provider interface {
|
|||
type Status struct {
|
||||
Ref string
|
||||
Offset int64
|
||||
Total int64
|
||||
StartedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
@ -45,9 +47,13 @@ type Writer interface {
|
|||
}
|
||||
|
||||
type Ingester interface {
|
||||
Writer(ctx context.Context, ref string) (Writer, error)
|
||||
Writer(ctx context.Context, ref string, size int64, expected digest.Digest) (Writer, error)
|
||||
}
|
||||
|
||||
func IsNotFound(err error) bool {
|
||||
return errors.Cause(err) == errNotFound
|
||||
}
|
||||
|
||||
func IsExists(err error) bool {
|
||||
return errors.Cause(err) == errExists
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ func TestContentWriter(t *testing.T) {
|
|||
t.Fatal("ingest dir should be created", err)
|
||||
}
|
||||
|
||||
cw, err := cs.Writer(ctx, "myref")
|
||||
cw, err := cs.Writer(ctx, "myref", 0, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -39,13 +39,13 @@ func TestContentWriter(t *testing.T) {
|
|||
}
|
||||
|
||||
// reopen, so we can test things
|
||||
cw, err = cs.Writer(ctx, "myref")
|
||||
cw, err = cs.Writer(ctx, "myref", 0, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// make sure that second resume also fails
|
||||
if _, err = cs.Writer(ctx, "myref"); err == nil {
|
||||
if _, err = cs.Writer(ctx, "myref", 0, ""); err == nil {
|
||||
// TODO(stevvooe): This also works across processes. Need to find a way
|
||||
// to test that, as well.
|
||||
t.Fatal("no error on second resume")
|
||||
|
@ -88,7 +88,7 @@ func TestContentWriter(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cw, err = cs.Writer(ctx, "aref")
|
||||
cw, err = cs.Writer(ctx, "aref", 0, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -269,7 +269,7 @@ func checkBlobPath(t *testing.T, cs *Store, dgst digest.Digest) string {
|
|||
}
|
||||
|
||||
func checkWrite(t checker, ctx context.Context, cs *Store, dgst digest.Digest, p []byte) digest.Digest {
|
||||
if err := WriteBlob(ctx, cs, bytes.NewReader(p), dgst.String(), int64(len(p)), dgst); err != nil {
|
||||
if err := WriteBlob(ctx, cs, dgst.String(), bytes.NewReader(p), int64(len(p)), dgst); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package content
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
|
@ -16,10 +17,14 @@ import (
|
|||
// This is useful when the digest and size are known beforehand.
|
||||
//
|
||||
// Copy is buffered, so no need to wrap reader in buffered io.
|
||||
func WriteBlob(ctx context.Context, cs Ingester, r io.Reader, ref string, size int64, expected digest.Digest) error {
|
||||
cw, err := cs.Writer(ctx, ref)
|
||||
func WriteBlob(ctx context.Context, cs Ingester, ref string, r io.Reader, size int64, expected digest.Digest) error {
|
||||
cw, err := cs.Writer(ctx, ref, size, expected)
|
||||
if err != nil {
|
||||
return err
|
||||
if !IsExists(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil // all ready present
|
||||
}
|
||||
|
||||
ws, err := cw.Status()
|
||||
|
@ -28,30 +33,56 @@ func WriteBlob(ctx context.Context, cs Ingester, r io.Reader, ref string, size i
|
|||
}
|
||||
|
||||
if ws.Offset > 0 {
|
||||
// Arbitrary limitation for now. We can detect io.Seeker on r and
|
||||
// resume.
|
||||
return errors.Errorf("cannot resume already started write")
|
||||
r, err = seekReader(r, ws.Offset, size)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unabled to resume write to %v", ref)
|
||||
}
|
||||
}
|
||||
|
||||
buf := BufPool.Get().([]byte)
|
||||
defer BufPool.Put(buf)
|
||||
|
||||
nn, err := io.CopyBuffer(cw, r, buf)
|
||||
if err != nil {
|
||||
if _, err := io.CopyBuffer(cw, r, buf); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if size > 0 && nn != size {
|
||||
return errors.Errorf("failed size verification: %v != %v", nn, size)
|
||||
}
|
||||
|
||||
if err := cw.Commit(size, expected); err != nil {
|
||||
return err
|
||||
if !IsExists(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// seekReader attempts to seek the reader to the given offset, either by
|
||||
// resolving `io.Seeker` or by detecting `io.ReaderAt`.
|
||||
func seekReader(r io.Reader, offset, size int64) (io.Reader, error) {
|
||||
// attempt to resolve r as a seeker and setup the offset.
|
||||
seeker, ok := r.(io.Seeker)
|
||||
if ok {
|
||||
nn, err := seeker.Seek(offset, io.SeekStart)
|
||||
if nn != offset {
|
||||
return nil, fmt.Errorf("failed to seek to offset %v", offset)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// ok, let's try io.ReaderAt!
|
||||
readerAt, ok := r.(io.ReaderAt)
|
||||
if ok && size > offset {
|
||||
sr := io.NewSectionReader(readerAt, offset, size)
|
||||
return sr, nil
|
||||
}
|
||||
|
||||
return nil, errors.Errorf("cannot seek to offset %v", offset)
|
||||
}
|
||||
|
||||
func readFileString(path string) (string, error) {
|
||||
p, err := ioutil.ReadFile(path)
|
||||
return string(p), err
|
||||
|
|
|
@ -2,10 +2,12 @@ package content
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
|
@ -165,17 +167,34 @@ func (s *Store) status(ingestPath string) (Status, error) {
|
|||
return Status{
|
||||
Ref: ref,
|
||||
Offset: fi.Size(),
|
||||
Total: s.total(ingestPath),
|
||||
UpdatedAt: fi.ModTime(),
|
||||
StartedAt: startedAt,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// total attempts to resolve the total expected size for the write.
|
||||
func (s *Store) total(ingestPath string) int64 {
|
||||
totalS, err := readFileString(filepath.Join(ingestPath, "total"))
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
total, err := strconv.ParseInt(totalS, 10, 64)
|
||||
if err != nil {
|
||||
// represents a corrupted file, should probably remove.
|
||||
return 0
|
||||
}
|
||||
|
||||
return total
|
||||
}
|
||||
|
||||
// Writer begins or resumes the active writer identified by ref. If the writer
|
||||
// is already in use, an error is returned. Only one writer may be in use per
|
||||
// ref at a time.
|
||||
//
|
||||
// The argument `ref` is used to uniquely identify a long-lived writer transaction.
|
||||
func (s *Store) Writer(ctx context.Context, ref string) (Writer, error) {
|
||||
func (s *Store) Writer(ctx context.Context, ref string, total int64, expected digest.Digest) (Writer, error) {
|
||||
path, refp, data, lock, err := s.ingestPaths(ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -202,16 +221,19 @@ func (s *Store) Writer(ctx context.Context, ref string) (Writer, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// validate that we have no collision for the ref.
|
||||
refraw, err := readFileString(refp)
|
||||
status, err := s.status(path)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not read ref")
|
||||
return nil, errors.Wrap(err, "failed reading status of resume write")
|
||||
}
|
||||
|
||||
if ref != refraw {
|
||||
if ref != status.Ref {
|
||||
// NOTE(stevvooe): This is fairly catastrophic. Either we have some
|
||||
// layout corruption or a hash collision for the ref key.
|
||||
return nil, errors.Wrapf(err, "ref key does not match: %v != %v", ref, refraw)
|
||||
return nil, errors.Wrapf(err, "ref key does not match: %v != %v", ref, status.Ref)
|
||||
}
|
||||
|
||||
if total > 0 && status.Total > 0 && total != status.Total {
|
||||
return nil, errors.Errorf("provided total differs from status: %v != %v", total, status.Total)
|
||||
}
|
||||
|
||||
// slow slow slow!!, send to goroutine or use resumable hashes
|
||||
|
@ -229,18 +251,9 @@ func (s *Store) Writer(ctx context.Context, ref string) (Writer, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
fi, err := os.Stat(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
updatedAt = fi.ModTime()
|
||||
|
||||
if st, ok := fi.Sys().(*syscall.Stat_t); ok {
|
||||
startedAt = time.Unix(st.Ctim.Sec, st.Ctim.Nsec)
|
||||
} else {
|
||||
startedAt = updatedAt
|
||||
}
|
||||
updatedAt = status.UpdatedAt
|
||||
startedAt = status.StartedAt
|
||||
total = status.Total
|
||||
} else {
|
||||
// the ingest is new, we need to setup the target location.
|
||||
// write the ref to a file for later use
|
||||
|
@ -248,6 +261,12 @@ func (s *Store) Writer(ctx context.Context, ref string) (Writer, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if total > 0 {
|
||||
if err := ioutil.WriteFile(filepath.Join(path, "total"), []byte(fmt.Sprint(total)), 0666); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
startedAt = time.Now()
|
||||
updatedAt = startedAt
|
||||
}
|
||||
|
@ -264,6 +283,7 @@ func (s *Store) Writer(ctx context.Context, ref string) (Writer, error) {
|
|||
ref: ref,
|
||||
path: path,
|
||||
offset: offset,
|
||||
total: total,
|
||||
digester: digester,
|
||||
startedAt: startedAt,
|
||||
updatedAt: updatedAt,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package content
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/docker/containerd/log"
|
||||
"github.com/nightlyone/lockfile"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -19,6 +19,7 @@ type writer struct {
|
|||
path string // path to writer dir
|
||||
ref string // ref key
|
||||
offset int64
|
||||
total int64
|
||||
digester digest.Digester
|
||||
startedAt time.Time
|
||||
updatedAt time.Time
|
||||
|
@ -28,6 +29,7 @@ func (w *writer) Status() (Status, error) {
|
|||
return Status{
|
||||
Ref: w.ref,
|
||||
Offset: w.offset,
|
||||
Total: w.total,
|
||||
StartedAt: w.startedAt,
|
||||
UpdatedAt: w.updatedAt,
|
||||
}, nil
|
||||
|
@ -52,12 +54,12 @@ func (w *writer) Write(p []byte) (n int, err error) {
|
|||
return n, err
|
||||
}
|
||||
|
||||
func (cw *writer) Commit(size int64, expected digest.Digest) error {
|
||||
if err := cw.fp.Sync(); err != nil {
|
||||
func (w *writer) Commit(size int64, expected digest.Digest) error {
|
||||
if err := w.fp.Sync(); err != nil {
|
||||
return errors.Wrap(err, "sync failed")
|
||||
}
|
||||
|
||||
fi, err := cw.fp.Stat()
|
||||
fi, err := w.fp.Stat()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "stat on ingest file failed")
|
||||
}
|
||||
|
@ -67,7 +69,7 @@ func (cw *writer) Commit(size int64, expected digest.Digest) error {
|
|||
// only allowing reads honoring the umask on creation.
|
||||
//
|
||||
// This removes write and exec, only allowing read per the creation umask.
|
||||
if err := cw.fp.Chmod((fi.Mode() & os.ModePerm) &^ 0333); err != nil {
|
||||
if err := w.fp.Chmod((fi.Mode() & os.ModePerm) &^ 0333); err != nil {
|
||||
return errors.Wrap(err, "failed to change ingest file permissions")
|
||||
}
|
||||
|
||||
|
@ -75,18 +77,18 @@ func (cw *writer) Commit(size int64, expected digest.Digest) error {
|
|||
return errors.Errorf("failed size validation: %v != %v", fi.Size(), size)
|
||||
}
|
||||
|
||||
if err := cw.fp.Close(); err != nil {
|
||||
if err := w.fp.Close(); err != nil {
|
||||
return errors.Wrap(err, "failed closing ingest")
|
||||
}
|
||||
|
||||
dgst := cw.digester.Digest()
|
||||
dgst := w.digester.Digest()
|
||||
if expected != "" && expected != dgst {
|
||||
return errors.Errorf("unexpected digest: %v != %v", dgst, expected)
|
||||
}
|
||||
|
||||
var (
|
||||
ingest = filepath.Join(cw.path, "data")
|
||||
target = cw.s.blobPath(dgst)
|
||||
ingest = filepath.Join(w.path, "data")
|
||||
target = w.s.blobPath(dgst)
|
||||
)
|
||||
|
||||
// make sure parent directories of blob exist
|
||||
|
@ -95,18 +97,18 @@ func (cw *writer) Commit(size int64, expected digest.Digest) error {
|
|||
}
|
||||
|
||||
// clean up!!
|
||||
defer os.RemoveAll(cw.path)
|
||||
defer os.RemoveAll(w.path)
|
||||
|
||||
if err := os.Rename(ingest, target); err != nil {
|
||||
if os.IsExist(err) {
|
||||
// collision with the target file!
|
||||
return nil
|
||||
return errExists
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
unlock(cw.lock)
|
||||
cw.fp = nil
|
||||
unlock(w.lock)
|
||||
w.fp = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -121,7 +123,7 @@ func (cw *writer) Commit(size int64, expected digest.Digest) error {
|
|||
// clean up the associated resources.
|
||||
func (cw *writer) Close() (err error) {
|
||||
if err := unlock(cw.lock); err != nil {
|
||||
log.Printf("unlock failed: %v", err)
|
||||
log.L.Debug("unlock failed: %v", err)
|
||||
}
|
||||
|
||||
if cw.fp != nil {
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"io"
|
||||
)
|
||||
|
||||
type Remote interface {
|
||||
type Fetcher interface {
|
||||
// Fetch the resource identified by id. The id is opaque to the remote, but
|
||||
// may typically be a tag or a digest.
|
||||
//
|
||||
|
@ -32,8 +32,10 @@ type Remote interface {
|
|||
Fetch(ctx context.Context, id string, hints ...string) (io.ReadCloser, error)
|
||||
}
|
||||
|
||||
type RemoteFunc func(context.Context, string, ...string) (io.ReadCloser, error)
|
||||
// FetcherFunc allows package users to implement a Fetcher with just a
|
||||
// function.
|
||||
type FetcherFunc func(context.Context, string, ...string) (io.ReadCloser, error)
|
||||
|
||||
func (fn RemoteFunc) Fetch(ctx context.Context, object string, hints ...string) (io.ReadCloser, error) {
|
||||
func (fn FetcherFunc) Fetch(ctx context.Context, object string, hints ...string) (io.ReadCloser, error) {
|
||||
return fn(ctx, object, hints...)
|
||||
}
|
||||
|
|
|
@ -9,11 +9,11 @@ type Resolver interface {
|
|||
// A locator is a scheme-less URI representing the remote. Structurally, it
|
||||
// has a host and path. The "host" can be used to directly reference a
|
||||
// specific host or be matched against a specific handler.
|
||||
Resolve(ctx context.Context, locator string) (Remote, error)
|
||||
Resolve(ctx context.Context, locator string) (Fetcher, error)
|
||||
}
|
||||
|
||||
type ResolverFunc func(context.Context, string) (Remote, error)
|
||||
type ResolverFunc func(context.Context, string) (Fetcher, error)
|
||||
|
||||
func (fn ResolverFunc) Resolve(ctx context.Context, locator string) (Remote, error) {
|
||||
func (fn ResolverFunc) Resolve(ctx context.Context, locator string) (Fetcher, error) {
|
||||
return fn(ctx, locator)
|
||||
}
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
package content
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/containerd"
|
||||
api "github.com/docker/containerd/api/services/content"
|
||||
"github.com/docker/containerd/content"
|
||||
"github.com/docker/containerd/log"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
|
@ -128,14 +131,25 @@ func (rw *readResponseWriter) Write(p []byte) (n int, err error) {
|
|||
|
||||
func (s *Service) Write(session api.Content_WriteServer) (err error) {
|
||||
var (
|
||||
ref string
|
||||
msg api.WriteResponse
|
||||
req *api.WriteRequest
|
||||
ctx = session.Context()
|
||||
msg api.WriteResponse
|
||||
req *api.WriteRequest
|
||||
ref string
|
||||
total int64
|
||||
expected digest.Digest
|
||||
)
|
||||
|
||||
defer func(msg *api.WriteResponse) {
|
||||
// pump through the last message if no error was encountered
|
||||
if err != nil {
|
||||
// TODO(stevvooe): Really need a log line here to track which
|
||||
// errors are actually causing failure on the server side. May want
|
||||
// to configure the service with an interceptor to make this work
|
||||
// identically across all GRPC methods.
|
||||
//
|
||||
// This is pretty noisy, so we can remove it but leave it for now.
|
||||
log.G(ctx).WithError(err).Error("(*Service).Write failed")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -149,47 +163,88 @@ func (s *Service) Write(session api.Content_WriteServer) (err error) {
|
|||
}
|
||||
|
||||
ref = req.Ref
|
||||
|
||||
if ref == "" {
|
||||
return grpc.Errorf(codes.InvalidArgument, "first message must have a reference")
|
||||
}
|
||||
|
||||
fields := logrus.Fields{
|
||||
"ref": ref,
|
||||
}
|
||||
total = req.Total
|
||||
expected = req.Expected
|
||||
if total > 0 {
|
||||
fields["total"] = total
|
||||
}
|
||||
|
||||
if expected != "" {
|
||||
fields["expected"] = expected
|
||||
}
|
||||
|
||||
ctx = log.WithLogger(ctx, log.G(ctx).WithFields(fields))
|
||||
// this action locks the writer for the session.
|
||||
wr, err := s.store.Writer(session.Context(), ref)
|
||||
wr, err := s.store.Writer(ctx, ref, total, expected)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer wr.Close()
|
||||
|
||||
for {
|
||||
// TODO(stevvooe): We need to study this behavior in containerd a
|
||||
// little better to decide where to put this. We may be able to make
|
||||
// this determination elsewhere and avoid even creating the writer.
|
||||
//
|
||||
// Ideally, we just use the expected digest on commit to abandon the
|
||||
// cost of the move when they collide.
|
||||
if req.ExpectedDigest != "" {
|
||||
if _, err := s.store.Info(req.ExpectedDigest); err != nil {
|
||||
if !content.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
return grpc.Errorf(codes.AlreadyExists, "blob with expected digest %v exists", req.ExpectedDigest)
|
||||
}
|
||||
}
|
||||
|
||||
msg.Action = req.Action
|
||||
ws, err := wr.Status()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg.Offset = ws.Offset
|
||||
msg.StartedAt = ws.StartedAt
|
||||
msg.UpdatedAt = ws.UpdatedAt
|
||||
msg.Offset = ws.Offset // always set the offset.
|
||||
|
||||
// NOTE(stevvooe): In general, there are two cases underwhich a remote
|
||||
// writer is used.
|
||||
//
|
||||
// For pull, we almost always have this before fetching large content,
|
||||
// through descriptors. We allow predeclaration of the expected size
|
||||
// and digest.
|
||||
//
|
||||
// For push, it is more complex. If we want to cut through content into
|
||||
// storage, we may have no expectation until we are done processing the
|
||||
// content. The case here is the following:
|
||||
//
|
||||
// 1. Start writing content.
|
||||
// 2. Compress inline.
|
||||
// 3. Validate digest and size (maybe).
|
||||
//
|
||||
// Supporting these two paths is quite awkward but it let's both API
|
||||
// users use the same writer style for each with a minimum of overhead.
|
||||
if req.Expected != "" {
|
||||
if expected != "" && expected != req.Expected {
|
||||
return grpc.Errorf(codes.InvalidArgument, "inconsistent digest provided: %v != %v", req.Expected, expected)
|
||||
}
|
||||
expected = req.Expected
|
||||
|
||||
if _, err := s.store.Info(req.Expected); err == nil {
|
||||
if err := s.store.Abort(ref); err != nil {
|
||||
log.G(ctx).WithError(err).Error("failed to abort write")
|
||||
}
|
||||
|
||||
return grpc.Errorf(codes.AlreadyExists, "blob with expected digest %v exists", req.Expected)
|
||||
}
|
||||
}
|
||||
|
||||
if req.Total > 0 {
|
||||
// Update the expected total. Typically, this could be seen at
|
||||
// negotiation time or on a commit message.
|
||||
if total > 0 && req.Total != total {
|
||||
return grpc.Errorf(codes.InvalidArgument, "inconsistent total provided: %v != %v", req.Total, total)
|
||||
}
|
||||
total = req.Total
|
||||
}
|
||||
|
||||
switch req.Action {
|
||||
case api.WriteActionStat:
|
||||
msg.Digest = wr.Digest()
|
||||
msg.StartedAt = ws.StartedAt
|
||||
msg.UpdatedAt = ws.UpdatedAt
|
||||
msg.Total = total
|
||||
case api.WriteActionWrite, api.WriteActionCommit:
|
||||
if req.Offset > 0 {
|
||||
// validate the offset if provided
|
||||
|
@ -217,7 +272,11 @@ func (s *Service) Write(session api.Content_WriteServer) (err error) {
|
|||
}
|
||||
|
||||
if req.Action == api.WriteActionCommit {
|
||||
return wr.Commit(req.ExpectedSize, req.ExpectedDigest)
|
||||
if err := wr.Commit(total, expected); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg.Digest = wr.Digest()
|
||||
}
|
||||
case api.WriteActionAbort:
|
||||
return s.store.Abort(ref)
|
||||
|
|
Loading…
Reference in a new issue